diff options
-rw-r--r-- | oauthlib/oauth1/rfc5849/__init__.py | 10 | ||||
-rw-r--r-- | oauthlib/oauth1/rfc5849/signature.py | 35 | ||||
-rw-r--r-- | tests/oauth1/rfc5849/test_client.py | 6 | ||||
-rw-r--r-- | tests/oauth1/rfc5849/test_signatures.py | 20 |
4 files changed, 63 insertions, 8 deletions
diff --git a/oauthlib/oauth1/rfc5849/__init__.py b/oauthlib/oauth1/rfc5849/__init__.py index c7c7f20..974777e 100644 --- a/oauthlib/oauth1/rfc5849/__init__.py +++ b/oauthlib/oauth1/rfc5849/__init__.py @@ -97,6 +97,13 @@ class Client(object): def get_oauth_signature(self, request): """Get an OAuth signature to be used in signing a request + + To satisfy `section 3.4.1.2`_ item 2, if the request argument's + headers dict attribute contains a Host item, its value will + replace any netloc part of the request argument's uri attribute + value. + + .. _`section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 """ if self.signature_method == SIGNATURE_PLAINTEXT: # fast-path @@ -112,7 +119,8 @@ class Client(object): log.debug("Collected params: {0}".format(collected_params)) normalized_params = signature.normalize_parameters(collected_params) - normalized_uri = signature.normalize_base_string_uri(request.uri) + normalized_uri = signature.normalize_base_string_uri(uri, + headers.get('Host', None)) log.debug("Normalized params: {0}".format(normalized_params)) log.debug("Normalized URI: {0}".format(normalized_uri)) diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py index d9d11a8..677865c 100644 --- a/oauthlib/oauth1/rfc5849/signature.py +++ b/oauthlib/oauth1/rfc5849/signature.py @@ -99,7 +99,7 @@ def construct_base_string(http_method, base_string_uri, return base_string -def normalize_base_string_uri(uri): +def normalize_base_string_uri(uri, host=None): """**Base String URI** Per `section 3.4.1.2`_ of the spec. @@ -118,6 +118,8 @@ def normalize_base_string_uri(uri): is represented by the base string URI: "https://www.example.net:8080/". .. _`section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 + + The host argument overrides the netloc part of the uri argument. """ if not isinstance(uri, unicode_type): raise ValueError('uri must be a unicode object.') @@ -131,13 +133,26 @@ def normalize_base_string_uri(uri): # # .. _`RFC2616`: http://tools.ietf.org/html/rfc3986 + if not scheme: + raise ValueError('uri must include a scheme') + + # Per `RFC 2616 section 5.1.2`_: + # + # Note that the absolute path cannot be empty; if none is present in + # the original URI, it MUST be given as "/" (the server root). + # + # .. _`RFC 2616 section 5.1.2`: http://tools.ietf.org/html/rfc2616#section-5.1.2 + if not path: + path = '/' + # 1. The scheme and host MUST be in lowercase. scheme = scheme.lower() netloc = netloc.lower() # 2. The host and port values MUST match the content of the HTTP # request "Host" header field. - # TODO: enforce this constraint + if host is not None: + netloc = host.lower() # 3. The port MUST be included if it is not the default port for the # scheme, and MUST be excluded if it is the default. Specifically, @@ -514,6 +529,15 @@ def verify_hmac_sha1(request, client_secret=None, Per `section 3.4`_ of the spec. .. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 + + To satisfy `RFC2616 section 5.2`_ item 1, the request argument's uri + attribute MUST be an absolute URI whose netloc part identifies the + origin server or gateway on which the resource resides. Any Host + item of the request argument's headers dict attribute will be + ignored. + + .. _`RFC2616 section 5.2`: http://tools.ietf.org/html/rfc2616#section-5.2 + """ norm_params = normalize_parameters(request.params) uri = normalize_base_string_uri(request.uri) @@ -532,6 +556,13 @@ def verify_rsa_sha1(request, rsa_public_key): .. _`section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 + To satisfy `RFC2616 section 5.2`_ item 1, the request argument's uri + attribute MUST be an absolute URI whose netloc part identifies the + origin server or gateway on which the resource resides. Any Host + item of the request argument's headers dict attribute will be + ignored. + + .. _`RFC2616 section 5.2`: http://tools.ietf.org/html/rfc2616#section-5.2 """ from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 diff --git a/tests/oauth1/rfc5849/test_client.py b/tests/oauth1/rfc5849/test_client.py index 6b3dc8a..7716369 100644 --- a/tests/oauth1/rfc5849/test_client.py +++ b/tests/oauth1/rfc5849/test_client.py @@ -9,20 +9,20 @@ class ClientRealmTests(TestCase): def test_client_no_realm(self): client = Client("client-key") - uri, header, body = client.sign("example-uri") + uri, header, body = client.sign("http://example-uri") self.assertTrue( header["Authorization"].startswith('OAuth oauth_nonce=')) def test_client_realm_sign_with_default_realm(self): client = Client("client-key", realm="moo-realm") self.assertEqual(client.realm, "moo-realm") - uri, header, body = client.sign("example-uri") + uri, header, body = client.sign("http://example-uri") self.assertTrue( header["Authorization"].startswith('OAuth realm="moo-realm",')) def test_client_realm_sign_with_additional_realm(self): client = Client("client-key", realm="moo-realm") - uri, header, body = client.sign("example-uri", realm="baa-realm") + uri, header, body = client.sign("http://example-uri", realm="baa-realm") self.assertTrue( header["Authorization"].startswith('OAuth realm="baa-realm",')) # make sure sign() does not override the default realm diff --git a/tests/oauth1/rfc5849/test_signatures.py b/tests/oauth1/rfc5849/test_signatures.py index 8d4ce85..4abf914 100644 --- a/tests/oauth1/rfc5849/test_signatures.py +++ b/tests/oauth1/rfc5849/test_signatures.py @@ -83,8 +83,24 @@ class SignatureTests(TestCase): uri = b"www.example.com:8080" self.assertRaises(ValueError, normalize_base_string_uri, uri) - uri = "http://www.example.com:80" - self.assertEquals(normalize_base_string_uri(uri), "http://www.example.com") + # test a URI with the default port + uri = "http://www.example.com:80/" + self.assertEquals(normalize_base_string_uri(uri), "http://www.example.com/") + + # test a URI missing a path + uri = "http://www.example.com" + self.assertEquals(normalize_base_string_uri(uri), "http://www.example.com/") + + # test a relative URI + uri = "/a-host-relative-uri" + host = "www.example.com" + self.assertRaises(ValueError, normalize_base_string_uri, (uri, host)) + + # test overriding the URI's netloc with a host argument + uri = "http://www.example.com/a-path" + host = "alternatehost.example.com" + self.assertEquals(normalize_base_string_uri(uri, host), + "http://alternatehost.example.com/a-path") def test_collect_parameters(self): """ We check against parameters multiple times in case things change after more |