summaryrefslogtreecommitdiff
path: root/oauthlib
diff options
context:
space:
mode:
authorIdan Gazit <idan@gazit.me>2012-03-12 17:23:18 -0700
committerIdan Gazit <idan@gazit.me>2012-03-12 17:23:18 -0700
commita4a954c9fc0970c90ed4dbacdb2a6dd5200e2543 (patch)
treef4f968e1249ad16d31f0ef0af746d1703b06af30 /oauthlib
parent9b264d1efde3800bcc0258f805ab7affd081ffcb (diff)
parent31710fe8b16ff3b19ccc770a635ed7994f00562d (diff)
downloadoauthlib-a4a954c9fc0970c90ed4dbacdb2a6dd5200e2543.tar.gz
Merge branch 'master' of github.com:idangazit/oauthlib
Diffstat (limited to 'oauthlib')
-rw-r--r--oauthlib/oauth.py229
-rw-r--r--oauthlib/signature.py13
-rw-r--r--oauthlib/utils.py12
3 files changed, 113 insertions, 141 deletions
diff --git a/oauthlib/oauth.py b/oauthlib/oauth.py
index bf71546..1ff1955 100644
--- a/oauthlib/oauth.py
+++ b/oauthlib/oauth.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import absolute_import
"""
oauthlib.oauth
@@ -8,141 +9,105 @@ This module is a generic implementation of various logic needed
for signing OAuth requests.
"""
-import time
-import hashlib
-from random import getrandbits
-import urllib
-import hmac
-import binascii
-from urlparse import urlparse
+import urlparse
+
+from . import parameters, signature, utils
SIGNATURE_HMAC = "HMAC-SHA1"
SIGNATURE_RSA = "RSA-SHA1"
SIGNATURE_PLAINTEXT = "PLAINTEXT"
+SIGNATURE_TYPE_AUTH_HEADER = 'AUTH_HEADER'
+SIGNATURE_TYPE_QUERY = 'QUERY'
+
+class OAuthClient(object):
+ """An OAuth client used to sign OAuth requests"""
+ def __init__(self, client_key, client_secret,
+ resource_owner_key, resource_owner_secret,
+ signature_method=SIGNATURE_HMAC,
+ signature_type=SIGNATURE_TYPE_AUTH_HEADER,
+ callback_uri=None, rsa_key=None, verifier=None):
+ self.client_key = client_key
+ self.client_secret = client_secret
+ self.resource_owner_key = resource_owner_key
+ self.resource_owner_secret = resource_owner_secret
+ self.signature_method = signature_method
+ self.signature_type = signature_type
+ self.callback_uri = callback_uri
+ self.rsa_key = rsa_key
+ self.verifier = verifier
+
+ def get_oauth_signature(self, uri, http_method=u'GET', body=None,
+ authorization_header=None):
+ """Get an OAuth signature to be used in signing a request"""
+ if self.signature_method == SIGNATURE_PLAINTEXT:
+ # fast-path
+ return signature.sign_plaintext(self.client_secret,
+ self.resource_owner_secret)
+
+ query = urlparse.urlparse(uri).query
+ params = signature.collect_parameters(uri_query=query,
+ authorization_header=authorization_header, body=body)
+ normalized_params = signature.normalize_parameters(params)
+ normalized_uri = signature.normalize_base_string_uri(uri)
+ base_string = signature.construct_base_string(http_method,
+ normalized_uri, normalized_params)
+ if self.signature_method == SIGNATURE_HMAC:
+ return signature.sign_hmac_sha1(base_string, self.client_secret,
+ self.resource_owner_secret)
+ elif self.signature_method == SIGNATURE_RSA:
+ return signature.sign_rsa_sha1(base_string, self.rsa_key)
+ else:
+ return signature.sign_plaintext(self.client_secret,
+ self.resource_owner_secret)
+
+ def get_oauth_params(self):
+ """Get the basic OAuth parameters to be used in generating a signature.
+ """
+ params = [
+ (u'oauth_nonce', utils.generate_nonce()),
+ (u'oauth_timestamp', utils.generate_timestamp()),
+ (u'oauth_version', '1.0'),
+ (u'oauth_signature_method', self.signature_method),
+ (u'oauth_consumer_key', self.client_key),
+ (u'oauth_token', self.resource_owner_key),
+ ]
+ if self.callback_uri:
+ params.append((u'oauth_callback', self.callback_uri))
+ if self.verifier:
+ params.append((u'oauth_verifier', self.verifier))
+
+ return params
+
+ def _contribute_parameters(self, uri, params):
+ if self.signature_type == SIGNATURE_TYPE_AUTH_HEADER:
+ authorization_header = parameters.prepare_authorization_header(
+ params)
+ complete_uri = uri
+ else:
+ authorization_header = None
+ complete_uri = paramaters.prepare_request_uri_query(params, uri)
+
+ return complete_uri, authorization_header
+
+ def sign_request(self, uri, http_method=u'GET', body=None):
+ """Get the signed uri and authorization header.
+ Authorization header will be None if signature type is "query".
+ """
+ # get the OAuth params and contribute them to either the uri or
+ # authorization header
+ params = self.get_oauth_params()
+ complete_uri, authorization_header = self._contribute_parameters(uri,
+ params)
+
+ # use the new uri and authorization header to generate a signature and
+ # contribute that signature to the OAuth parameters
+ oauth_signature = self.get_oauth_signature(complete_uri,
+ http_method=http_method, body=body,
+ authorization_header=authorization_header)
+ params.append((u'oauth_signature', oauth_signature))
+
+ # 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)
-
-
-def generate_params(client_key, access_token, signature_method):
- """Generates the requisite parameters for a valid OAuth request."""
- params = {
- 'oauth_consumer_key': client_key,
- 'oauth_nonce': generate_nonce(),
- 'oauth_signature_method': signature_method,
- 'oauth_token': access_token,
- 'oauth_timestamp': generate_timestamp(),
- 'oauth_version': '1.0',
- }
- return params
-
-
-def normalize_http_method(method):
- """Uppercases the HTTP method.
-
- Per `section 3.4.1.1` of the spec.
-
- .. _`section 3.4.1.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.1
-
- """
- return method.upper()
-
-
-def normalize_base_string_uri(uri):
- """Prepares the base string URI.
-
- Parses the URL and rebuilds it to be scheme://host/path. The normalized
- return value is already escaped.
-
- Per `section 3.4.1.2` of the spec.
-
- .. _`section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2
-
- """
- parts = urlparse(uri)
- scheme, netloc, path = parts[:3]
- # Exclude default port numbers.
- if scheme == 'http' and netloc[-3:] == ':80':
- netloc = netloc[:-3]
- elif scheme == 'https' and netloc[-4:] == ':443':
- netloc = netloc[:-4]
- return escape('{0}://{1}{2}'.format(scheme, netloc, path))
-
-
-def normalize_parameters(params):
- """Prepares the request parameters.
-
- Per `section 3.4.1.3` of the spec.
-
- .. _`section 3.4.1.3`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3
-
- """
- try:
- # Exclude the signature if it exists.
- del params['oauth_signature']
- except:
- pass
-
- # Escape key values before sorting.
- key_values = []
- for k, v in params.items():
- key_values.append((escape(utf8_str(k)), escape(utf8_str(v))))
-
- # Sort lexicographically, first after key, then after value.
- key_values.sort()
-
- # Combine key value pairs into a string and return.
- return escape('&'.join(['{0}={1}'.format(escape(k), escape(v)) for k, v in key_values]))
-
-
-def prepare_hmac_key(client_secret, access_secret=None):
- """Prepares the signing key for HMAC-SHA1.
-
- Per `section 3.4.2`_ of the spec.
-
- .. _`section 3.4.2`: http://tools.ietf.org/html/rfc5849#section-3.4.2
-
- """
- return '{0}&{1}'.format(
- escape(client_secret),
- escape(access_secret or ''))
-
-
-def prepare_base_string(method, uri, params):
- """Prepare a signature base string.
-
- Per `section 3.4.1`_ of the spec.
-
- .. _`section 3.4.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1
-
- """
- return "{method}&{uri}&{params}".format(
- method=normalize_http_method(method),
- uri=normalize_base_string_uri(uri),
- params=normalize_parameters(params))
-
-
-def sign_hmac(method, url, params, client_secret, access_secret):
- """Sign a request using HMAC-SHA1.
-
- Per `section 3.4.2`_ of the spec.
-
- .. _`section 3.4.2`: http://tools.ietf.org/html/rfc5849#section-3.4.2
-
- """
- base_string = prepare_base_string(method, url, params)
- key = prepare_hmac_key(client_secret, access_secret)
- signature = hmac.new(key, base_string, hashlib.sha1)
- return escape(binascii.b2a_base64(signature.digest())[:-1])
-
-
-def prepare_authorization_header(realm, params):
- """Prepare the authorization header.
-
- Per `section 3.5.1`_ of the spec.
-
- .. _`section 3.5.1`: http://tools.ietf.org/html/rfc5849#section-3.5.1
-
- """
- return 'OAuth realm="{realm}", {params}'.format(
- realm=realm, params=', '.join(
- ['{0}="{1}"'.format(k, params[k]) for k in params.keys()]))
diff --git a/oauthlib/signature.py b/oauthlib/signature.py
index 688a133..c5a2f5b 100644
--- a/oauthlib/signature.py
+++ b/oauthlib/signature.py
@@ -24,7 +24,6 @@ Steps for signing a request:
import binascii
import hashlib
import hmac
-import urllib2
import urlparse
from . import utils
@@ -78,12 +77,7 @@ def collect_parameters(uri_query=None, authorization_header=None, body=None):
params.extend(urlparse.parse_qs(uri_query).items())
if authorization_header is not None:
- items = urllib2.parse_http_list(authorization_header)
- try:
- auth_header_params = urllib2.parse_keqv_list(items)
- except ValueError:
- raise ValueError('Malformed authorization header')
- params.extend(auth_header_params.items())
+ params.extend(utils.parse_authorization_header(authorization_header))
if body is not None:
params.extend(urlparse.parse_qs(body).items())
@@ -94,7 +88,7 @@ def collect_parameters(uri_query=None, authorization_header=None, body=None):
)
params = filter(lambda i: i[0] not in exclude_params, params)
- return params.items()
+ return params
def normalize_parameters(params):
"""Normalize querystring parameters for use in constructing a base string.
@@ -122,7 +116,8 @@ def sign_hmac_sha1(base_string, client_secret, resource_owner_secret):
key = u'&'.join((utils.escape(client_secret),
utils.escape(resource_owner_secret)))
- signature = hmac.new(key, base_string, hashlib.sha1)
+ signature = hmac.new(key.encode('utf-8'), base_string.encode('utf-8'),
+ hashlib.sha1)
return binascii.b2a_base64(signature.digest())[:-1]
def sign_rsa_sha1(base_string, rsa_private_key):
diff --git a/oauthlib/utils.py b/oauthlib/utils.py
index 0b81df4..20b4d70 100644
--- a/oauthlib/utils.py
+++ b/oauthlib/utils.py
@@ -10,6 +10,7 @@ spec.
import time
import urllib
+import urllib2
from random import getrandbits
@@ -90,3 +91,14 @@ def urlencode(query):
query = query.items()
return "&".join(['='.join([escape(k), escape(v)]) for k, v in query])
+def parse_authorization_header(authorization_header):
+ """Parse an OAuth authorization header into a list of 2-tuples"""
+ auth_scheme = 'OAuth '
+ if authorization_header.startswith(auth_scheme):
+ authorization_header = authorization_header.replace(auth_scheme, '', 1)
+ items = urllib2.parse_http_list(authorization_header)
+ try:
+ return urllib2.parse_keqv_list(items).items()
+ except ValueError:
+ raise ValueError('Malformed authorization header')
+