diff options
| author | David Gouldin <david@gould.in> | 2012-05-01 23:29:48 -0700 |
|---|---|---|
| committer | David Gouldin <david@gould.in> | 2012-05-01 23:30:01 -0700 |
| commit | 70c405473288098fd3e1d4f17bec2b737589ef2b (patch) | |
| tree | ec05fe591a9ce4ea138bc6af51e3574efdec99fd | |
| parent | 772d48de9a285d9f95dcac49be4542576c38c267 (diff) | |
| download | oauthlib-70c405473288098fd3e1d4f17bec2b737589ef2b.tar.gz | |
More porting of internal metods to use Request objects. Some tests are still broken.
| -rw-r--r-- | oauthlib/common.py | 8 | ||||
| -rw-r--r-- | oauthlib/oauth1/rfc5849/__init__.py | 71 | ||||
| -rw-r--r-- | oauthlib/oauth1/rfc5849/parameters.py | 20 | ||||
| -rw-r--r-- | tests/oauth1/rfc5849/test_parameters.py | 29 |
4 files changed, 58 insertions, 70 deletions
diff --git a/oauthlib/common.py b/oauthlib/common.py index a8bbde1..5ec354e 100644 --- a/oauthlib/common.py +++ b/oauthlib/common.py @@ -155,8 +155,14 @@ class Request(object): return urlparse.parse_qsl(self.uri_query, keep_blank_values=True, strict_parsing=True) + @property + def urlencoded_body(self): + return urlencode(self.body or []) + def clone(self): - return Request(self.uri, http_method=self.http_method, + cloned_request = Request(self.uri, http_method=self.http_method, body=self.body, headers=copy.copy(self.headers)) + cloned_request.oauth_params = self.oauth_params + return cloned_request diff --git a/oauthlib/oauth1/rfc5849/__init__.py b/oauthlib/oauth1/rfc5849/__init__.py index d5fccad..98dcf93 100644 --- a/oauthlib/oauth1/rfc5849/__init__.py +++ b/oauthlib/oauth1/rfc5849/__init__.py @@ -13,7 +13,7 @@ import logging import urlparse from oauthlib.common import Request, urlencode -from . import parameters, signature, utils, constants +from . import constants, parameters, signature, utils class Client(object): @@ -23,8 +23,8 @@ class Client(object): resource_owner_key=None, resource_owner_secret=None, callback_uri=None, - signature_method=SIGNATURE_HMAC, - signature_type=SIGNATURE_TYPE_AUTH_HEADER, + signature_method=constants.SIGNATURE_METHOD_HMAC, + signature_type=constants.SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None): self.client_key = client_key self.client_secret = client_secret @@ -36,25 +36,23 @@ class Client(object): self.rsa_key = rsa_key self.verifier = verifier - if self.signature_method == SIGNATURE_RSA and self.rsa_key is None: + if (self.signature_method == constants.SIGNATURE_METHOD_RSA and + self.rsa_key is None): raise ValueError('rsa_key is required when using RSA signature method.') def get_oauth_signature(self, request): """Get an OAuth signature to be used in signing a request """ - if self.signature_method == SIGNATURE_PLAINTEXT: + if self.signature_method == constants.SIGNATURE_METHOD_PLAINTEXT: # fast-path return signature.sign_plaintext(self.client_secret, self.resource_owner_secret) # XXX hack to make sure oauth params are included in the info # passed to collect_parameters below. Is there a cleaner way? - uri, headers, body = self._render(request) + request = self._render(request) - collected_params = signature.collect_parameters( - uri_query=urlparse.urlparse(uri).query, - body=body, - headers=headers) + collected_params = signature.collect_parameters(request) logging.debug("Collected params: {0}".format(collected_params)) normalized_params = signature.normalize_parameters(collected_params) @@ -67,14 +65,13 @@ class Client(object): logging.debug("Base signing string: {0}".format(base_string)) - if self.signature_method == SIGNATURE_HMAC: + if self.signature_method == constants.SIGNATURE_METHOD_HMAC: return signature.sign_hmac_sha1(base_string, self.client_secret, self.resource_owner_secret) - elif self.signature_method == SIGNATURE_RSA: + elif self.signature_method == constants.SIGNATURE_METHOD_RSA: return signature.sign_rsa_sha1(base_string, self.rsa_key) else: - return signature.sign_plaintext(self.client_secret, - self.resource_owner_secret) + raise ValueError("Unknown signature method: %s" % self.signature_method) def get_oauth_params(self): """Get the basic OAuth parameters to be used in generating a signature. @@ -105,29 +102,7 @@ class Client(object): """ # TODO what if there are body params on a header-type auth? # TODO what if there are query params on a body-type auth? - - uri, headers, body = request.uri, request.headers, request.body - - # TODO: right now these prepare_* methods are very narrow in scope--they - # only affect their little thing. In some cases (for example, with - # header auth) it might be advantageous to allow these methods to touch - # other parts of the request, like the headers—so the prepare_headers - # method could also set the Content-Type header to x-www-form-urlencoded - # like the spec requires. This would be a fundamental change though, and - # I'm not sure how I feel about it. - if self.signature_type == SIGNATURE_TYPE_AUTH_HEADER: - request = parameters.prepare_headers(request) - elif self.signature_type == SIGNATURE_TYPE_BODY and request.decoded_body is not None: - body = parameters.prepare_form_encoded_body(request.oauth_params, request.decoded_body) - if formencode: - body = urlencode(body) - headers['Content-Type'] = u'application/x-www-form-urlencoded' - elif self.signature_type == SIGNATURE_TYPE_QUERY: - uri = parameters.prepare_request_uri_query(request.oauth_params, request.uri) - else: - raise ValueError('Unknown signature type specified.') - - return uri, headers, body + return parameters.prepare_request(request, self.signature_type) def sign(self, uri, http_method=u'GET', body=None, headers=None): """Sign a request @@ -159,8 +134,9 @@ class Client(object): # sanity check content_type = request.headers.get('Content-Type', None) multipart = content_type and content_type.startswith('multipart/') - should_have_params = content_type == CONTENT_TYPE_FORM_URLENCODED + should_have_params = content_type == constants.CONTENT_TYPE_FORM_URLENCODED has_params = request.decoded_body is not None + # 3.4.1.3.1. Parameter Sources # [Parameters are collected from the HTTP request entity-body, but only # if [...]: @@ -176,7 +152,6 @@ class Client(object): # header field set to "application/x-www-form-urlencoded". elif not should_have_params and has_params: raise ValueError("Body contains parameters but Content-Type header was not set.") - # 3.5.2. Form-Encoded Body # Protocol parameters can be transmitted in the HTTP request entity- # body, but only if the following REQUIRED conditions are met: @@ -186,7 +161,7 @@ class Client(object): # [W3C.REC-html40-19980424]. # o The HTTP request entity-header includes the "Content-Type" header # field set to "application/x-www-form-urlencoded". - elif self.signature_type == SIGNATURE_TYPE_BODY and not ( + elif self.signature_type == constants.SIGNATURE_TYPE_BODY and not ( should_have_params and has_params and not multipart): raise ValueError('Body signatures may only be used with form-urlencoded content') @@ -197,12 +172,14 @@ class Client(object): request.oauth_params.append((u'oauth_signature', self.get_oauth_signature(request))) # render the signed request and return it - return self._render(request, formencode=True) + request = self._render(request) + return request.uri, request.headers, request.urlencoded_body class Server(object): """A server used to verify OAuth 1.0 RFC 5849 requests""" - def __init__(self, signature_method=SIGNATURE_HMAC, rsa_key=None): + def __init__(self, signature_method=constants.SIGNATURE_METHOD_HMAC, + rsa_key=None): self.signature_method = signature_method self.rsa_key = rsa_key @@ -214,13 +191,13 @@ class Server(object): 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( + (constants.SIGNATURE_TYPE_AUTH_HEADER, utils.filter_oauth_params( signature.collect_parameters(headers=headers, exclude_oauth_signature=False))), - (SIGNATURE_TYPE_BODY, utils.filter_oauth_params( + (constants.SIGNATURE_TYPE_BODY, utils.filter_oauth_params( signature.collect_parameters(body=body, exclude_oauth_signature=False))), - (SIGNATURE_TYPE_QUERY, utils.filter_oauth_params( + (constants.SIGNATURE_TYPE_QUERY, utils.filter_oauth_params( signature.collect_parameters(uri_query=uri_query, exclude_oauth_signature=False))), )) @@ -289,7 +266,7 @@ class Server(object): raise ValueError("Invalid OAuth version.") # signature method must be valid - if not signature_method in SIGNATURE_METHODS: + if not signature_method in constants.SIGNATURE_METHODS: raise ValueError("Invalid signature method.") # ensure client key is valid @@ -309,7 +286,7 @@ class Server(object): # 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 == SIGNATURE_RSA: + if signature_method == constants.SIGNATURE_METHOD_RSA: oauth_client = Client(client_key, resource_owner_key=resource_owner_key, callback_uri=callback_uri, diff --git a/oauthlib/oauth1/rfc5849/parameters.py b/oauthlib/oauth1/rfc5849/parameters.py index e36dd28..315cccf 100644 --- a/oauthlib/oauth1/rfc5849/parameters.py +++ b/oauthlib/oauth1/rfc5849/parameters.py @@ -15,8 +15,6 @@ from . import constants, utils from oauthlib.common import extract_params, urlencode -# TODO: do we need filter_params now that oauth_params are handled by Request? -# We can easily pass in just oauth protocol params. def prepare_headers(request, realm=None): """**Prepare the Authorization header.** Per `section 3.5.1`_ of the spec. @@ -40,12 +38,14 @@ def prepare_headers(request, realm=None): .. _`section 3.5.1`: http://tools.ietf.org/html/rfc5849#section-3.5.1 .. _`RFC2617`: http://tools.ietf.org/html/rfc2617 """ + if not request.oauth_params: + raise ValueError('request.oauth_params must be present.') new_request = request.clone() # Protocol parameters SHALL be included in the "Authorization" header # field as follows: authorization_header_parameters_parts = [] - for oauth_parameter_name, value in oauth_params: + for oauth_parameter_name, value in new_request.oauth_params: # 1. Parameter names and values are encoded per Parameter Encoding # (`Section 3.6`_) # @@ -105,7 +105,7 @@ def _append_params(oauth_params, params): return merged -def prepare_form_encoded_body(request, formencode=False): +def prepare_form_encoded_body(request): """Prepare the Form-Encoded Body. Per `section 3.5.2`_ of the spec. @@ -113,11 +113,12 @@ def prepare_form_encoded_body(request, formencode=False): .. _`section 3.5.2`: http://tools.ietf.org/html/rfc5849#section-3.5.2 """ + if not request.oauth_params: + raise ValueError('request.oauth_params must be present.') + # append OAuth params to the existing body new_request = request.clone() body = _append_params(new_request.oauth_params, new_request.body) - if formencode: - body = urlencode(body) new_request.body = body new_request.headers['Content-Type'] = u'application/x-www-form-urlencoded' return new_request @@ -142,12 +143,15 @@ def prepare_request_uri_query(request): PREPARE_BY_SIGNATURE_TYPE = { - constants.SIGNATURE_TYPE_AUTH_HEADER: prepare_header, + constants.SIGNATURE_TYPE_AUTH_HEADER: prepare_headers, constants.SIGNATURE_TYPE_QUERY: prepare_form_encoded_body, constants.SIGNATURE_TYPE_BODY: prepare_request_uri_query, } def prepare_request(request, signature_type): - return PREPARE_BY_SIGNATURE_TYPE[signature_type](request) + try: + return PREPARE_BY_SIGNATURE_TYPE[signature_type](request) + except KeyError: + raise ValueError('Unknown signature type specified.') diff --git a/tests/oauth1/rfc5849/test_parameters.py b/tests/oauth1/rfc5849/test_parameters.py index 36b6fff..9765cab 100644 --- a/tests/oauth1/rfc5849/test_parameters.py +++ b/tests/oauth1/rfc5849/test_parameters.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from oauthlib.common import urlencode +from oauthlib.common import urlencode, Request from oauthlib.oauth1.rfc5849.parameters import (_append_params, prepare_headers, prepare_form_encoded_body, prepare_request_uri_query) from ...unittest import TestCase @@ -58,31 +58,32 @@ class ParameterTests(TestCase): self.assertEqual(_append_params(unordered_1, unordered_2), expected) def test_prepare_headers(self): + request = Request(u'http://www.google.com/') + request.oauth_params = self.auth_only_params self.assertEqual( - prepare_headers(self.auth_only_params, {}), + prepare_headers(request).headers, {u'Authorization': self.norealm_authorization_header}) - self.assertEqual( - prepare_headers(self.auth_only_params, {}, realm=self.realm), - {u'Authorization': self.withrealm_authorization_header}) - def test_prepare_headers_ignore_data(self): + def test_prepare_headers_with_realm(self): + request = Request(u'http://www.google.com/') + request.oauth_params = self.auth_only_params self.assertEqual( - prepare_headers(self.auth_and_data, {}), - {u'Authorization': self.norealm_authorization_header}) - self.assertEqual( - prepare_headers(self.auth_and_data, {}, realm=self.realm), + prepare_headers(request, realm=self.realm).headers, {u'Authorization': self.withrealm_authorization_header}) def test_prepare_form_encoded_body(self): - existing_body = u'' + request = Request(u'http://www.google.com/') + request.oauth_params = self.auth_only_params form_encoded_body = 'data_param_foo=foo&data_param_1=1&oauth_consumer_key=9djdj82h48djs9d2&oauth_token=kkk9d7dh3k39sjv7&oauth_signature_method=HMAC-SHA1&oauth_timestamp=137131201&oauth_nonce=7d8f3e4a&oauth_signature=bYT5CMsGcbgUdFHObYMEfcx6bsw%3D' self.assertEqual( urlencode(prepare_form_encoded_body(self.auth_and_data, existing_body)), form_encoded_body) def test_prepare_request_uri_query(self): - url = u'http://notarealdomain.com/foo/bar/baz?some=args&go=here' - request_uri_query = u'http://notarealdomain.com/foo/bar/baz?some=args&go=here&data_param_foo=foo&data_param_1=1&oauth_consumer_key=9djdj82h48djs9d2&oauth_token=kkk9d7dh3k39sjv7&oauth_signature_method=HMAC-SHA1&oauth_timestamp=137131201&oauth_nonce=7d8f3e4a&oauth_signature=bYT5CMsGcbgUdFHObYMEfcx6bsw%3D' + request = Request(u'http://notarealdomain.com/foo/bar/baz?some=args&go=here') + request.oauth_params = self.auth_only_params + request_uri_query = u'http://notarealdomain.com/foo/bar/baz?some=args&go=here&oauth_consumer_key=9djdj82h48djs9d2&oauth_token=kkk9d7dh3k39sjv7&oauth_signature_method=HMAC-SHA1&oauth_timestamp=137131201&oauth_nonce=7d8f3e4a&oauth_signature=bYT5CMsGcbgUdFHObYMEfcx6bsw%3D' self.assertEqual( - prepare_request_uri_query(self.auth_and_data, url), + prepare_request_uri_query(request).uri, request_uri_query) + |
