summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIb Lundgren <ib.lundgren@gmail.com>2013-05-05 09:25:09 -0700
committerIb Lundgren <ib.lundgren@gmail.com>2013-05-05 09:25:09 -0700
commit87a6602c7abc0557519d72c8758afff7069985da (patch)
treedbedf9b4a97bc24c2f74f55630b0b0d933898e4e
parent83b353eafabcb8ad130278464128583028ebdbc9 (diff)
parent4a7130d9c0c5097b2b218bafcde4667ca559111f (diff)
downloadoauthlib-87a6602c7abc0557519d72c8758afff7069985da.tar.gz
Merge pull request #143 from matthewlmcclure/idan/142
Fix defect in choice of authority for signature base string
-rw-r--r--oauthlib/oauth1/rfc5849/__init__.py10
-rw-r--r--oauthlib/oauth1/rfc5849/signature.py35
-rw-r--r--tests/oauth1/rfc5849/test_client.py6
-rw-r--r--tests/oauth1/rfc5849/test_signatures.py20
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