Up

googlelogin.py

 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()