def test_sign_unicode(self): client = Client('client_key', nonce='abc', timestamp='abc') _, h, b = client.sign('http://i.b/path', http_method='POST', body='status=%E5%95%A6%E5%95%A6', headers={'Content-Type': 'application/x-www-form-urlencoded'}) self.assertEqual(b, 'status=%E5%95%A6%E5%95%A6') self.assertIn('oauth_signature="yrtSqp88m%2Fc5UDaucI8BXK4oEtk%3D"', h['Authorization']) _, h, b = client.sign('http://i.b/path', http_method='POST', body='status=%C3%A6%C3%A5%C3%B8', headers={'Content-Type': 'application/x-www-form-urlencoded'}) self.assertEqual(b, 'status=%C3%A6%C3%A5%C3%B8') self.assertIn('oauth_signature="oG5t3Eg%2FXO5FfQgUUlTtUeeZzvk%3D"', h['Authorization'])
def test_client_realm_sign_with_additional_realm(self): client = Client("client-key", realm="moo-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 self.assertEqual(client.realm, "moo-realm")
def get_access_token(request_token, request_token_secret, access_token_url, access_token_method, public_key, secret_key, verifier): """ Returns access token and access token secret """ c = Client(public_key, secret_key, resource_owner_key=request_token, resource_owner_secret=request_token_secret, signature_type=SIGNATURE_TYPE_QUERY, verifier=verifier ) uri, headers, body = c.sign(uri=access_token_url, http_method=access_token_method) http = httplib2.Http() response, content = httplib2.Http.request(http, uri, method=access_token_method, body=body, headers=headers) if response.get('status') != '200': raise Exception("Invalid access token response: %s." % content) tokens = dict(urlparse.parse_qsl(content)) access_token = tokens.get('oauth_token') access_token_secret = tokens.get('oauth_token_secret') return access_token, access_token_secret
def test_can_load_consumer_secret_from_settings(self): lti = Client( client_key=OTHER_LTI_CONSUMER_KEY, client_secret=OTHER_LTI_CONSUMER_SECRET, signature_type=SIGNATURE_TYPE_BODY, ) (uri, _headers, body) = lti.sign( uri=self.url_prefix + LTI_TPA_LOGIN_URL, http_method='POST', headers={'Content-Type': FORM_ENCODED}, body={ 'user_id': LTI_USER_ID, 'custom_tpa_next': '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll', } ) with self.settings(SOCIAL_AUTH_LTI_CONSUMER_SECRETS={OTHER_LTI_CONSUMER_KEY: OTHER_LTI_CONSUMER_SECRET}): login_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body) # The user should be redirected to the registration form self.assertEqual(login_response.status_code, 302) self.assertTrue(login_response['Location'].endswith(reverse('signin_user'))) register_response = self.client.get(login_response['Location']) self.assertEqual(register_response.status_code, 200) self.assertIn( '"currentProvider": "Tool Consumer with Secret in Settings"', register_response.content ) self.assertIn('"errorMessage": null', register_response.content)
class OAuth1(AuthBase): """Signs the request using OAuth 1 (RFC5849)""" def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None): try: signature_type = signature_type.upper() except AttributeError: pass self.client = Client(client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier) def __call__(self, r): contenttype = r.headers.get('Content-Type', None) decoded_body = extract_params(r.data) if contenttype == None and decoded_body != None: r.headers['Content-Type'] = 'application/x-www-form-urlencoded' r.url, r.headers, r.data = self.client.sign( unicode(r.url), unicode(r.method), r.data, r.headers) return r
def test_check_redirect_uri(self): client = Client('foo') uri, headers, _ = client.sign(self.uri) h, b, s = self.endpoint.create_request_token_response( uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b)
def get_request_token(public_key, secret_key, url, method=u'POST'): ''' :param public_key: :param secret_key: :param url: :param method: ''' c = Client( unicode(public_key), unicode(secret_key), signature_type=SIGNATURE_TYPE_QUERY ) uri, headers, body = c.sign( uri=url, http_method=method) http = httplib2.Http() response, content = httplib2.Http.request(http, uri, method=method, body=body, headers=headers ) if response.get('status') != '200': raise Exception("Invalid request token response: %s." % content) tokens = dict(urlparse.parse_qsl(content)) token = tokens.get('oauth_token') token_secret = tokens.get('oauth_token_secret') return unicode(token), unicode(token_secret)
def test_rsa_method(self): private_key = ( "-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQDk1/bxy" "S8Q8jiheHeYYp/4rEKJopeQRRKKpZI4s5i+UPwVpupG\nAlwXWfzXw" "SMaKPAoKJNdu7tqKRniqst5uoHXw98gj0x7zamu0Ck1LtQ4c7pFMVa" "h\n5IYGhBi2E9ycNS329W27nJPWNCbESTu7snVlG8V8mfvGGg3xNjT" "MO7IdrwIDAQAB\nAoGBAOQ2KuH8S5+OrsL4K+wfjoCi6MfxCUyqVU9" "GxocdM1m30WyWRFMEz2nKJ8fR\np3vTD4w8yplTOhcoXdQZl0kRoaD" "zrcYkm2VvJtQRrX7dKFT8dR8D/Tr7dNQLOXfC\nDY6xveQczE7qt7V" "k7lp4FqmxBsaaEuokt78pOOjywZoInjZhAkEA9wz3zoZNT0/i\nrf6" "qv2qTIeieUB035N3dyw6f1BGSWYaXSuerDCD/J1qZbAPKKhyHZbVaw" "Ft3UMhe\n542UftBaxQJBAO0iJy1I8GQjGnS7B3yvyH3CcLYGy296+" "XO/2xKp/d/ty1OIeovx\nC60pLNwuFNF3z9d2GVQAdoQ89hUkOtjZL" "eMCQQD0JO6oPHUeUjYT+T7ImAv7UKVT\nSuy30sKjLzqoGw1kR+wv7" "C5PeDRvscs4wa4CW9s6mjSrMDkDrmCLuJDtmf55AkEA\nkmaMg2PNr" "jUR51F0zOEFycaaqXbGcFwe1/xx9zLmHzMDXd4bsnwt9kk+fe0hQzV" "S\nJzatanQit3+feev1PN3QewJAWv4RZeavEUhKv+kLe95Yd0su7lT" "LVduVgh4v5yLT\nGa6FHdjGPcfajt+nrpB1n8UQBEH9ZxniokR/IPv" "dMlxqXA==\n-----END RSA PRIVATE KEY-----" ) client = Client('client_key', signature_method=SIGNATURE_RSA, rsa_key=private_key, timestamp='1234567890', nonce='abc') u, h, b = client.sign('http://example.com') correct = ('OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="RSA-SHA1", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="ktvzkUhtrIawBcq21DRJrAyysTc3E1Zq5GdGu8EzH' 'OtbeaCmOBDLGHAcqlm92mj7xp5E1Z6i2vbExPimYAJL7FzkLnkRE5YEJR4' 'rNtIgAf1OZbYsIUmmBO%2BCLuStuu5Lg3tAluwC7XkkgoXCBaRKT1mUXzP' 'HJILzZ8iFOvS6w5E%3D"') self.assertEqual(h['Authorization'], correct)
def test_uri_provided_realm(self): client = Client("foo", callback_uri="https://c.b/cb", client_secret="bar") uri = self.uri + "?realm=foo" _, headers, _ = client.sign(uri) u, h, b, s = self.endpoint.create_request_token_response(uri, headers=headers) self.assertEqual(s, 200) self.assertIn("oauth_token", b)
def test_hmac_sha1_method(self): client = Client('client_key', timestamp='1234567890', nonce='abc') u, h, b = client.sign('http://example.com') correct = ('OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="HMAC-SHA1", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="hH5BWYVqo7QI4EmPBUUe9owRUUQ%3D"') self.assertEqual(h['Authorization'], correct)
def test_validate_signature(self): client = Client('foo', resource_owner_key='token', resource_owner_secret='secret') _, headers, _ = client.sign(self.uri + '/extra') v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=headers) self.assertFalse(v)
def test_hmac_sha256_method(self): client = Client('client_key', signature_method=SIGNATURE_HMAC_SHA256, timestamp='1234567890', nonce='abc') u, h, b = client.sign('http://example.com') correct = ('OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="HMAC-SHA256", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="JzgJWBxX664OiMW3WE4MEjtYwOjI%2FpaUWHqtdHe68Es%3D"') self.assertEqual(h['Authorization'], correct)
def test_uri_provided_realm(self): client = Client('foo', callback_uri='https://c.b/cb', client_secret='bar') uri = self.uri + '?realm=foo' _, headers, _ = client.sign(uri) h, b, s = self.endpoint.create_request_token_response( uri, headers=headers) self.assertEqual(s, 200) self.assertIn('oauth_token', b)
def test_validate_signature(self): client = Client('foo', resource_owner_key='token', resource_owner_secret='secret', verifier='verfier') _, headers, _ = client.sign(self.uri + '/extra') h, b, s = self.endpoint.create_access_token_response( self.uri, headers=headers) self.assertEqual(s, 401)
def test_decoding(self): client = Client('client_key', decoding='utf-8') uri, headers, body = client.sign('http://a.b/path?query', body='a=b', headers={'Content-Type': 'application/x-www-form-urlencoded'}) self.assertIsInstance(uri, bytes_type) self.assertIsInstance(body, bytes_type) for k, v in headers.items(): self.assertIsInstance(k, bytes_type) self.assertIsInstance(v, bytes_type)
def test_sign_unicode(self): client = Client("client_key", nonce="abc", timestamp="abc") _, h, b = client.sign( "http://i.b/path", http_method="POST", body="status=%E5%95%A6%E5%95%A6", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) self.assertEqual(b, "status=%E5%95%A6%E5%95%A6") self.assertIn('oauth_signature="yrtSqp88m%2Fc5UDaucI8BXK4oEtk%3D"', h["Authorization"]) _, h, b = client.sign( "http://i.b/path", http_method="POST", body="status=%C3%A6%C3%A5%C3%B8", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) self.assertEqual(b, "status=%C3%A6%C3%A5%C3%B8") self.assertIn('oauth_signature="oG5t3Eg%2FXO5FfQgUUlTtUeeZzvk%3D"', h["Authorization"])
def test_sign_body(self): client = Client("client_key") _, h, b = client.sign( "http://i.b/path", http_method="POST", body="", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) self.assertEqual(h["Content-Type"], "application/x-www-form-urlencoded")
def test_params_in_query(self): client = Client('client_key', signature_type=SIGNATURE_TYPE_QUERY, timestamp='1378988215', nonce='14205877133089081931378988215') u, _, _ = client.sign('http://i.b/path', http_method='POST') correct = ('http://i.b/path?oauth_nonce=14205877133089081931378988215&' 'oauth_timestamp=1378988215&' 'oauth_version=1.0&' 'oauth_signature_method=HMAC-SHA1&' 'oauth_consumer_key=client_key&' 'oauth_signature=08G5Snvw%2BgDAzBF%2BCmT5KqlrPKo%3D') self.assertEqual(u, correct)
def test_case_insensitive_headers(self): client = Client('client_key') # Uppercase _, h, _ = client.sign('http://i.b/path', http_method='POST', body='', headers={'Content-Type': 'application/x-www-form-urlencoded'}) self.assertEqual(h['Content-Type'], 'application/x-www-form-urlencoded') # Lowercase _, h, _ = client.sign('http://i.b/path', http_method='POST', body='', headers={'content-type': 'application/x-www-form-urlencoded'}) self.assertEqual(h['content-type'], 'application/x-www-form-urlencoded') # Capitalized _, h, _ = client.sign('http://i.b/path', http_method='POST', body='', headers={'Content-type': 'application/x-www-form-urlencoded'}) self.assertEqual(h['Content-type'], 'application/x-www-form-urlencoded') # Random _, h, _ = client.sign('http://i.b/path', http_method='POST', body='', headers={'conTent-tYpe': 'application/x-www-form-urlencoded'}) self.assertEqual(h['conTent-tYpe'], 'application/x-www-form-urlencoded')
def test_decoding(self): client = Client("client_key", decoding="utf-8") uri, headers, body = client.sign( "http://a.b/path?query", http_method="POST", body="a=b", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) self.assertIsInstance(uri, bytes_type) self.assertIsInstance(body, bytes_type) for k, v in headers.items(): self.assertIsInstance(k, bytes_type) self.assertIsInstance(v, bytes_type)
def test_validate_signature(self): client = Client('foo', resource_owner_key='token', resource_owner_secret='secret') _, headers, _ = client.sign(self.uri + '/extra') v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=headers) self.assertFalse(v) # the validator log should have `False` values self.assertTrue(r.validator_log['client']) self.assertTrue(r.validator_log['realm']) self.assertTrue(r.validator_log['resource_owner']) self.assertFalse(r.validator_log['signature'])
def test_plaintext_method(self): client = Client('client_key', signature_method=SIGNATURE_PLAINTEXT, timestamp='1234567890', nonce='abc', client_secret='foo', resource_owner_secret='bar') u, h, b = client.sign('http://example.com') correct = ('OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="PLAINTEXT", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="foo%26bar"') self.assertEqual(h['Authorization'], correct)
def test_params_in_body(self): client = Client('client_key', signature_type=SIGNATURE_TYPE_BODY, timestamp='1378988215', nonce='14205877133089081931378988215') _, h, b = client.sign('http://i.b/path', http_method='POST', body='a=b', headers={'Content-Type': 'application/x-www-form-urlencoded'}) self.assertEqual(h['Content-Type'], 'application/x-www-form-urlencoded') correct = ('a=b&oauth_nonce=14205877133089081931378988215&' 'oauth_timestamp=1378988215&' 'oauth_version=1.0&' 'oauth_signature_method=HMAC-SHA1&' 'oauth_consumer_key=client_key&' 'oauth_signature=2JAQomgbShqoscqKWBiYQZwWq94%3D') self.assertEqual(b, correct)
def test_case_insensitive_headers(self): client = Client("client_key") # Uppercase _, h, _ = client.sign( "http://i.b/path", http_method="POST", body="", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) self.assertEqual(h["Content-Type"], "application/x-www-form-urlencoded") # Lowercase _, h, _ = client.sign( "http://i.b/path", http_method="POST", body="", headers={"content-type": "application/x-www-form-urlencoded"}, ) self.assertEqual(h["content-type"], "application/x-www-form-urlencoded") # Capitalized _, h, _ = client.sign( "http://i.b/path", http_method="POST", body="", headers={"Content-type": "application/x-www-form-urlencoded"}, ) self.assertEqual(h["Content-type"], "application/x-www-form-urlencoded") # Random _, h, _ = client.sign( "http://i.b/path", http_method="POST", body="", headers={"conTent-tYpe": "application/x-www-form-urlencoded"}, ) self.assertEqual(h["conTent-tYpe"], "application/x-www-form-urlencoded")
def test_plaintext_method(self): client = Client( "client_key", signature_method=SIGNATURE_PLAINTEXT, timestamp="1234567890", nonce="abc", client_secret="foo", resource_owner_secret="bar", ) u, h, b = client.sign("http://example.com") correct = ( 'OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="PLAINTEXT", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="foo%26bar"' ) self.assertEqual(h["Authorization"], correct)
def test_register_method(self): Client.register_signature_method('PIZZA', lambda base_string, client: 'PIZZA') self.assertTrue('PIZZA' in Client.SIGNATURE_METHODS) client = Client('client_key', signature_method='PIZZA', timestamp='1234567890', nonce='abc') u, h, b = client.sign('http://example.com') self.assertEqual(h['Authorization'], ( 'OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="PIZZA", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="PIZZA"' ))
def test_params_in_query(self): client = Client( "client_key", signature_type=SIGNATURE_TYPE_QUERY, timestamp="1378988215", nonce="14205877133089081931378988215", ) u, _, _ = client.sign("http://i.b/path", http_method="POST") correct = ( "http://i.b/path?oauth_nonce=14205877133089081931378988215&" "oauth_timestamp=1378988215&" "oauth_version=1.0&" "oauth_signature_method=HMAC-SHA1&" "oauth_consumer_key=client_key&" "oauth_signature=08G5Snvw%2BgDAzBF%2BCmT5KqlrPKo%3D" ) self.assertEqual(u, correct)
def test_register_method(self): Client.register_signature_method("PIZZA", lambda base_string, client: "PIZZA") self.assertTrue("PIZZA" in Client.SIGNATURE_METHODS) client = Client("client_key", signature_method="PIZZA", timestamp="1234567890", nonce="abc") u, h, b = client.sign("http://example.com") self.assertEquals( h["Authorization"], ( 'OAuth oauth_nonce="abc", oauth_timestamp="1234567890", ' 'oauth_version="1.0", oauth_signature_method="PIZZA", ' 'oauth_consumer_key="client_key", ' 'oauth_signature="PIZZA"' ), )
class SignatureOnlyEndpointTest(TestCase): def setUp(self): self.validator = MagicMock(wraps=RequestValidator()) self.validator.check_client_key.return_value = True self.validator.allowed_signature_methods = ['HMAC-SHA1'] self.validator.get_client_secret.return_value = 'bar' self.validator.timestamp_lifetime = 600 self.validator.validate_client_key.return_value = True self.validator.validate_timestamp_and_nonce.return_value = True self.validator.dummy_client = 'dummy' self.validator.dummy_secret = 'dummy' self.endpoint = SignatureOnlyEndpoint(self.validator) self.client = Client('foo', client_secret='bar') self.uri, self.headers, self.body = self.client.sign( 'https://i.b/protected_resource') def test_missing_parameters(self): v, r = self.endpoint.validate_request( self.uri) self.assertFalse(v) def test_validate_client_key(self): self.validator.validate_client_key.return_value = False v, r = self.endpoint.validate_request( self.uri, headers=self.headers) self.assertFalse(v) def test_validate_signature(self): client = Client('foo') _, headers, _ = client.sign(self.uri + '/extra') v, r = self.endpoint.validate_request( self.uri, headers=headers) self.assertFalse(v) def test_valid_request(self): v, r = self.endpoint.validate_request( self.uri, headers=self.headers) self.assertTrue(v) self.validator.validate_timestamp_and_nonce.assert_called_once_with( self.client.client_key, ANY, ANY, ANY)
def test_params_in_body(self): client = Client( "client_key", signature_type=SIGNATURE_TYPE_BODY, timestamp="1378988215", nonce="14205877133089081931378988215", ) _, h, b = client.sign( "http://i.b/path", http_method="POST", body="a=b", headers={"Content-Type": "application/x-www-form-urlencoded"}, ) self.assertEqual(h["Content-Type"], "application/x-www-form-urlencoded") correct = ( "a=b&oauth_nonce=14205877133089081931378988215&" "oauth_timestamp=1378988215&" "oauth_version=1.0&" "oauth_signature_method=HMAC-SHA1&" "oauth_consumer_key=client_key&" "oauth_signature=2JAQomgbShqoscqKWBiYQZwWq94%3D" ) self.assertEqual(b, correct)
def test_sign_body(self): client = Client('client_key') _, h, b = client.sign('http://i.b/path', http_method='POST', body='', headers={'Content-Type': 'application/x-www-form-urlencoded'}) self.assertEqual(h['Content-Type'], 'application/x-www-form-urlencoded')
class ResourceEndpointTest(TestCase): def setUp(self): self.validator = MagicMock(wraps=RequestValidator()) self.validator.check_client_key.return_value = True self.validator.check_access_token.return_value = True self.validator.allowed_signature_methods = ['HMAC-SHA1'] self.validator.get_client_secret.return_value = 'bar' self.validator.get_access_token_secret.return_value = 'secret' self.validator.timestamp_lifetime = 600 self.validator.validate_client_key.return_value = True self.validator.validate_access_token.return_value = True self.validator.validate_timestamp_and_nonce.return_value = True self.validator.validate_realms.return_value = True self.validator.dummy_client = 'dummy' self.validator.dummy_secret = 'dummy' self.validator.dummy_access_token = 'dummy' self.endpoint = ResourceEndpoint(self.validator) self.client = Client('foo', client_secret='bar', resource_owner_key='token', resource_owner_secret='secret') self.uri, self.headers, self.body = self.client.sign( 'https://i.b/protected_resource') def test_missing_parameters(self): self.validator.check_access_token.return_value = False v, r = self.endpoint.validate_protected_resource_request(self.uri) self.assertFalse(v) def test_check_access_token(self): self.validator.check_access_token.return_value = False v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=self.headers) self.assertFalse(v) def test_validate_client_key(self): self.validator.validate_client_key.return_value = False v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=self.headers) self.assertFalse(v) # the validator log should have `False` values self.assertFalse(r.validator_log['client']) self.assertTrue(r.validator_log['realm']) self.assertTrue(r.validator_log['resource_owner']) self.assertTrue(r.validator_log['signature']) def test_validate_access_token(self): self.validator.validate_access_token.return_value = False v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=self.headers) self.assertFalse(v) # the validator log should have `False` values self.assertTrue(r.validator_log['client']) self.assertTrue(r.validator_log['realm']) self.assertFalse(r.validator_log['resource_owner']) self.assertTrue(r.validator_log['signature']) def test_validate_realms(self): self.validator.validate_realms.return_value = False v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=self.headers) self.assertFalse(v) # the validator log should have `False` values self.assertTrue(r.validator_log['client']) self.assertFalse(r.validator_log['realm']) self.assertTrue(r.validator_log['resource_owner']) self.assertTrue(r.validator_log['signature']) def test_validate_signature(self): client = Client('foo', resource_owner_key='token', resource_owner_secret='secret') _, headers, _ = client.sign(self.uri + '/extra') v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=headers) self.assertFalse(v) # the validator log should have `False` values self.assertTrue(r.validator_log['client']) self.assertTrue(r.validator_log['realm']) self.assertTrue(r.validator_log['resource_owner']) self.assertFalse(r.validator_log['signature']) def test_valid_request(self): v, r = self.endpoint.validate_protected_resource_request( self.uri, headers=self.headers) self.assertTrue(v) self.validator.validate_timestamp_and_nonce.assert_called_once_with( self.client.client_key, ANY, ANY, ANY, access_token=self.client.resource_owner_key) # everything in the validator_log should be `True` self.assertTrue(all(r.validator_log.items()))
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("http://example-uri") self.assertTrue( header["Authorization"].startswith('OAuth realm="moo-realm",'))
class OAuth1(AuthBase): """Signs the request using OAuth 1 (RFC5849)""" def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None): try: signature_type = signature_type.upper() except AttributeError: pass self.client = Client(client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier) def __call__(self, r): """Add OAuth parameters to the request. Parameters may be included from the body if the content-type is urlencoded, if no content type is set an educated guess is made. """ contenttype = r.headers.get('Content-Type', None) # extract_params will not give params unless the body is a properly # formatted string, a dictionary or a list of 2-tuples. decoded_body = extract_params(r.data) if contenttype == None and decoded_body != None: # extract_params can only check the present r.data and does not know # of r.files, thus an extra check is performed. We know that # if files are present the request will not have # Content-type: x-www-form-urlencoded. We guess it will have # a mimetype of multipart/form-encoded and if this is not the case # we assume the correct header will be set later. if r.files: # Omit body data in the signing and since it will always # be empty (cant add paras to body if multipart) and we wish # to preserve body. r.headers['Content-Type'] = 'multipart/form-encoded' r.url, r.headers, _ = self.client.sign(unicode(r.url), unicode(r.method), None, r.headers) else: # Normal signing r.headers['Content-Type'] = 'application/x-www-form-urlencoded' r.url, r.headers, r.data = self.client.sign( unicode(r.url), unicode(r.method), r.data, r.headers) # Having the authorization header, key or value, in unicode will # result in UnicodeDecodeErrors when the request is concatenated # by httplib. This can easily be seen when attaching files. # Note that simply encoding the value is not enough since Python # saves the type of first key set. Thus we remove and re-add. # >>> d = {u'a':u'foo'} # >>> d['a'] = 'foo' # >>> d # { u'a' : 'foo' } u_header = unicode('Authorization') if u_header in r.headers: auth_header = r.headers[u_header].encode('utf-8') del r.headers[u_header] r.headers['Authorization'] = auth_header return r
def test_validate_signature(self): client = Client('foo', callback_uri='https://c.b/cb') _, headers, _ = client.sign(self.uri + '/extra') u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=headers) self.assertEqual(s, 401)
class RequestTokenEndpointTest(TestCase): def setUp(self): self.validator = MagicMock(wraps=RequestValidator()) self.validator.check_client_key.return_value = True self.validator.allowed_signature_methods = ['HMAC-SHA1'] self.validator.get_client_secret.return_value = 'bar' self.validator.get_default_realms.return_value = ['foo'] self.validator.timestamp_lifetime = 600 self.validator.check_realms.return_value = True self.validator.validate_client_key.return_value = True self.validator.validate_requested_realms.return_value = True self.validator.validate_redirect_uri.return_value = True self.validator.validate_timestamp_and_nonce.return_value = True self.validator.dummy_client = 'dummy' self.validator.dummy_secret = 'dummy' self.validator.save_request_token = MagicMock() self.endpoint = RequestTokenEndpoint(self.validator) self.client = Client('foo', client_secret='bar', realm='foo', callback_uri='https://c.b/cb') self.uri, self.headers, self.body = self.client.sign( 'https://i.b/request_token') def test_check_redirect_uri(self): client = Client('foo') uri, headers, _ = client.sign(self.uri) u, h, b, s = self.endpoint.create_request_token_response( uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_check_realms(self): self.validator.check_realms.return_value = False u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_validate_client_key(self): self.validator.validate_client_key.return_value = False u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 401) def test_validate_realms(self): self.validator.validate_requested_realms.return_value = False u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 401) def test_validate_redirect_uri(self): self.validator.validate_redirect_uri.return_value = False u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 401) def test_validate_signature(self): client = Client('foo', callback_uri='https://c.b/cb') _, headers, _ = client.sign(self.uri + '/extra') u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=headers) self.assertEqual(s, 401) def test_valid_request(self): u, h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 200) self.assertIn('oauth_token', b) def test_uri_provided_realm(self): client = Client('foo', callback_uri='https://c.b/cb', client_secret='bar') uri = self.uri + '?realm=foo' _, headers, _ = client.sign(uri) u, h, b, s = self.endpoint.create_request_token_response( uri, headers=headers) self.assertEqual(s, 200) self.assertIn('oauth_token', b)
def test_client_no_realm(self): client = Client("client-key") uri, header, body = client.sign("http://example-uri") self.assertTrue( header["Authorization"].startswith('OAuth oauth_nonce='))
def test_validate_signature(self): client = Client('foo') _, headers, _ = client.sign(self.uri + '/extra') v, r = self.endpoint.validate_request(self.uri, headers=headers) self.assertFalse(v)
class AccessTokenEndpointTest(TestCase): def setUp(self): self.validator = MagicMock(wraps=RequestValidator()) self.validator.check_client_key.return_value = True self.validator.check_request_token.return_value = True self.validator.check_verifier.return_value = True self.validator.allowed_signature_methods = ['HMAC-SHA1'] self.validator.get_client_secret.return_value = 'bar' self.validator.get_request_token_secret.return_value = 'secret' self.validator.get_realms.return_value = ['foo'] self.validator.timestamp_lifetime = 600 self.validator.validate_client_key.return_value = True self.validator.validate_request_token.return_value = True self.validator.validate_verifier.return_value = True self.validator.validate_timestamp_and_nonce.return_value = True self.validator.invalidate_request_token.return_value = True self.validator.dummy_client = 'dummy' self.validator.dummy_secret = 'dummy' self.validator.dummy_request_token = 'dummy' self.validator.save_access_token = MagicMock() self.endpoint = AccessTokenEndpoint(self.validator) self.client = Client('foo', client_secret='bar', resource_owner_key='token', resource_owner_secret='secret', verifier='verfier') self.uri, self.headers, self.body = self.client.sign( 'https://i.b/access_token') def test_check_request_token(self): self.validator.check_request_token.return_value = False h, b, s = self.endpoint.create_access_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_check_verifier(self): self.validator.check_verifier.return_value = False h, b, s = self.endpoint.create_access_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_validate_client_key(self): self.validator.validate_client_key.return_value = False h, b, s = self.endpoint.create_access_token_response( self.uri, headers=self.headers) self.assertEqual(s, 401) def test_validate_request_token(self): self.validator.validate_request_token.return_value = False h, b, s = self.endpoint.create_access_token_response( self.uri, headers=self.headers) self.assertEqual(s, 401) def test_validate_verifier(self): self.validator.validate_verifier.return_value = False h, b, s = self.endpoint.create_access_token_response( self.uri, headers=self.headers) self.assertEqual(s, 401) def test_validate_signature(self): client = Client('foo', resource_owner_key='token', resource_owner_secret='secret', verifier='verfier') _, headers, _ = client.sign(self.uri + '/extra') h, b, s = self.endpoint.create_access_token_response(self.uri, headers=headers) self.assertEqual(s, 401) def test_valid_request(self): h, b, s = self.endpoint.create_access_token_response( self.uri, headers=self.headers) self.assertEqual(s, 200) self.assertIn('oauth_token', b) self.validator.validate_timestamp_and_nonce.assert_called_once_with( self.client.client_key, ANY, ANY, ANY, request_token=self.client.resource_owner_key) self.validator.invalidate_request_token.assert_called_once_with( self.client.client_key, self.client.resource_owner_key, ANY)
class IntegrationTestLTI(testutil.TestCase): """ Integration tests for third_party_auth LTI auth providers """ def setUp(self): super(IntegrationTestLTI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.hostname = 'testserver' self.client.defaults['SERVER_NAME'] = self.hostname self.url_prefix = 'http://{}'.format(self.hostname) self.configure_lti_provider( name='Other Tool Consumer 1', enabled=True, lti_consumer_key='other1', lti_consumer_secret='secret1', lti_max_timestamp_age=10, ) self.configure_lti_provider( name='LTI Test Tool Consumer', enabled=True, lti_consumer_key=LTI_CONSUMER_KEY, lti_consumer_secret=LTI_CONSUMER_SECRET, lti_max_timestamp_age=10, ) self.configure_lti_provider( name='Tool Consumer with Secret in Settings', enabled=True, lti_consumer_key=OTHER_LTI_CONSUMER_KEY, lti_consumer_secret='', lti_max_timestamp_age=10, ) self.lti = Client( client_key=LTI_CONSUMER_KEY, client_secret=LTI_CONSUMER_SECRET, signature_type=SIGNATURE_TYPE_BODY, ) def test_lti_login(self): # The user initiates a login from an external site (uri, _headers, body) = self.lti.sign( uri=self.url_prefix + LTI_TPA_LOGIN_URL, http_method='POST', headers={'Content-Type': FORM_ENCODED}, body={ 'user_id': LTI_USER_ID, 'custom_tpa_next': '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll', }) login_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body) # The user should be redirected to the registration form assert login_response.status_code == 302 assert login_response['Location'].endswith(reverse('signin_user')) register_response = self.client.get(login_response['Location']) self.assertContains(register_response, '"currentProvider": "LTI Test Tool Consumer"') self.assertContains(register_response, '"errorMessage": null') # Now complete the form: ajax_register_response = self.client.post( reverse('user_api_registration'), { 'email': EMAIL, 'name': 'Myself', 'username': EDX_USER_ID, 'honor_code': True, }) assert ajax_register_response.status_code == 200 continue_response = self.client.get(self.url_prefix + LTI_TPA_COMPLETE_URL) # The user should be redirected to the finish_auth view which will enroll them. # FinishAuthView.js reads the URL parameters directly from $.url assert continue_response.status_code == 302 assert continue_response[ 'Location'] == '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll' # Now check that we can login again self.client.logout() self.verify_user_email(EMAIL) (uri, _headers, body) = self.lti.sign(uri=self.url_prefix + LTI_TPA_LOGIN_URL, http_method='POST', headers={'Content-Type': FORM_ENCODED}, body={'user_id': LTI_USER_ID}) login_2_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body) # The user should be redirected to the dashboard assert login_2_response.status_code == 302 assert login_2_response['Location'] == (LTI_TPA_COMPLETE_URL + '?') continue_2_response = self.client.get(login_2_response['Location']) assert continue_2_response.status_code == 302 assert continue_2_response['Location'].endswith(reverse('dashboard')) # Check that the user was created correctly user = User.objects.get(email=EMAIL) assert user.username == EDX_USER_ID def test_reject_initiating_login(self): response = self.client.get(self.url_prefix + LTI_TPA_LOGIN_URL) assert response.status_code == 405 # Not Allowed def test_reject_bad_login(self): login_response = self.client.post( path=self.url_prefix + LTI_TPA_LOGIN_URL, content_type=FORM_ENCODED, data="invalid=login", ) # The user should be redirected to the login page with an error message # (auth_entry defaults to login for this provider) assert login_response.status_code == 302 assert login_response['Location'].endswith(reverse('signin_user')) error_response = self.client.get(login_response['Location']) self.assertContains( error_response, 'Authentication failed: LTI parameters could not be validated.', ) def test_can_load_consumer_secret_from_settings(self): lti = Client( client_key=OTHER_LTI_CONSUMER_KEY, client_secret=OTHER_LTI_CONSUMER_SECRET, signature_type=SIGNATURE_TYPE_BODY, ) (uri, _headers, body) = lti.sign( uri=self.url_prefix + LTI_TPA_LOGIN_URL, http_method='POST', headers={'Content-Type': FORM_ENCODED}, body={ 'user_id': LTI_USER_ID, 'custom_tpa_next': '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll', }) with self.settings(SOCIAL_AUTH_LTI_CONSUMER_SECRETS={ OTHER_LTI_CONSUMER_KEY: OTHER_LTI_CONSUMER_SECRET }): login_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body) # The user should be redirected to the registration form assert login_response.status_code == 302 assert login_response['Location'].endswith(reverse('signin_user')) register_response = self.client.get(login_response['Location']) self.assertContains( register_response, '"currentProvider": "Tool Consumer with Secret in Settings"', ) self.assertContains(register_response, '"errorMessage": null')