diff options
author | Ib Lundgren <ib.lundgren@gmail.com> | 2012-06-27 19:26:05 +0200 |
---|---|---|
committer | Ib Lundgren <ib.lundgren@gmail.com> | 2012-06-27 19:26:05 +0200 |
commit | fad6f859f3f4df691df7bea308d4aba50a78ffec (patch) | |
tree | bef9bc35061f1957269dbc5c206bba98c1958d29 | |
parent | 184db924c5b3f208a3e34432e38a253ab4ed8d6d (diff) | |
download | oauthlib-fad6f859f3f4df691df7bea308d4aba50a78ffec.tar.gz |
Exclude body if not urlencoded
-rw-r--r-- | oauthlib/oauth1/rfc5849/__init__.py | 24 | ||||
-rw-r--r-- | tests/oauth1/rfc5849/test_server.py | 88 |
2 files changed, 60 insertions, 52 deletions
diff --git a/oauthlib/oauth1/rfc5849/__init__.py b/oauthlib/oauth1/rfc5849/__init__.py index d382194..3e518a8 100644 --- a/oauthlib/oauth1/rfc5849/__init__.py +++ b/oauthlib/oauth1/rfc5849/__init__.py @@ -273,7 +273,7 @@ class Server(object): client key or resource owner key is invalid. Instead dummy values should be used during the remaining verification process. It is very important that the dummy client and token are valid input parameters to the methods - get_client_secret, get_rsa_key and get_(access/request)_token_secret and + get_client_secret, get_rsa_key and get_(access/request)_token_secret and that the running time of those methods when given a dummy value remain equivalent to the running time when given a valid client/resource owner. The following properties must be implemented: @@ -506,7 +506,7 @@ class Server(object): def validate_request_token(self, client_key, request_token): """Validates that supplied request token is registered and valid. - Note that if the dummy request_token is supplied it should validate in + Note that if the dummy request_token is supplied it should validate in the same nearly the same amount of time as a valid one. Bad: @@ -526,7 +526,7 @@ class Server(object): def validate_access_token(self, client_key, access_token): """Validates that supplied access token is registered and valid. - Note that if the dummy access token is supplied it should validate in + Note that if the dummy access token is supplied it should validate in the same or nearly the same amount of time as a valid one. Bad: @@ -586,7 +586,7 @@ class Server(object): """ raise NotImplementedError("Subclasses must implement this function.") - def validate_realm(self, client_key, access_token, uri=None, + def validate_realm(self, client_key, access_token, uri=None, required_realm=None): """Validates access to the request realm. @@ -595,7 +595,7 @@ class Server(object): of protected resources such as "photos". required_realm is a convenience parameter which can be used to provide - a per view method pre-defined list of allowed realms. + a per view method pre-defined list of allowed realms. """ raise NotImplementedError("Subclasses must implement this function.") @@ -642,7 +642,13 @@ class Server(object): .. _`Timing attacks`: http://rdist.root.org/2010/07/19/exploiting-remote-timing-attacks/ .. _`enumeration attacks`: http://www.sans.edu/research/security-laboratory/article/attacks-browsing """ - request = Request(uri, http_method, body, headers) + # Only include body data from x-www-form-urlencoded requests + headers = headers or {} + if (u"Content-Type" in headers and + headers[u"Content-Type"] == CONTENT_TYPE_FORM_URLENCODED): + request = Request(uri, http_method, body, headers) + else: + request = Request(uri, http_method, u'', headers) if self.enforce_ssl and not request.uri.lower().startswith("https://"): raise ValueError("Insecure transport, only HTTPS is allowed.") @@ -796,14 +802,14 @@ class Server(object): # # The require_realm indicates this is the first step in the OAuth # workflow where a client requests access to a specific realm. - # + # # Clients obtaining an access token will not supply a realm and it will - # not be checked. Instead the previously requested realm should be + # not be checked. Instead the previously requested realm should be # transferred from the request token to the access token. # # Access to protected resources will always validate the realm but note # that the realm is now tied to the access token and not provided by - # the client. + # the client. if require_realm and not resource_owner_key: valid_realm = self.validate_requested_realm(client_key, realm) elif require_verifier: diff --git a/tests/oauth1/rfc5849/test_server.py b/tests/oauth1/rfc5849/test_server.py index 928ddc4..c253f06 100644 --- a/tests/oauth1/rfc5849/test_server.py +++ b/tests/oauth1/rfc5849/test_server.py @@ -15,9 +15,11 @@ class ServerTests(TestCase): RESOURCE_OWNER_SECRET = u'just-a-string asdasd' RSA_KEY = u"-----BEGIN PRIVATE KEY-----\n MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMOZ519ZczgJiUPI\n J9Oac424LUvJw+HXqB2PqwFxdrcar+FDJihQbuHxGhz7bhhHADPG9KhNH45V5sDI\n /g4USqdd9wys8lAqxQAA9AxV2vXX+HK+id+WOZUfBM78OnzeOdvUzyxgmRean+ps\n A/U+PwsiToeGp0ywFkBCF7VJvd8pAgMBAAECgYBuQDWWHQlAsL9aIVuxfgFcBFAj\n w9pRVglAgFZXPek4VCaGxh6f4pZdbFTXuTDZJkwK4z3MD4yV4f1q9N+ed/mLVsZv\n XJb22jQmnNKhiz/thDWz9f97z+TTSocC85H0zdsUrmRKlxIR6+ys9hpBPe2HSKbJ\n zEcW1IKDkM0acJYm8QJBAP12rHp00IrIdrUsm9rO6dinLZpbGeVu2LFPM0Me7nYO\n Kc/GqrLHTSnm91BDbj9IgFrk45mEcSCCOUYutoKgPy8CQQDFjv9ZHd3BkCSbojG1\n RyRVyJQXfZHGMBabta5jjjTJlO7bMjELSfPsnZxoILjyf06qX/LoqsAXrV0Imf8n\n d/EnAkAcZSUheuC6C4cw+NRlCPUtrlzvg/E8wNRJ2OOXS2nPk/qfKlSJPsaoQRXH\n yiYZtNecVzQgSLQbvjsIX8dWjvlFAkAEuHwFhx8rZuRZC7EgYcjOe/J99TQshi2k\n Ht1B573/Kx3iAvsFCAlaGBIKsu14be5VR+GoCZx5dF0KvZNJQCZ1AkEAuYIpaPLf\n xyvKM8kDJ3uyJ2OHiuVlhMNe8g9GX3hHU4UWx3QdnaVm92mx84iuwRdaB1k6Yhk/\n 9jQrjQ0RmlMjpw==\n -----END PRIVATE KEY-----" - + PUB_RSA_KEY = u"-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDmedfWXM4CYlDyCfTmnONuC1L\nycPh16gdj6sBcXa3Gq/hQyYoUG7h8Roc+24YRwAzxvSoTR+OVebAyP4OFEqnXfcM\nrPJQKsUAAPQMVdr11/hyvonfljmVHwTO/Dp83jnb1M8sYJkXmp/qbAP1Pj8LIk6H\nhqdMsBZAQhe1Sb3fKQIDAQAB\n-----END PUBLIC KEY-----" + URLENCODED = {u"Content-Type": u"application/x-www-form-urlencoded"} + class TestServer(Server): @property @@ -120,19 +122,19 @@ class ServerTests(TestCase): def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, request_token=None, access_token=None): resource_owner_key = request_token if request_token else access_token - return not (client_key, nonce, timestamp, resource_owner_key) in self.nonces + return not (client_key, nonce, timestamp, resource_owner_key) in self.nonces def validate_client_key(self, client_key): return client_key in self.clients def validate_access_token(self, client_key, access_token): - return (self.owners.get(client_key) and + return (self.owners.get(client_key) and access_token in self.owners.get(client_key)) def validate_request_token(self, client_key, request_token): - return (self.owners.get(client_key) and + return (self.owners.get(client_key) and request_token in self.owners.get(client_key)) - + def validate_requested_realm(self, client_key, realm): return True @@ -168,7 +170,7 @@ class ServerTests(TestCase): rsa_key=self.RSA_KEY, resource_owner_key=self.RESOURCE_OWNER_KEY, ) - + s = self.TestServer() uri, headers, body = c.sign(u'http://server.example.com:80/init') @@ -231,7 +233,7 @@ class ServerTests(TestCase): """Ensure params are only supplied once""" s = Server() - self.assertRaises(ValueError, s.verify_request, + self.assertRaises(ValueError, s.verify_request, u'https://a.b/?oauth_version=a&oauth_version=b') self.assertRaises(ValueError, s.verify_request, u'https://a.b/', body=u'oauth_version=a&oauth_version=b') @@ -242,14 +244,14 @@ class ServerTests(TestCase): self.assertRaises(ValueError, s.verify_request, u'https://a.b/') self.assertRaises(ValueError, s.verify_request, u'https://a.b/', body=(u'oauth_signature=a&oauth_consumer_key=b&oauth_nonce')) - + def test_oauth_version(self): """OAuth version must be 1.0 if present.""" s = Server() self.assertRaises(ValueError, s.verify_request, u'https://a.b/', body=(u'oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' u'oauth_timestamp=a&oauth_signature_method=RSA-SHA1&' - u'oauth_version=2.0')) + u'oauth_version=2.0')) def test_oauth_timestamp(self): """Check for a valid UNIX timestamp.""" @@ -259,19 +261,19 @@ class ServerTests(TestCase): self.assertRaises(ValueError, s.verify_request, u'https://a.b/', body=(u'oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' u'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' - u'oauth_timestamp=123456789')) + u'oauth_timestamp=123456789')) # Invalid timestamp age, must be younger than 10 minutes self.assertRaises(ValueError, s.verify_request, u'https://a.b/', body=(u'oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' u'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' - u'oauth_timestamp=1234567890')) + u'oauth_timestamp=1234567890')) # Timestamp must be an integer self.assertRaises(ValueError, s.verify_request, u'https://a.b/', body=(u'oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' u'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' - u'oauth_timestamp=123456789a')) + u'oauth_timestamp=123456789a')) def test_signature_method_validation(self): """Ensure valid signature method is used.""" @@ -279,46 +281,46 @@ class ServerTests(TestCase): body=(u'oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' u'oauth_version=1.0&oauth_signature_method=%s&' u'oauth_timestamp=1234567890') - + uri = u'https://example.com/' class HMACServer(Server): - + @property def allowed_signature_methods(self): return (SIGNATURE_HMAC,) s = HMACServer() - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'RSA-SHA1') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'PLAINTEXT') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'shibboleth') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'RSA-SHA1') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'PLAINTEXT') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'shibboleth') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'') class RSAServer(Server): - + @property def allowed_signature_methods(self): return (SIGNATURE_RSA,) s = RSAServer() - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'HMAC-SHA1') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'PLAINTEXT') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'shibboleth') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'HMAC-SHA1') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'PLAINTEXT') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'shibboleth') class PlainServer(Server): - + @property def allowed_signature_methods(self): return (SIGNATURE_PLAINTEXT,) s = PlainServer() - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'HMAC-SHA1') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'RSA-SHA1') - self.assertRaises(ValueError, s.verify_request, uri, body=body % u'shibboleth') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'HMAC-SHA1') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'RSA-SHA1') + self.assertRaises(ValueError, s.verify_request, uri, body=body % u'shibboleth') def test_check_methods(self): """Ensure values are correctly formatted. - + Default setting is to only allow alphanumeric characters and a length between 20 and 30 characters. """ @@ -329,7 +331,7 @@ class ServerTests(TestCase): u'oauth_version=1.0&oauth_signature_method=HMAC-SHA1&' u'oauth_token=abcdefghijklmnopqrstuvxyz&' u'oauth_consumer_key=%s') - + owner=(u'oauth_signature=a&oauth_timestamp=%s&' u'oauth_nonce=abcdefghijklmnopqrstuvwxyz&' u'oauth_version=1.0&oauth_signature_method=HMAC-SHA1&' @@ -376,11 +378,11 @@ class ServerTests(TestCase): # Too long loong = (ts, u'abcdefghijklmnopqrstuvwxyz123456789') - self.assertRaises(ValueError, s.verify_request, uri, body=client % loong) - self.assertRaises(ValueError, s.verify_request, uri, body=owner % loong) - self.assertRaises(ValueError, s.verify_request, uri, body=nonce % loong) + self.assertRaises(ValueError, s.verify_request, uri, body=client % loong) + self.assertRaises(ValueError, s.verify_request, uri, body=owner % loong) + self.assertRaises(ValueError, s.verify_request, uri, body=nonce % loong) self.assertRaises(ValueError, s.verify_request, uri, body=verifier % loong, - require_verifier=True) + require_verifier=True) # By default no realms are allowed test = (ts, u'shibboleth') @@ -388,7 +390,7 @@ class ServerTests(TestCase): require_realm=True) # Missing required owner - self.assertRaises(ValueError, s.verify_request, uri, body=owner % (ts, u'')) + self.assertRaises(ValueError, s.verify_request, uri, body=owner % (ts, u'')) # Missing required verifier self.assertRaises(ValueError, s.verify_request, uri, body=realm % test, @@ -404,8 +406,8 @@ class ServerTests(TestCase): u'oauth_consumer_key={0}') s = self.ClientServer() - self.assertFalse(s.verify_request(uri, body=client.format(u'bar'))) - self.assertTrue(s.verify_request(uri, body=client.format(u'foo'))) + self.assertFalse(s.verify_request(uri, headers=self.URLENCODED, body=client.format(u'bar'))) + self.assertTrue(s.verify_request(uri, headers=self.URLENCODED, body=client.format(u'foo'))) def test_nonce_and_timestamp_validation(self): uri = u'https://example.com/' @@ -417,7 +419,7 @@ class ServerTests(TestCase): u'oauth_consumer_key=foo') s = self.ClientServer() - self.assertFalse(s.verify_request(uri, body=replay)) + self.assertFalse(s.verify_request(uri, headers=self.URLENCODED, body=replay)) def test_resource_owner_validation(self): uri = u'https://example.com/' @@ -430,7 +432,7 @@ class ServerTests(TestCase): u'oauth_consumer_key=foo') s = self.ClientServer() - self.assertFalse(s.verify_request(uri, body=invalid_owner)) + self.assertFalse(s.verify_request(uri, headers=self.URLENCODED, body=invalid_owner)) def test_signature_verification(self): uri = u'https://example.com/' @@ -449,8 +451,8 @@ class ServerTests(TestCase): u'oauth_consumer_key=foo') s = self.ClientServer() - self.assertFalse(s.verify_request(uri, body=short_sig)) - self.assertFalse(s.verify_request(uri, body=plain)) + self.assertFalse(s.verify_request(uri, headers=self.URLENCODED, body=short_sig)) + self.assertFalse(s.verify_request(uri, headers=self.URLENCODED, body=plain)) def test_realm_validation(self): uri = u'https://example.com/' @@ -462,9 +464,9 @@ class ServerTests(TestCase): u'oauth_consumer_key=foo&realm=photos') s = self.ClientServer() - self.assertTrue(s.verify_request(uri, body=realm)) + self.assertTrue(s.verify_request(uri, headers=self.URLENCODED, body=realm)) - def test_verifier_validation(self): + def test_verifier_validation(self): uri = u'https://example.com/' verifier = (u'oauth_signature=6AsWnRg%2BZnvfJOZKgaC5JKrF3Pk%3D&' u'oauth_timestamp=1234567890&' @@ -475,8 +477,8 @@ class ServerTests(TestCase): s = self.ClientServer() self.assertTrue(s.verify_request(uri, body=verifier, - require_verifier=True)) - + headers=self.URLENCODED, require_verifier=True)) + def test_timing_attack(self): """Ensure near constant time verification.""" # TODO: |