Skip to content

Instantly share code, notes, and snippets.

@zookos
Created January 20, 2011 23:55
Show Gist options
  • Save zookos/788972 to your computer and use it in GitHub Desktop.
Save zookos/788972 to your computer and use it in GitHub Desktop.
oauth.py
# copied from https://github.com/simplegeo/python-oauth2 and modified
from simplegeo.shared import to_unicode
import hashlib, hmac, urllib
def escape(s):
"""Escape a URL including any /."""
return urllib.quote(to_unicode(s).encode('utf-8'), safe='~')
def normalize_parameters(params):
items = []
for k, v in params.iteritems():
# 1.0a/9.1.1 states that kvp must be sorted by key, then by
# value, so we unpack sequence values into multiple items for
# sorting.
if isinstance(v, basestring):
items.append((k, v))
else:
for e in v:
items.append((k, e))
# Encode signature parameters per Oauth Core 1.0 protocol spec
# draft 7, section 3.6
# (http://tools.ietf.org/html/draft-hammer-oauth-07#section-3.6)
# Spaces must be encoded with "%20" instead of "+"
return urllib.urlencode(sorted(items)).replace('+', '%20').replace('%7E', '~')
def signing_base(method, url, params, secret):
sig = [
escape(method),
escape(url),
escape(normalize_parameters(params)),
]
key = '%s&' % escape(secret)
raw = '&'.join(sig)
return key, raw
def sign_request(key, secret, method, url, params, realm):
params['oauth_consumer_key'] = key
params['oauth_signature_method'] = 'HMAC-SHA1'
key, raw = signing_base(method, url, params, secret)
params['oauth_signature'] = hmac.new(key, raw, hashlib.sha1).hexdigest()
oauth_params = ((k, escape(to_unicode(v))) for k, v in params.iteritems() if k.startswith('oauth_'))
header_params = ('%s="%s"' % (k, v) for k, v in oauth_params)
params_header = ', '.join(header_params)
auth_header = 'OAuth realm="%s"' % realm
if params_header:
auth_header = "%s, %s" % (auth_header, params_header)
return auth_header
import unittest
from oauth import escape, normalize_parameters, signing_base, sign_request
class ReallyEqualMixin:
def failUnlessReallyEqual(self, a, b, msg=None):
self.failUnlessEqual(a, b, msg=msg)
self.failUnlessEqual(type(a), type(b), msg="a :: %r, b :: %r, %r" % (a, b, msg))
class OauthTest(unittest.TestCase, ReallyEqualMixin):
def test_escape(self):
self.failUnlessReallyEqual(escape('~'), '~')
self.failUnlessReallyEqual(escape(u'\u2766'), '%E2%9D%A6')
def test_signing_base(self):
sb = signing_base('GET', 'http://example.com/api/', {}, 'sekrit')
self.failUnlessReallyEqual(sb, ('sekrit&', 'GET&http%3A%2F%2Fexample.com%2Fapi%2F&'))
def test_normalize_parameters(self):
np = normalize_parameters({'d': 'b', 'c': 'd'})
self.failUnlessReallyEqual(np, 'c=d&d=b')
np = normalize_parameters({'a': 'b', 'c': 'd'})
self.failUnlessReallyEqual(np, 'a=b&c=d')
np = normalize_parameters({'a': ['e', 'b'], 'c': 'd'})
self.failUnlessReallyEqual(np, 'a=b&a=e&c=d')
np = normalize_parameters({'a': 'b c'})
self.failUnlessReallyEqual(np, 'a=b%20c')
np = normalize_parameters({'a': 'b~c'})
self.failUnlessReallyEqual(np, 'a=b~c')
def test_sign(self):
authheader = sign_request('abcde', 'fghijk', 'GET', 'http://example.com/api', {}, 'example')
self.failUnlessReallyEqual(authheader, 'OAuth realm="example", oauth_signature="8b1d544bfc74ae64784dd95b0fffaf2c48a027a4", oauth_consumer_key="abcde", oauth_signature_method="HMAC-SHA1"')
authheader = sign_request('abcde', 'fghijk', 'GET', 'http://example.com/api', {'a': ['e', 'b'], 'c': 'd'}, 'example')
self.failUnlessReallyEqual(authheader, 'OAuth realm="example", oauth_signature="769eeb73ed355ad177cf113bc28a85a54c8c8ff6", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="abcde"')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment