Parse an HTTP request Authorization header with Python - python

I need to take a header like this:
Authorization: Digest qop="chap",
realm="testrealm#host.com",
username="Foobear",
response="6629fae49393a05397450978507c4ef1",
cnonce="5ccc069c403ebaf9f0171e9517f40e41"
And parse it into this using Python:
{'protocol':'Digest',
'qop':'chap',
'realm':'testrealm#host.com',
'username':'Foobear',
'response':'6629fae49393a05397450978507c4ef1',
'cnonce':'5ccc069c403ebaf9f0171e9517f40e41'}
Is there a library to do this, or something I could look at for inspiration?
I'm doing this on Google App Engine, and I'm not sure if the Pyparsing library is available, but maybe I could include it with my app if it is the best solution.
Currently I'm creating my own MyHeaderParser object and using it with reduce() on the header string. It's working, but very fragile.
Brilliant solution by nadia below:
import re
reg = re.compile('(\w+)[=] ?"?(\w+)"?')
s = """Digest
realm="stackoverflow.com", username="kixx"
"""
print str(dict(reg.findall(s)))

A little regex:
import re
reg=re.compile('(\w+)[:=] ?"?(\w+)"?')
>>>dict(reg.findall(headers))
{'username': 'Foobear', 'realm': 'testrealm', 'qop': 'chap', 'cnonce': '5ccc069c403ebaf9f0171e9517f40e41', 'response': '6629fae49393a05397450978507c4ef1', 'Authorization': 'Digest'}

You can also use urllib2 as [CheryPy][1] does.
here is the snippet:
input= """
Authorization: Digest qop="chap",
realm="testrealm#host.com",
username="Foobear",
response="6629fae49393a05397450978507c4ef1",
cnonce="5ccc069c403ebaf9f0171e9517f40e41"
"""
import urllib2
field, sep, value = input.partition("Authorization: Digest ")
if value:
items = urllib2.parse_http_list(value)
opts = urllib2.parse_keqv_list(items)
opts['protocol'] = 'Digest'
print opts
it outputs:
{'username': 'Foobear', 'protocol': 'Digest', 'qop': 'chap', 'cnonce': '5ccc069c403ebaf9f0171e9517f40e41', 'realm': 'testrealm#host.com', 'response': '6629fae49393a05397450978507c4ef1'}
[1]: https://web.archive.org/web/20130118133623/http://www.google.com:80/codesearch/p?hl=en#OQvO9n2mc04/CherryPy-3.0.1/cherrypy/lib/httpauth.py&q=Authorization Digest http lang:python

Here's my pyparsing attempt:
text = """Authorization: Digest qop="chap",
realm="testrealm#host.com",
username="Foobear",
response="6629fae49393a05397450978507c4ef1",
cnonce="5ccc069c403ebaf9f0171e9517f40e41" """
from pyparsing import *
AUTH = Keyword("Authorization")
ident = Word(alphas,alphanums)
EQ = Suppress("=")
quotedString.setParseAction(removeQuotes)
valueDict = Dict(delimitedList(Group(ident + EQ + quotedString)))
authentry = AUTH + ":" + ident("protocol") + valueDict
print authentry.parseString(text).dump()
which prints:
['Authorization', ':', 'Digest', ['qop', 'chap'], ['realm', 'testrealm#host.com'],
['username', 'Foobear'], ['response', '6629fae49393a05397450978507c4ef1'],
['cnonce', '5ccc069c403ebaf9f0171e9517f40e41']]
- cnonce: 5ccc069c403ebaf9f0171e9517f40e41
- protocol: Digest
- qop: chap
- realm: testrealm#host.com
- response: 6629fae49393a05397450978507c4ef1
- username: Foobear
I'm not familiar with the RFC, but I hope this gets you rolling.

An older question but one I found very helpful.
(edit after recent upvote) I've created a package that builds on
this answer (link to tests to see how to use the class in the
package).
pip install authparser
I needed a parser to handle any properly formed Authorization header, as defined by RFC7235 (raise your hand if you enjoy reading ABNF).
Authorization = credentials
BWS = <BWS, see [RFC7230], Section 3.2.3>
OWS = <OWS, see [RFC7230], Section 3.2.3>
Proxy-Authenticate = *( "," OWS ) challenge *( OWS "," [ OWS
challenge ] )
Proxy-Authorization = credentials
WWW-Authenticate = *( "," OWS ) challenge *( OWS "," [ OWS challenge
] )
auth-param = token BWS "=" BWS ( token / quoted-string )
auth-scheme = token
challenge = auth-scheme [ 1*SP ( token68 / [ ( "," / auth-param ) *(
OWS "," [ OWS auth-param ] ) ] ) ]
credentials = auth-scheme [ 1*SP ( token68 / [ ( "," / auth-param )
*( OWS "," [ OWS auth-param ] ) ] ) ]
quoted-string = <quoted-string, see [RFC7230], Section 3.2.6>
token = <token, see [RFC7230], Section 3.2.6>
token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" )
*"="
Starting with PaulMcG's answer, I came up with this:
import pyparsing as pp
tchar = '!#$%&\'*+-.^_`|~' + pp.nums + pp.alphas
t68char = '-._~+/' + pp.nums + pp.alphas
token = pp.Word(tchar)
token68 = pp.Combine(pp.Word(t68char) + pp.ZeroOrMore('='))
scheme = token('scheme')
header = pp.Keyword('Authorization')
name = pp.Word(pp.alphas, pp.alphanums)
value = pp.quotedString.setParseAction(pp.removeQuotes)
name_value_pair = name + pp.Suppress('=') + value
params = pp.Dict(pp.delimitedList(pp.Group(name_value_pair)))
credentials = scheme + (token68('token') ^ params('params'))
auth_parser = header + pp.Suppress(':') + credentials
This allows for parsing any Authorization header:
parsed = auth_parser.parseString('Authorization: Basic Zm9vOmJhcg==')
print('Authenticating with {0} scheme, token: {1}'.format(parsed['scheme'], parsed['token']))
which outputs:
Authenticating with Basic scheme, token: Zm9vOmJhcg==
Bringing it all together into an Authenticator class:
import pyparsing as pp
from base64 import b64decode
import re
class Authenticator:
def __init__(self):
"""
Use pyparsing to create a parser for Authentication headers
"""
tchar = "!#$%&'*+-.^_`|~" + pp.nums + pp.alphas
t68char = '-._~+/' + pp.nums + pp.alphas
token = pp.Word(tchar)
token68 = pp.Combine(pp.Word(t68char) + pp.ZeroOrMore('='))
scheme = token('scheme')
auth_header = pp.Keyword('Authorization')
name = pp.Word(pp.alphas, pp.alphanums)
value = pp.quotedString.setParseAction(pp.removeQuotes)
name_value_pair = name + pp.Suppress('=') + value
params = pp.Dict(pp.delimitedList(pp.Group(name_value_pair)))
credentials = scheme + (token68('token') ^ params('params'))
# the moment of truth...
self.auth_parser = auth_header + pp.Suppress(':') + credentials
def authenticate(self, auth_header):
"""
Parse auth_header and call the correct authentication handler
"""
authenticated = False
try:
parsed = self.auth_parser.parseString(auth_header)
scheme = parsed['scheme']
details = parsed['token'] if 'token' in parsed.keys() else parsed['params']
print('Authenticating using {0} scheme'.format(scheme))
try:
safe_scheme = re.sub("[!#$%&'*+-.^_`|~]", '_', scheme.lower())
handler = getattr(self, 'auth_handle_' + safe_scheme)
authenticated = handler(details)
except AttributeError:
print('This is a valid Authorization header, but we do not handle this scheme yet.')
except pp.ParseException as ex:
print('Not a valid Authorization header')
print(ex)
return authenticated
# The following methods are fake, of course. They should use what's passed
# to them to actually authenticate, and return True/False if successful.
# For this demo I'll just print some of the values used to authenticate.
#staticmethod
def auth_handle_basic(token):
print('- token is {0}'.format(token))
try:
username, password = b64decode(token).decode().split(':', 1)
except Exception:
raise DecodeError
print('- username is {0}'.format(username))
print('- password is {0}'.format(password))
return True
#staticmethod
def auth_handle_bearer(token):
print('- token is {0}'.format(token))
return True
#staticmethod
def auth_handle_digest(params):
print('- username is {0}'.format(params['username']))
print('- cnonce is {0}'.format(params['cnonce']))
return True
#staticmethod
def auth_handle_aws4_hmac_sha256(params):
print('- Signature is {0}'.format(params['Signature']))
return True
To test this class:
tests = [
'Authorization: Digest qop="chap", realm="testrealm#example.com", username="Foobar", response="6629fae49393a05397450978507c4ef1", cnonce="5ccc069c403ebaf9f0171e9517f40e41"',
'Authorization: Bearer cn389ncoiwuencr',
'Authorization: Basic Zm9vOmJhcg==',
'Authorization: AWS4-HMAC-SHA256 Credential="AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request", SignedHeaders="host;range;x-amz-date", Signature="fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024"',
'Authorization: CrazyCustom foo="bar", fizz="buzz"',
]
authenticator = Authenticator()
for test in tests:
authenticator.authenticate(test)
print()
Which outputs:
Authenticating using Digest scheme
- username is Foobar
- cnonce is 5ccc069c403ebaf9f0171e9517f40e41
Authenticating using Bearer scheme
- token is cn389ncoiwuencr
Authenticating using Basic scheme
- token is Zm9vOmJhcg==
- username is foo
- password is bar
Authenticating using AWS4-HMAC-SHA256 scheme
- signature is fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
Authenticating using CrazyCustom scheme
This is a valid Authorization header, but we do not handle this scheme yet.
In future if we wish to handle CrazyCustom we'll just add
def auth_handle_crazycustom(params):

If those components will always be there, then a regex will do the trick:
test = '''Authorization: Digest qop="chap", realm="testrealm#host.com", username="Foobear", response="6629fae49393a05397450978507c4ef1", cnonce="5ccc069c403ebaf9f0171e9517f40e41"'''
import re
re_auth = re.compile(r"""
Authorization:\s*(?P<protocol>[^ ]+)\s+
qop="(?P<qop>[^"]+)",\s+
realm="(?P<realm>[^"]+)",\s+
username="(?P<username>[^"]+)",\s+
response="(?P<response>[^"]+)",\s+
cnonce="(?P<cnonce>[^"]+)"
""", re.VERBOSE)
m = re_auth.match(test)
print m.groupdict()
produces:
{ 'username': 'Foobear',
'protocol': 'Digest',
'qop': 'chap',
'cnonce': '5ccc069c403ebaf9f0171e9517f40e41',
'realm': 'testrealm#host.com',
'response': '6629fae49393a05397450978507c4ef1'
}

I would recommend finding a correct library for parsing http headers unfortunately I can't reacall any. :(
For a while check the snippet below (it should mostly work):
input= """
Authorization: Digest qop="chap",
realm="testrealm#host.com",
username="Foob,ear",
response="6629fae49393a05397450978507c4ef1",
cnonce="5ccc069c403ebaf9f0171e9517f40e41"
"""
field, sep, value = input.partition(":")
if field.endswith('Authorization'):
protocol, sep, opts_str = value.strip().partition(" ")
opts = {}
for opt in opts_str.split(",\n"):
key, value = opt.strip().split('=')
key = key.strip(" ")
value = value.strip(' "')
opts[key] = value
opts['protocol'] = protocol
print opts

Your original concept of using PyParsing would be the best approach. What you've implicitly asked for is something that requires a grammar... that is, a regular expression or simple parsing routine is always going to be brittle, and that sounds like it's something you're trying to avoid.
It appears that getting pyparsing on google app engine is easy: How do I get PyParsing set up on the Google App Engine?
So I'd go with that, and then implement the full HTTP authentication/authorization header support from rfc2617.

The http digest Authorization header field is a bit of an odd beast. Its format is similar to that of rfc 2616's Cache-Control and Content-Type header fields, but just different enough to be incompatible. If you're still looking for a library that's a little smarter and more readable than the regex, you might try removing the Authorization: Digest part with str.split() and parsing the rest with parse_dict_header() from Werkzeug's http module. (Werkzeug can be installed on App Engine.)

Nadia's regex only matches alphanumeric characters for the value of a parameter. That means it fails to parse at least two fields. Namely, the uri and qop. According to RFC 2617, the uri field is a duplicate of the string in the request line (i.e. the first line of the HTTP request). And qop fails to parse correctly if the value is "auth-int" due to the non-alphanumeric '-'.
This modified regex allows the URI (or any other value) to contain anything but ' ' (space), '"' (qoute), or ',' (comma). That's probably more permissive than it needs to be, but shouldn't cause any problems with correctly formed HTTP requests.
reg re.compile('(\w+)[:=] ?"?([^" ,]+)"?')
Bonus tip: From there, it's fairly straight forward to convert the example code in RFC-2617 to python. Using python's md5 API, "MD5Init()" becomes "m = md5.new()", "MD5Update()" becomes "m.update()" and "MD5Final()" becomes "m.digest()".

If your response comes in a single string that that never varies and has as many lines as there are expressions to match, you can split it into an array on the newlines called authentication_array and use regexps:
pattern_array = ['qop', 'realm', 'username', 'response', 'cnonce']
i = 0
parsed_dict = {}
for line in authentication_array:
pattern = "(" + pattern_array[i] + ")" + "=(\".*\")" # build a matching pattern
match = re.search(re.compile(pattern), line) # make the match
if match:
parsed_dict[match.group(1)] = match.group(2)
i += 1

Related

How can I generate JWT token using HMAC? How is the signature created?

I went to this website https://jwt.io/#debugger-io
Here I took the given sample info and passed it to my code.
But the encoded information that I got is not matching what is given on the website.
Since I am doing something wrong here, I am not able to generate the signature in a valid format.
I need to make a program for JWT verification without using PyJWT types libraries.
Here is my code
import base64
import hmac
header = {"alg": "HS256", "typ": "JWT"}
payload = {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
header = base64.urlsafe_b64encode(bytes(str(header), 'utf-8'))
payload = base64.urlsafe_b64encode(bytes(str(payload), 'utf-8'))
print(header)
print(payload)
signature = hmac.new(bytes('hi', 'utf-8'), header + b'.' + payload, digestmod='sha256').hexdigest()
print(signature)
Outputs
There are 3 things that need to be changed in your code.
your header and payload are not valid JSON. If you decode the result of your Base64 encoded header eydhbGcnOiAnSFMyNTYnLCAndHlwJzogJ0pXVCd9 you get
{'alg': 'HS256', 'typ': 'JWT'}
but it should be (with "instead of ')
{"alg": "HS256", "typ": "JWT"}
the function base64.b64encode produces an output that can still contain '='. The padding has to be removed.
You create the signature with .hexdigest(), which produces a hex-ascii string. Instead you need to use .digest() to get binary output and then Base64URL encode the result.
The code below is a corrected version of your code which produces a JWT string that can be verified on https://jwt.io.
import base64
import hmac
header = '{"alg":"HS256","typ":"JWT"}'
payload = '{"sub":"1234567890","name":"John Doe","iat":1516239022}'
header = base64.urlsafe_b64encode(bytes(str(header), 'utf-8')).decode().replace("=", "")
payload = base64.urlsafe_b64encode(bytes(str(payload), 'utf-8')).decode().replace("=", "")
print(header)
print(payload)
signature = hmac.new(bytes('hi', 'utf-8'), bytes(header + '.' + payload, 'utf-8'), digestmod='sha256').digest()
sigb64 = base64.urlsafe_b64encode(bytes(signature)).decode().replace("=", "")
print(sigb64)
token = header + '.' + payload + '.' + sigb64
print(token)
As a sidenote: The secret that you use to create the HMAC should have a length of at least 256 bits, even if the very short key is accepted. Some libs enforce a minimum key length.

I am trying to make an HTTP post, but json returns "message":"Unauthorized"

import httplib2
import hmac
import hashlib
import time
import sys
import struct
import json
root = "https://api.challenge.hennge.com/challenges/003"
content_type = "application/json"
userid = "toufiqurrahman45#gmail.com"
name = "HENNGECHALLENGE003"
shared_secret = userid+name
timestep = 30
T0 = 0
def HOTP(K, C, digits=10):
K_bytes = str.encode(K)
C_bytes = struct.pack(">Q", C)
hmac_sha512 = hmac.new(key = K_bytes, msg=C_bytes, digestmod=hashlib.sha512).hexdigest()
return Truncate(hmac_sha512)[-digits:]
def Truncate(hmac_sha512):
offset = int(hmac_sha512[-1], 16)
binary = int(hmac_sha512[(offset *2):((offset*2)+8)], 16) & 0x7FFFFFFF
return str(binary)
def TOTP(K, digits=10, timeref = 0, timestep = 30):
C = int ( time.time() - timeref ) // timestep
return HOTP(K, C, digits = digits)
data = { "github_url": "https://gist.github.com/TaufiqurRahman45/f5347e5ba6e7d24aa61ac8c78fda452e", "contact_email": "toufiqurrahman45#gmail.com" }
password = TOTP(shared_secret, 10, T0, timestep).zfill(10)
h = httplib2.Http()
h.add_credentials( userid, password )
header = {"content-type": "application/json"}
resp, content = h.request(root, "POST", headers = header, body = json.dumps(data))
print(resp)
print(content)
Authorization
The URL is protected by HTTP Basic Authentication, which is explained on Chapter 2 of RFC2617, so you have to provide an Authorization: header field in your POST request
For the userid of HTTP Basic Authentication, use the same email address you put in the JSON string.
For the password, provide a 10-digit time-based one time password conforming to RFC6238 TOTP.
I generating also password and using hash function HMAC-SHA-512
The URL is protected by HTTP Basic Authentication, which is explained on Chapter 2 >of RFC2617, so you have to provide an Authorization: header field in your POST request
For the userid of HTTP Basic Authentication, use the same email address you put in >the JSON string. For the password, provide a 10-digit time-based one time password >conforming to RFC6238 TOTP.
As mentioned here, you have to provide an Authorization: header field like this:
headers={"Authorization":"OATH TOKEN","content-type": "application/json"}
You can get an OATH Token for github from https://github.com/settings/tokens

401 Authorization Required on Twitter API request

I'm building an Python script to automatically post status updates on Twitter. I've carefully read and followed the API documentation for creating a signature and do the request to update the status. But I'm getting an error when doing the request.
HTTP Error 401: Authorization Required
I've seen more questions like this on Stackoverflow and other resources, but couldn't find a solution to this problem yet.
def sendTweet(self):
url = 'https://api.twitter.com/1.1/statuses/update.json'
message = 'Testing'
oauths = [
['oauth_consumer_key', '1234567890'],
['oauth_nonce', self.generate_nonce()],
['oauth_signature', ''],
['oauth_signature_method', 'HMAC-SHA1'],
['oauth_timestamp', str(int(time.time()))],
['oauth_token', '1234567890'],
['oauth_version', '1.0']
]
signature = self.sign(oauths, message)
oauths[2][1] = signature
count = 0
auth = 'OAuth '
for oauth in oauths:
count = count + 1
if oauth[1]:
auth = auth + self.quote(oauth[0]) + '="' + self.quote(oauth[1]) + '"'
if count < len(oauths):
auth = auth + ', '
headers = {
'Authorization': auth,
'Content-Type': 'application/x-www-form-urlencoded'
}
payload = {'status' : message.encode('utf-8')}
req = urllib2.Request(url, data=urllib.urlencode(payload), headers=headers)
try:
response = urllib2.urlopen(req)
data = response.read()
print data
except (urllib2.HTTPError, urllib2.URLError) as err:
print err
This is what the self.sign function does
def sign(self, oauths, message):
signatureParams = ''
count = 0
values = [
['oauth_consumer_key', oauths[0][1]],
['oauth_nonce', oauths[1][1]],
['oauth_signature_method', oauths[3][1]],
['oauth_timestamp', oauths[4][1]],
['oauth_token', oauths[5][1]],
['oauth_version', oauths[6][1]],
['status', message]
]
customerSecret = '1234567890'
tokenSecret = '1234567890'
for value in oauths:
count = count + 1
signatureParams = signatureParams + self.quote(value[0]) + '=' + self.quote(value[1])
if count < len(oauths):
signatureParams = signatureParams + '&'
signature = 'POST&' + self.quote(self.endPoint) + '&' + self.quote(signatureParams)
signinKey = self.quote(customerSecret) + '&' + self.quote(tokenSecret)
signed = base64.b64encode(self.signRequest(signinKey, signature))
return signed
And below are the helper functions.
def generate_nonce(self):
return ''.join([str(random.randint(0, 9)) for i in range(8)])
def quote(self, param):
return urllib.quote(param.encode('utf8'), safe='')
def signRequest(self, key, raw):
from hashlib import sha1
import hmac
hashed = hmac.new(key, raw, sha1)
return hashed.digest().encode('base64').rstrip('\n')
This is what the auth string looks like when I print it.
OAuth oauth_consumer_key="1234567890",
oauth_nonce="78261149",
oauth_signature="akc2alpFWWdjbElZV2RCMmpGcDc0V1d1S1B3PQ%3D%3D",
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1540896473",
oauth_token="1234567890",
oauth_version="1.0"
That is exactly like it should be if I read the Twitter documentation. But still I get the 401 Authorization Required error.. I just can't see what is going wrong here.
The Access level for the keys is Read, write, and direct messages
All keys are replaced with 1234567890, but in the actual code I use the real ones.
Does someone have an idea what I am doing wrong? Thanks in advance!

What is the Pythonic way to remove "Bearer " from the HTTP authorization header

I have an Authorization header in a string like this:
Bearer [myawesometoken]
I don't want to tokenize using the space character because I want to require the string "Bearer" to be at the start of the string
What is the pythonic way to return just the token from the string?
Is there a regex matching function like PHP preg_match()? Would this be the pythonic way to do it?
I think the most Pythonic way of doing this would be to use the built-in startswith method of str and string slicing:
PREFIX = 'Bearer '
def get_token(header):
if not header.startswith(PREFIX):
raise ValueError('Invalid token')
return header[len(PREFIX):]
I however would prefer str.partition to tokenize the header into a 3-tuple:
PREFIX = 'Bearer'
def get_token(header):
bearer, _, token = header.partition(' ')
if bearer != PREFIX:
raise ValueError('Invalid token')
return token
Let say your authorization string is
Bearer mytoken
then u can extract token like this
import re
authorization_string="Bearer mytoken"
g = re.match("^Bearer\s+(.*)", authorization_string)
if g:
# ur token
print(g.group(1)
else:
print("No token")
Is the string always in this format?
header_string = 'Bearer [myawesometoken]'
token = header_string[8:-1]

Authentication Required - Problems Establishing AIM OSCAR Session using Python

I'm writing a simple python script that will interface with the AIM servers using the OSCAR protocol. It includes a somewhat complex handshake protocol. You essentially have to send a GET request to a specific URL, receive XML or JSON encoded reply, extract a special session token and secret key, then generate a response using the token and the key.
I tried to follow these steps to a tee, but the process fails in the last one. Here is my code:
class simpleOSCAR:
def __init__(self, username, password):
self.username = username
self.password = password
self.open_aim_key = 'whatever'
self.client_name = 'blah blah blah'
self.client_version = 'yadda yadda yadda'
def authenticate(self):
# STEP 1
url = 'https://api.screenname.aol.com/auth/clientLogin?f=json'
data = urllib.urlencode( [
('k', self.open_aim_key),
('s', self.username),
('pwd', self.password),
('clientVersion', self.client_version),
('clientName', self.client_name)]
)
response = urllib2.urlopen(url, data)
json_response = simplejson.loads(urllib.unquote(response.read()))
session_secret = json_response['response']['data']['sessionSecret']
host_time = json_response['response']['data']['hostTime']
self.token = json_response['response']['data']['token']['a']
# STEP 2
self.session_key = base64.b64encode(hmac.new(self.password, session_secret, sha256).digest())
#STEP 3
uri = "http://api.oscar.aol.com/aim/startOSCARSession?"
data = urllib.urlencode([
('a', self.token),
('clientName', self.client_name),
('clientVersion', self.client_version),
('f', 'json'),
('k', self.open_aim_key),
('ts', host_time),
]
)
urldata = uri+data
hashdata = "GET&" + urllib.quote("http://api.oscar.aol.com/aim/startOSCARSession?") + data
digest = base64.b64encode(hmac.new(self.session_key, hashdata, sha256).digest())
urldata = urldata + "&sig_sha256=" + digest
print urldata + "\n"
response = urllib2.urlopen(urldata)
json_response = urllib.unquote(response.read())
print json_response
if __name__ == '__main__':
so = simpleOSCAR("aimscreenname", "somepassword")
so.authenticate()
I get the following response from the server:
{ "response" : {
"statusCode":401,
"statusText":"Authentication Required. statusDetailCode 1014",
"statusDetailCode":1014,
"data":{
"ts":1235878395
}
}
}
I tried troubleshooting it in various ways, but the URL's I generate look the same as the ones shown in the signon flow example. And yet, it fails.
Any idea what I'm doing wrong here? Am I hashing the values wrong? Am I encoding something improperly? Is my session timing out?
Try using Twisted's OSCAR support instead of writing your own? It hasn't seen a lot of maintenance, but I believe it works.
URI Encode your digest?
-moxford

Categories

Resources