1 from httplib import HTTPConnection, HTTPSConnection
2 import re
3
4 # In regex below:
5 # [^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+ matches a "token" as defined by HTTP
6 # "(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?" matches a "quoted-string" as defined by HTTP, when LWS have already been replaced by a single space
7 # Actually, as an auth-param value can be either a token or a quoted-string, they are combined in a single pattern which matches both:
8 # \"?((?<=\")(?:[^\0-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x08\x0A-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?
9 WWW_AUTH = re.compile(r"^(?:\s*(?:,\s*)?([^ \t\r\n=]+)\s*=\s*\"?((?<=\")(?:[^\\\"]|\\.)*?(?=\")|(?<!\")[^ \t\r\n,]+(?!\"))\"?)(.*)$")
10 UNQUOTE_PAIRS = re.compile(r'\\(.)')
11 def _parse_www_authenticate(authenticate):
12 """Returns a dictionary of dictionaries, one dict
13 per auth-scheme. The dictionary for each auth-scheme
14 contains all the auth-params.
15 """
16 retval = {}
17 authenticate = authenticate.strip()
18 while authenticate:
19 # Break off the scheme at the beginning of the line
20 (auth_scheme, the_rest) = authenticate.split(" ", 1)
21 # Now loop over all the key value pairs that come after the scheme,
22 # being careful not to roll into the next scheme
23 match = WWW_AUTH.search(the_rest)
24 auth_params = {}
25 while match:
26 if match and len(match.groups()) == 3:
27 (key, value, the_rest) = match.groups()
28 auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')])
29 match = WWW_AUTH.search(the_rest)
30 retval[auth_scheme.lower()] = auth_params
31 authenticate = the_rest.strip()
32 return retval
33
34
35 def googlelogin(name, password, useragent, challenge):
36 from urllib import urlencode
37 service = challenge['googlelogin']['service']
38 auth = dict(Email=name, Passwd=password, service=service, source=useragent)
39 conn = HTTPSConnection('www.google.com')
40 conn.request('POST', '/accounts/ClientLogin', body=urlencode(auth), headers={'content-type': 'application/x-www-form-urlencoded'})
41 r = conn.getresponse()
42 content = r.read()
43 lines = content.split('\n')
44 d = dict([tuple(line.split("=", 1)) for line in lines if line])
45 if r.status == 403:
46 auth = ""
47 else:
48 auth = d['Auth']
49 return auth
50
51 # Try an operation
52 headers = {}
53 conn = HTTPConnection('www.blogger.com')
54 conn.request("GET", "/feeds/default/blogs?alt=atom-service", headers=headers)
55 r = conn.getresponse()
56 print r.status
57 content = r.read()
58 # If we get a 401 then respond to the challenge
59 if r.status == 401:
60 name, password = open("/home/jcgregorio/gmail", "r").read().split()
61 useragent = "My-App-01"
62 headers = {}
63 challenge = _parse_www_authenticate(r.getheader('www-authenticate'))
64 if 'googlelogin' in challenge:
65 auth = googlelogin(name, password, useragent, challenge)
66 headers['authorization'] = 'GoogleLogin Auth=' + auth
67 else:
68 # Obviously you could check for 'basic' in challenge and
69 # do Basic auth here. Similarly for Digest.
70 pass
71
72 # Now try the request again, this time with the authorization header in place.
73 conn.request("GET", "/feeds/default/blogs?alt=atom-service", headers=headers)
74 r = conn.getresponse()
75 print r.status
76 print r.read()