Skip to content

Commit

Permalink
Merge pull request oauthlib#20 from calebbrown/master
Browse files Browse the repository at this point in the history
Bug fixes for the OAuth 1.0 Client and Server
  • Loading branch information
idan committed Apr 19, 2012
2 parents cd12e00 + 6d56d09 commit 4d26eb9
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 16 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -5,3 +5,4 @@ Idan Gazit
David Gouldin
Ib Lundgren
Daniel Greenfeld
Caleb Brown
16 changes: 8 additions & 8 deletions oauthlib/oauth1/rfc5849/__init__.py
Expand Up @@ -138,7 +138,7 @@ def sign(self, uri, http_method=u'GET', body='', headers=None):

# take the new OAuth params with signature and contribute the
# now-complete parameters to the uri or authorization header
return self._contribute_parameters(uri, params)
return self._contribute_parameters(uri, params, body=body, headers=headers)


class Server(object):
Expand All @@ -156,7 +156,7 @@ def get_resource_owner_secret(self, resource_owner_key):
def get_signature_type_and_params(self, uri_query, headers, body):
signature_types_with_oauth_params = filter(lambda s: s[1], (
(SIGNATURE_TYPE_AUTH_HEADER, utils.filter_oauth_params(
signature.collect_parameters(header=header,
signature.collect_parameters(headers=headers,
exclude_oauth_signature=False))),
(SIGNATURE_TYPE_BODY, utils.filter_oauth_params(
signature.collect_parameters(body=body,
Expand All @@ -166,11 +166,11 @@ def get_signature_type_and_params(self, uri_query, headers, body):
exclude_oauth_signature=False))),
))

if len(signature_types_with_params) > 1:
if len(signature_types_with_oauth_params) > 1:
raise ValueError('oauth_ params must come from only 1 signature type but were found in %s' % ', '.join(
[s[0] for s in signature_types_with_params]))
[s[0] for s in signature_types_with_oauth_params]))
try:
signature_type, params = signature_types_with_params[0]
signature_type, params = signature_types_with_oauth_params[0]
except IndexError:
raise ValueError('oauth_ params are missing. Could not determine signature type.')

Expand Down Expand Up @@ -217,7 +217,7 @@ def check_request_signature(self, uri, http_method=u'GET', body='',
timestamp = params.get(u'oauth_timestamp')
callback_uri = params.get(u'oauth_callback')
verifier = params.get(u'oauth_verifier')
signature_method = params.get(u'oauth_signature')
signature_method = params.get(u'oauth_signature_method')

# ensure all mandatory parameters are present
if not all((request_signature, client_key, nonce,
Expand Down Expand Up @@ -249,7 +249,7 @@ def check_request_signature(self, uri, http_method=u'GET', body='',
# oauth_client parameters depend on client chosen signature method
# which may vary for each request, section 3.4
# HMAC-SHA1 and PLAINTEXT share parameters
if signature_method == RSA_SHA1:
if signature_method == SIGNATURE_RSA:
oauth_client = Client(client_key,
resource_owner_key=resource_owner_key,
callback_uri=callback_uri,
Expand All @@ -270,7 +270,7 @@ def check_request_signature(self, uri, http_method=u'GET', body='',
verifier=verifier)

client_signature = oauth_client.get_oauth_signature(uri,
body=body, headers=headers)
http_method=http_method, body=body, headers=headers)

# FIXME: use near constant time string compare to avoid timing attacks
return client_signature == request_signature
Expand Down
7 changes: 4 additions & 3 deletions oauthlib/oauth1/rfc5849/signature.py
Expand Up @@ -112,7 +112,7 @@ def collect_parameters(uri_query='', body='', headers=None,
if isinstance(k, str):
k = k.decode('utf-8')
if isinstance(v, str):
if v.startswith('oauth_'):
if k.startswith('oauth_'):
v = utils.unescape(v)
else:
v = v.decode('utf-8')
Expand Down Expand Up @@ -153,8 +153,9 @@ def sign_hmac_sha1(base_string, client_secret, resource_owner_secret):
.. _`section 3.4.2`: http://tools.ietf.org/html/rfc5849#section-3.4.2
"""

key = '&'.join((utils.escape(client_secret),
utils.escape(resource_owner_secret)))
key = '&'.join((utils.escape(client_secret or u''),
utils.escape(resource_owner_secret or u'')))

signature = hmac.new(key, base_string, hashlib.sha1)
return binascii.b2a_base64(signature.digest())[:-1].decode('utf-8')

Expand Down
4 changes: 3 additions & 1 deletion oauthlib/oauth1/rfc5849/utils.py
Expand Up @@ -98,13 +98,15 @@ def escape(u):
"""
if not isinstance(u, unicode):
raise ValueError('Only unicode objects are escapable.')
# Letters, digits, and the characters '_.-' are already treated as safe
# by urllib.quote(). We need to add '~' to fully support rfc5849.
return urllib.quote(u.encode('utf-8'), safe='~')


def unescape(s):
if not isinstance(s, str):
raise ValueError('Only string objects are unescapable.')
return urllib.unquote(s, safe='~').decode('utf-8')
return urllib.unquote(s).decode('utf-8')


def urlencode(query):
Expand Down
64 changes: 64 additions & 0 deletions tests/oauth1/rfc5849/test_server.py
@@ -0,0 +1,64 @@
from __future__ import absolute_import
from oauthlib.oauth1.rfc5849 import *
from oauthlib.oauth1.rfc5849 import utils
from ...unittest import TestCase




class ServerTests(TestCase):

CLIENT_KEY = u'dpf43f3p2l4k3l03'
CLIENT_SECRET = u'kd94hf93k423kf44'

RESOURCE_OWNER_KEY = u'kkk9d7dh3k39sjv7'
RESOURCE_OWNER_SECRET = u'just-a-string asdasd'

class TestServer(Server):
def get_client_secret(self, client_key):
return ServerTests.CLIENT_SECRET

def get_resource_owner_secret(self, resource_owner_key):
return ServerTests.RESOURCE_OWNER_SECRET

def check_client_key(self, client_key):
return ServerTests.CLIENT_KEY == client_key

def check_resource_owner_key(self, client_key, resource_owner_key):
return (ServerTests.CLIENT_KEY == client_key and
ServerTests.RESOURCE_OWNER_KEY == resource_owner_key)

def check_timestamp_and_nonce(self, timestamp, nonce):
return True

def test_basic_server_request(self):
c = Client(self.CLIENT_KEY,
client_secret=self.CLIENT_SECRET,
resource_owner_key=self.RESOURCE_OWNER_KEY,
resource_owner_secret=self.RESOURCE_OWNER_SECRET,
)

uri, body, headers = c.sign(u'http://server.example.com:80/init')

headers = dict([(str(k), str(v)) for k, v in headers.iteritems()])

s = self.TestServer()
self.assertTrue(s.check_request_signature(uri, body=body,
headers=headers))

def test_server_callback_request(self):
c = Client(self.CLIENT_KEY,
client_secret=self.CLIENT_SECRET,
resource_owner_key=self.RESOURCE_OWNER_KEY,
resource_owner_secret=self.RESOURCE_OWNER_SECRET,
callback_uri=u'http://client.example.com/callback'
)

uri, body, headers = c.sign(u'http://server.example.com:80/init')

headers = dict([(str(k), str(v)) for k, v in headers.iteritems()])

s = self.TestServer()
self.assertTrue(s.check_request_signature(uri, body=body,
headers=headers))

14 changes: 10 additions & 4 deletions tests/oauth1/rfc5849/test_utils.py
Expand Up @@ -39,7 +39,7 @@ class UtilsTests(TestCase):
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="137131201",
oauth_nonce="7d8f3e4a",
oauth_signature="djosJKDKJSD8743243%2Fjdk33klY%3D" """.strip()
oauth_signature="djosJKDKJSD8743243%2Fjdk33klY%3D" """.strip()


def test_filter_params(self):
Expand Down Expand Up @@ -73,7 +73,7 @@ def test_filter_oauth_params(self):
# should not be present in the filtered params
filtered_params = filter_oauth_params(self.sample_params_list)
self.assertEqual(len(filtered_params), 2)

self.assertTrue(filtered_params[0][0].startswith('oauth'))
self.assertTrue(filtered_params[1][0].startswith('oauth'))

Expand All @@ -86,7 +86,7 @@ def test_filter_oauth_params(self):
# should not be present in the filtered params
filtered_params = filter_oauth_params(self.sample_params_dict)
self.assertEqual(len(filtered_params), 2)

self.assertTrue(filtered_params[0][0].startswith('oauth'))
self.assertTrue(filtered_params[1][0].startswith('oauth'))

Expand All @@ -95,7 +95,7 @@ def test_utf8_str(self):
# check against crazy string
crazy_string = "àçéghîłñôßûÿž♬♨♧"
self.assertTrue(isinstance(utf8_str(crazy_string), str))

# check against crazy unicode
crazy_unicode = utf8_str(u"àçéghîłñôßûÿž♬♨♧")
self.assertTrue(isinstance(crazy_unicode, str))
Expand Down Expand Up @@ -128,6 +128,12 @@ def test_generate_token(self):
def test_escape(self):
self.assertRaises(ValueError, escape, "I am a string type. Not a unicode type.")
self.assertEqual(escape(u"I am a unicode type."), u"I%20am%20a%20unicode%20type.")
self.assertIsInstance(escape(u"I am a unicode type."), str)

def test_unescape(self):
self.assertRaises(ValueError, unescape, u"I am a unicode type. Not a string type.")
self.assertEqual(unescape("I%20am%20a%20unicode%20type."), u'I am a unicode type.')
self.assertIsInstance(unescape("I%20am%20a%20unicode%20type."), unicode)

def test_urlencode(self):

Expand Down

0 comments on commit 4d26eb9

Please sign in to comment.