J'ai passé une journée entière sur le codage ce, après plusieurs tentatives infructueuses au cours des dernières semaines. Cela vous permet seulement d'atteindre la première étape, mais sans bibliothèque externe. Et oui, je sais que c'est près de deux ans après le PO, mais d'après ce que j'ai pu voir, il fallait encore le faire.
#!/usr/bin/python
'demo Google OAuth'
import sys, os, urllib, urllib2, time, httplib
import hmac, hashlib, random, re, base64
PARAMETERS = {
'oauth_consumer_key': os.getenv('OAUTH_CONSUMER_KEY') or 'anonymous',
'oauth_signature_method': 'HMAC-SHA1',
'oauth_signature': '',
'oauth_timestamp': os.getenv('OAUTH_TIMESTAMP') or '%d' % time.time(),
'oauth_nonce': os.getenv('OAUTH_NONCE') or '%x' % random.getrandbits(64),
'oauth_version': '1.0',
'oauth_callback': os.getenv('OAUTH_CALLBACK') or 'callback',
}
SCOPE = {'scope': 'https://www.google.com/calendar/feeds/'}
SECRET = os.getenv('OAUTH_CONSUMER_SECRET') or 'anonymous'
def google_oauth():
'OAuthGetRequestToken, OAuthAuthorizeToken, OAuthGetAccessToken'
request_token = get_request_token()
return request_token
def get_request_token():
'ask Google for a request token'
url = 'https://www.google.com/accounts/OAuthGetRequestToken'
token_secret = '' # we don't have a token secret yet
PARAMETERS['oauth_signature'] = sign('&'.join((SECRET, token_secret)),
'&'.join(map(urlencode, ('GET', url, parameters('signing')))))
body = urllib.urlencode(SCOPE)
request = urllib2.Request(url + '?' + body)
request.add_header('Authorization', 'OAuth ' + parameters('header'))
opener = urllib2.build_opener(urllib2.HTTPSHandler(debuglevel = 1))
response = opener.open(request)
reply = response.read()
response.close()
return reply
def byte_encode(match):
'for use with re.sub'
return '%%%02X' % ord(match.group())
def urlencode(string):
"unreserved = ALPHA, DIGIT, '-', '.', '_', '~'"
return re.sub(re.compile('[^0-9A-Za-z._~-]'),
byte_encode, string.encode('utf8'))
def sign(secret, text):
print >>sys.stderr, 'signature base string: "%s", secret: %s' % (
repr(text), repr(secret))
digest = hmac.new(secret, text, hashlib.sha1).digest()
return urlencode(base64.encodestring(digest).rstrip())
def base64string(hexstring):
recoded = urlencode(base64.encodestring(hexstring.decode('hex')).rstrip())
print >>sys.stderr, 'recoded:', recoded
return recoded
def parameters(format):
if format == 'header':
formatted = ', '.join(['%s="%s"' % (key, value)
for key, value in PARAMETERS.items()])
elif format == 'signing':
formatted = '&'.join(sorted(['%s=%s' % (key,
urlencode(value.encode('utf8'))) for
key, value in (PARAMETERS.items() + SCOPE.items()) if
key not in ['oauth_signature']]))
#print >>sys.stderr, format, formatted
return formatted
def hmac_sha1_test():
'from tools.ietf.org/html/rfc2202'
assert sign('\x0b' * 20, 'Hi There') == base64string(
'b617318655057264e28bc0b6fb378c8ef146be00')
assert sign('Jefe', 'what do ya want for nothing?') == base64string(
'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79')
assert sign('\xaa' * 20, '\xdd' * 50) == base64string(
'125d7342b9ac11cd91a39af48aa17b4f63f175d3')
# last test from http://oauth.net/core/1.0/#rfc.section.9.1.1, app. A.5.2
assert sign('kd94hf93k423kf44&pfkkdhi9sl3r4s00',
'GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26' + \
'oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3D' + \
'kllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26' + \
'oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26' + \
'oauth_version%3D1.0%26size%3Doriginal') == urlencode(
'tR3+Ty81lMeYAr/Fid0kMTYa/WM=')
return True
if __name__ == '__main__':
command = os.path.splitext(os.path.basename(sys.argv[0]))[0]
print eval(command)(*sys.argv[1:])
Enregistrer comme google_oauth.py, et vous pouvez créer un lien vers elle comme ceci:
ln -s google_oauth.py hmac_sha1_test.py
pour tester l'un des sous-routines. Combiné avec l'utilisation de variables d'environnement, vous pouvez comparer vos résultats avec ceux de OAuth Playground de Google (d'autres personnes ici ont fourni le lien) et voir où vous allez mal. J'ai trouvé beaucoup de problèmes avec le script de cette façon; il pourrait bien y en avoir beaucoup plus. Mais si vous invoquez ./google_oauth.py, vous devriez voir quelque chose comme ceci:
[email protected]:~/rentacoder/marchie$ ./google_oauth.py
signature base string: "'GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_callback%3Dcallback%26oauth_consumer_key%3Danonymous%26oauth_nonce%3Da64720fda018906b%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1302253695%26oauth_version%3D1.0%26scope%3Dhttps%253A%252F%252Fwww.google.com%252Fcalendar%252Ffeeds%252F'", secret: 'anonymous&'
send: 'GET /accounts/OAuthGetRequestToken?scope=https%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: www.google.com\r\nConnection: close\r\nAuthorization: OAuth oauth_nonce="a64720fda018906b", oauth_timestamp="1302253695", oauth_consumer_key="anonymous", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_signature="LSJxopFXWN71sTSIBIkNeGgsOjc%3D", oauth_callback="callback"\r\nUser-Agent: Python-urllib/2.6\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: text/plain; charset=UTF-8
header: Date: Fri, 08 Apr 2011 09:08:20 GMT
header: Expires: Fri, 08 Apr 2011 09:08:20 GMT
header: Cache-Control: private, max-age=0
header: X-Content-Type-Options: nosniff
header: X-XSS-Protection: 1; mode=block
header: Content-Length: 118
header: Server: GSE
header: Connection: close
oauth_token=4%2FfvSIWW9WBHXa_CjInpOf4FdNYhCj&oauth_token_secret=qhB1EGIKjL1pG9POF2ZOcQk3&oauth_callback_confirmed=true
J'ai travaillé sur la même chose toute la journée, j'espère que quelque chose fonctionnera bientôt. –