def testUnauthorizedClient(self): """ Test the rejection of a request with a client that is not authorized to use the authorization code grant type. """ client = getTestPasswordClient('unauthorizedCodeGrantClient', authorizedGrantTypes=[]) code = 'unauthorizedClientCode' self._addAuthorizationToStorage(code, client, ['scope'], client.redirectUris[0]) request = self.generateValidTokenRequest(arguments={ 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': client.redirectUris[0], }, authentication=client) self._CLIENT_STORAGE.addClient(client) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, UnauthorizedClientError('authorization_code'), msg= 'Expected the resource token to reject an authorization_code request ' 'with a client that is not authorized to use that grant type.')
def testWithUnauthorizedClient(self): """ Test the rejection of a request with a client that is not allowed to use the response type. """ state = b'state\xFF\xFF' client = getTestPasswordClient(authorizedGrantTypes=[]) redirectUri = client.redirectUris[0] request = self.createAuthRequest( arguments={ 'response_type': self._RESPONSE_TYPE, 'client_id': client.id, 'redirect_uri': redirectUri, 'scope': 'All', 'state': state }) self._CLIENT_STORAGE.addClient(client) result = self._AUTH_RESOURCE.render_GET(request) self.assertFailedRequest( request, result, UnauthorizedClientError(self._RESPONSE_TYPE, state=state), msg= 'Expected the auth resource to reject a request for a client that is not ' 'authorized to request an authorization using the ' '{type} method.'.format(type=self._RESPONSE_TYPE), redirectUri=redirectUri)
def testWithDifferentClient(self): """ Test the rejection of a request with a valid authorization code that authorizes a different client. """ client = getTestPasswordClient( 'unauthorizedCodeGrantClient', authorizedGrantTypes=[GrantTypes.AuthorizationCode]) code = 'differentClientCode' self._addAuthorizationToStorage(code, client, ['scope'], client.redirectUris[0]) request = self.generateValidTokenRequest( arguments={ 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': client.redirectUris[0], }, authentication=self._VALID_CLIENT) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, InvalidTokenError('authorization code'), msg= 'Expected the resource token to reject an authorization_code request ' 'with a code that was issued to a different client.')
def testUnauthorizedClient(self): """ Test the rejection of a client that is not authorized to use the Resource Owner Password Credentials Grant. """ client = getTestPasswordClient( 'unauthorizedResourceOwnerPasswordCredentialsGrantClient', authorizedGrantTypes=[]) request = self.generateValidTokenRequest(arguments={ 'grant_type': 'password', 'scope': ' '.join(self._VALID_SCOPE), 'username': b'someUser', 'password': b'somePassword', }, authentication=client) self._CLIENT_STORAGE.addClient(client) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, UnauthorizedClientError('password'), msg='Expected the resource token to reject a password request ' 'with a client that is not authorized to use that grant type.')
class AbstractTokenFactoryTest(TwistedTestCase): """ An abstract test case for TokenFactory implementations. A subclass must set __test__ to True and call setupTokenFactory with an instance of the token factory to test. """ _TOKEN_FACTORY = None _VALID_SCOPE = ['All', 'Scope1'] _VALID_ADDITIONAL_DATA = 'additionalData' _DUMMY_CLIENT = getTestPasswordClient() @classmethod def setupTokenFactory(cls, tokenFactory, client=_DUMMY_CLIENT): """ Set the token factory implementation to use for the tests. :param tokenFactory: The token factory implementation to test. :param client: The client to use for token generation. """ cls._TOKEN_FACTORY = tokenFactory cls._DUMMY_CLIENT = client def testTokenGeneration(self): """ Verify that the token factory generates valid tokens. """ token = self._TOKEN_FACTORY.generateToken(None, self._DUMMY_CLIENT, self._VALID_SCOPE) self.assertIsInstance( token, str, message='Expected the token factory to return a string.') self.assertTrue( TokenResource.isValidToken(token), msg= 'The generated token is not valid according to the oauth2 specifications.' ) def testTokenUniqueness(self): """ Test that the token factory generates unique tokens. """ tokens = [ self._TOKEN_FACTORY.generateToken(None, self._DUMMY_CLIENT, self._VALID_SCOPE), self._TOKEN_FACTORY.generateToken(None, self._DUMMY_CLIENT, self._VALID_SCOPE), self._TOKEN_FACTORY.generateToken(200, self._DUMMY_CLIENT, self._VALID_SCOPE), self._TOKEN_FACTORY.generateToken(200, self._DUMMY_CLIENT, self._VALID_SCOPE), ] for firstToken in tokens: for secondToken in tokens: if firstToken is secondToken: continue self.assertNotEqual( firstToken, secondToken, msg='Expected the token factory to generate unique tokens.' )
def testWrongClient(self): """ Test the rejection of a request with a valid refresh token for a different client. """ client = getTestPasswordClient( clientId='differentClient', authorizedGrantTypes=[GrantTypes.REFRESH_TOKEN]) request = self.generateValidTokenRequest(arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN, }, authentication=client) self._CLIENT_STORAGE.addClient(client) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, InvalidTokenError('refresh token'), msg='Expected the token resource to reject a refresh_token request ' 'with a refresh token that is not valid for the client.')
def testUnauthorizedGrantTypeClient(self): """ Test the rejection of a valid request for an unauthorized client. """ client = getTestPasswordClient(clientId='unauthorizedClient', authorizedGrantTypes=[]) request = self.generateValidTokenRequest(arguments={ 'grant_type': 'refresh_token', 'client_id': client.id, 'client_secret': client.secret, 'refresh_token': self._VALID_REFRESH_TOKEN, }) self._CLIENT_STORAGE.addClient(client) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, UnauthorizedClientError('refresh_token'), msg='Expected the token resource to reject a refresh_token request ' 'for the client that is not authorized to use that grant type.')
def testAuthorizationMalformedClientSecretInHeader(self): """ Test the rejection of a request with a malformed client secret in the header. """ client = getTestPasswordClient('malformedSecret') client.secret = b'malformedSecret\xFF\xFF' request = self.generateValidTokenRequest( arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN }) self._addAuthenticationToRequestHeader(request, client) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, MalformedParameterError('client_secret'), msg='Expected the token resource to reject a ' 'request with a malformed Authorization header.')
def testTokenClient(self): """ Test that the token storage returns the correct client id for a token. """ self.assertEquals( self._DUMMY_CLIENT.id, self._TOKEN_STORAGE.getTokenClient(self._VALID_TOKEN), msg= 'Expected getTokenClient to return the correct client id for the token.' ) token = 'otherValidToken' client = getTestPasswordClient('otherClientId') self._TOKEN_STORAGE.store(token, client, self._VALID_SCOPE) self.assertEquals( client.id, self._TOKEN_STORAGE.getTokenClient(token), msg= 'Expected getTokenClient to return the client id given to store.') self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenClient, 'invalidToken')
def testAuthorizationWrongClientSecretInHeader(self): """ Test the rejection of a request with an invalid client secret in the header. """ client = getTestPasswordClient(self._VALID_CLIENT.id) client.secret = 'invalidSecret' request = self.generateValidTokenRequest( arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN }) self._addAuthenticationToRequestHeader(request, client) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, InvalidClientAuthenticationError(), msg= 'Expected the token resource to reject a request with an invalid client secret.' )
class AbstractTokenStorageTest(TwistedTestCase): """ An abstract test case for TokenStorage implementations. A subclass must set __test__ to True and call setupTokenStorage with an instance of the token storage to test. """ _TOKEN_STORAGE = None _VALID_TOKEN = 'ValidToken' _VALID_SCOPE = ['All', 'Scope1'] _VALID_ADDITIONAL_DATA = 'additionalData' _DUMMY_CLIENT = getTestPasswordClient() @classmethod def setupTokenStorage(cls, tokenStorage, client=_DUMMY_CLIENT): """ Set the token storage implementation to use for the tests and store the valid token in the token storage. :param tokenStorage: The token storage implementation to test. :param client: The client to use for storing tokens. """ cls._TOKEN_STORAGE = tokenStorage cls._DUMMY_CLIENT = client tokenStorage.store(cls._VALID_TOKEN, client, cls._VALID_SCOPE, cls._VALID_ADDITIONAL_DATA) def testContains(self): """ Test that the token storage correctly reports if it contains a token or not. """ self.assertTrue(self._TOKEN_STORAGE.contains(self._VALID_TOKEN), msg='Expected contains to return True for a token ' 'that was previously stored in the token storage.') self.assertFalse(self._TOKEN_STORAGE.contains('someInvalidToken'), msg='Expected contains to return False for a token ' 'that is not in the token storage.') def testHasAccess(self): """ Test that the token storage only reports granted access for valid tokens within valid scopes or subsets of the valid scopes. """ self.assertTrue( self._TOKEN_STORAGE.hasAccess(self._VALID_TOKEN, self._VALID_SCOPE), msg='Expected hasAccess to return True for a valid token and scope.' ) self.assertTrue( self._TOKEN_STORAGE.hasAccess(self._VALID_TOKEN, self._VALID_SCOPE[0:1]), msg='Expected hasAccess to return True for a valid token ' 'and a subset of the valid scopes.') self.assertFalse(self._TOKEN_STORAGE.hasAccess(self._VALID_TOKEN, ['invalidScope']), msg='Expected hasAccess to return False ' 'for a valid token and an invalid scope.') self.assertFalse( self._TOKEN_STORAGE.hasAccess(self._VALID_TOKEN, [self._VALID_SCOPE[0].upper()]), msg='Expected hasAccess to return False for a valid token ' 'and an invalid scope (scopes must be case sensitive).') self.assertFalse( self._TOKEN_STORAGE.hasAccess( self._VALID_TOKEN, self._VALID_SCOPE + ['invalidScope']), msg= 'Expected hasAccess to return False for a valid token and an invalid scope.' ) self.assertRaises(KeyError, self._TOKEN_STORAGE.hasAccess, 'invalidToken', self._VALID_SCOPE) def testTokenClient(self): """ Test that the token storage returns the correct client id for a token. """ self.assertEquals( self._DUMMY_CLIENT.id, self._TOKEN_STORAGE.getTokenClient(self._VALID_TOKEN), msg= 'Expected getTokenClient to return the correct client id for the token.' ) token = 'otherValidToken' client = getTestPasswordClient('otherClientId') self._TOKEN_STORAGE.store(token, client, self._VALID_SCOPE) self.assertEquals( client.id, self._TOKEN_STORAGE.getTokenClient(token), msg= 'Expected getTokenClient to return the client id given to store.') self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenClient, 'invalidToken') def testTokenScope(self): """ Test that the token storage returns the correct scope for a token. """ self.assertListEqual( self._VALID_SCOPE, self._TOKEN_STORAGE.getTokenScope(self._VALID_TOKEN), msg= 'Expected getTokenScope to return the correct scope for the token.' ) token = 'otherValidToken' self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE[0:1]) self.assertListEqual( self._VALID_SCOPE[0:1], self._TOKEN_STORAGE.getTokenScope(token), msg='Expected getTokenScope to return the scope given to store.') self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenScope, 'invalidToken') def testAdditionalData(self): """ Test if the token storage can correctly store additional data for a token. """ self.assertEquals(self._VALID_ADDITIONAL_DATA, self._TOKEN_STORAGE.getTokenAdditionalData( self._VALID_TOKEN), msg='Expected getTokenAdditionalData to return ' 'the correct additional data for the token.') token = 'dataTestToken' tokenData = 'Some arbitrary data' self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE, additionalData=tokenData) self.assertEquals( tokenData, self._TOKEN_STORAGE.getTokenAdditionalData(token), msg='Expected the token storage return the additional data ' 'that was stored with the token.') self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenAdditionalData, 'invalidToken') def testGetTokenLifetime(self): """ Test that the token storage correctly reports the lifetime of a token """ token = 'lifetimeToken' self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE[0:1]) self.assertEquals( 0, self._TOKEN_STORAGE.getTokenLifetime(token), msg= 'Expected the token resource to return the correct lifetime of the token.' ) self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenLifetime, 'nonExistentToken') def testStore(self): """ Test that the token storage can correctly store a token, it's scope and it's additional data. """ token = 'testToken' self.assertFalse(self._TOKEN_STORAGE.contains(token), msg='Did expect that the token storage would not ' 'contain the test token before it was stored.') self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE) self.assertTrue( self._TOKEN_STORAGE.contains(token), msg= 'Expected the token storage to contain the token after it was stored.' ) self.assertTrue( self._TOKEN_STORAGE.hasAccess(token, self._VALID_SCOPE), msg= 'Expected the token storage to contain the token after it was stored.' ) self.assertListEqual( self._VALID_SCOPE, self._TOKEN_STORAGE.getTokenScope(token), msg= 'Expected the token storage return the same scope that was supplied to store.' ) self.assertIsNone( self._TOKEN_STORAGE.getTokenAdditionalData(token), msg='Expected the token storage return None as the additional data ' 'for a token if none was supplied to store.') self.assertRaises(ValueError, self._TOKEN_STORAGE.store, None, self._DUMMY_CLIENT, self._VALID_SCOPE) self.assertRaises(ValueError, self._TOKEN_STORAGE.store, 42, self._DUMMY_CLIENT, self._VALID_SCOPE) def testRemove(self): """ Test that the token storage correctly removes tokens. """ token = 'removeToken' self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE) self.assertTrue( self._TOKEN_STORAGE.contains(token), msg= 'Expected the token storage to contain the token after it was stored.' ) self._TOKEN_STORAGE.remove(token) self.assertFalse( self._TOKEN_STORAGE.contains(token), msg= 'Expected the token storage to not contain the token after it has been removed.' ) self.assertRaises(KeyError, self._TOKEN_STORAGE.remove, 'nonExistentToken') def testTokenOverwrite(self): """ Test that the token storage correctly overwrites an existing token. Note that this should not happen if the TokenFactory is implemented correctly. """ token = 'overwriteTestToken' tokenData = 'token data' self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE) self.assertListEqual( self._VALID_SCOPE, self._TOKEN_STORAGE.getTokenScope(token), msg= 'Expected getTokenScope to return the scope that was stored with the token.' ) self.assertIsNone( self._TOKEN_STORAGE.getTokenAdditionalData(token), msg='Expected getTokenScope to return the additional ' 'data that was stored with the token.') self.assertEquals( self._DUMMY_CLIENT.id, self._TOKEN_STORAGE.getTokenClient(token), msg= 'Expected getTokenScope to return the client id that was stored with the token.' ) self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE[0:1], additionalData=tokenData) self.assertListEqual( self._VALID_SCOPE[0:1], self._TOKEN_STORAGE.getTokenScope(token), msg= 'Expected getTokenScope to return the new scope that was stored with the token.' ) self.assertEquals( tokenData, self._TOKEN_STORAGE.getTokenAdditionalData(token), msg='Expected getTokenScope to return the new additional ' 'data that was stored with the token.') self.assertEquals( self._DUMMY_CLIENT.id, self._TOKEN_STORAGE.getTokenClient(token), msg= 'Expected getTokenScope to return the new client id that was stored with the token.' ) self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE[1:2]) self.assertListEqual( self._VALID_SCOPE[1:2], self._TOKEN_STORAGE.getTokenScope(token), msg= 'Expected getTokenScope to return the new scope that was stored with the token.' ) self.assertIsNone( self._TOKEN_STORAGE.getTokenAdditionalData(token), msg='Expected getTokenScope to return the new additional ' 'data that was stored with the token.') self.assertEquals( self._DUMMY_CLIENT.id, self._TOKEN_STORAGE.getTokenClient(token), msg= 'Expected getTokenScope to return the new client id that was stored with the token.' ) def testExpireTime(self): """ Test that the token storage correctly expires the tokens. """ expireTokens = ['expireToken1', 'expireToken2', 'expireToken3'] noExpireToken = 'noExpireToken' futureExpireToken = 'futureExpireToken' hasExpiredToken = 'hasExpiredToken' for token in expireTokens: self._TOKEN_STORAGE.store(token, self._DUMMY_CLIENT, self._VALID_SCOPE, expireTime=time.time() + 1) self._TOKEN_STORAGE.store(noExpireToken, self._DUMMY_CLIENT, self._VALID_SCOPE) self._TOKEN_STORAGE.store(futureExpireToken, self._DUMMY_CLIENT, self._VALID_SCOPE, expireTime=time.time() + 600) self._TOKEN_STORAGE.store(hasExpiredToken, self._DUMMY_CLIENT, self._VALID_SCOPE, expireTime=time.time() - 10) for token in expireTokens: self.assertTrue( self._TOKEN_STORAGE.contains(token), msg='Expected the token storage to contain the tokens ' 'that will expire in a few seconds but have not yet.') self.assertTrue( self._TOKEN_STORAGE.contains(noExpireToken), msg= 'Expected the token storage to contain the token that will never expire.' ) self.assertTrue( self._TOKEN_STORAGE.contains(futureExpireToken), msg= 'Expected the token storage to contain the token has not expired.') self.assertFalse( self._TOKEN_STORAGE.contains(hasExpiredToken), msg= 'Expected the token storage to not contain the token that has expired.' ) time.sleep(1.5) self.assertFalse( self._TOKEN_STORAGE.contains(expireTokens[0]), msg='Expected the token storage to not contain an expired token.') self.assertRaises(KeyError, self._TOKEN_STORAGE.hasAccess, expireTokens[1], self._VALID_SCOPE) self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenAdditionalData, expireTokens[2]) self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenClient, expireTokens[2]) self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenScope, expireTokens[2]) self.assertRaises(KeyError, self._TOKEN_STORAGE.getTokenLifetime, expireTokens[2]) self.assertTrue( self._TOKEN_STORAGE.contains(noExpireToken), msg= 'Expected the token storage to contain the token that will never expire.' ) self.assertTrue( self._TOKEN_STORAGE.contains(futureExpireToken), msg= 'Expected the token storage to contain the token has not expired.') self.assertGreaterEqual( self._TOKEN_STORAGE.getTokenLifetime(noExpireToken), 1, msg= 'Expected the token storage to correctly report the lifetime of the token.' )
def setUpClass(cls): tokenStorage = DictTokenStorage() setattr(TokenResource, '_OAuthTokenStorage', tokenStorage) tokenStorage.store(cls.VALID_TOKEN, getTestPasswordClient(), cls.VALID_TOKEN_SCOPE)
class ClientStorageTest(TwistedTestCase): """ An abstract test case for ClientStorage implementations. A subclass must call setupClientStorage with an instance of the client storage to test. """ _CLIENT_STORAGE = None _VALID_CLIENTS = [ getTestPasswordClient(), PublicClient('publicClient', ['https://return.nonexistent'], []) ] @classmethod def setupClientStorage(cls, clientStorage): """ Set the client storage implementation to use for the tests. The client storage must contain all _VALID_CLIENTS. :param clientStorage: The client storage implementation to test. """ cls._CLIENT_STORAGE = clientStorage def testGetClient(self): """ Test the retrieval of clients from the client storage. """ for validClient in self._VALID_CLIENTS: client = self._CLIENT_STORAGE.getClient(validClient.id) self.assertIsInstance( client, Client, message= 'Expected the client storage to return a client object.') self.assertIsInstance( client, validClient.__class__, message='Expected the client storage to return a client ' 'object of the same subclass as the original client.') self.assertIsInstance( client.id, str, message='Expected the client id of the client returned ' 'by the client storage to be a string.') self.assertIsInstance( client.redirectUris, list, message='Expected the redirect uris of the client returned ' 'by the client storage to be a list.') for uri in client.redirectUris: self.assertIsInstance( uri, str, message='Expected all redirect uris of the client ' 'returned by the client storage to be a string.') self.assertIsInstance( client.authorizedGrantTypes, list, message='Expected the authorized grant types of the client ' 'returned by the client storage to be a list.') for grantType in client.authorizedGrantTypes: self.assertIsInstance( grantType, str, message= 'Expected all grant types of the client returned ' 'by the client storage to be a string.') assertClientEquals( self, client, validClient, message= 'Expected the attributes of the client returned by the client storage ' 'to have the same values as the attributes of the original client.' ) def testGetNonExistentClient(self): """ Test handling of requests for clients that do net exist in the client storage. """ self.assertRaises(KeyError, self._CLIENT_STORAGE.getClient, 'nonExistentClientId')
class AbstractTokenResourceTest(TwistedTestCase): """ Abstract base class for test targeting the token resource. """ _VALID_REFRESH_TOKEN = 'refreshToken' _VALID_SCOPE = ['All', 'scope'] _VALID_CLIENT = getTestPasswordClient() @classmethod def setUpClass(cls): super(AbstractTokenResourceTest, cls).setUpClass() cls._AUTH_TOKEN_STORAGE = DictTokenStorage() cls._REFRESH_TOKEN_STORAGE = DictTokenStorage() cls._TOKEN_FACTORY = TestTokenFactory() cls._PERSISTENT_STORAGE = TestPersistentStorage() cls._CLIENT_STORAGE = TestClientStorage() cls._REFRESH_TOKEN_STORAGE.store(cls._VALID_REFRESH_TOKEN, cls._VALID_CLIENT, cls._VALID_SCOPE) cls._CLIENT_STORAGE.addClient(cls._VALID_CLIENT) cls._PASSWORD_MANAGER = TestPasswordManager() cls._TOKEN_RESOURCE = TokenResource( cls._TOKEN_FACTORY, cls._PERSISTENT_STORAGE, cls._REFRESH_TOKEN_STORAGE, cls._AUTH_TOKEN_STORAGE, cls._CLIENT_STORAGE, passwordManager=cls._PASSWORD_MANAGER) @classmethod def tearDownClass(cls): setattr(TokenResource, '_OAuthTokenStorage', None) def setUp(self): self._TOKEN_FACTORY.reset(self) @staticmethod def _addAuthenticationToRequestHeader(request, client): """ Add authentication with the clients credentials to the header of the request. """ request.addAuthorization(client.id, client.secret) @staticmethod def generateValidTokenRequest(url='token', urlQuery='', authentication=None, **kwargs): """ :param url: The request url. :param urlQuery: An optional query part of the request url. :param authentication: An optional client to use for header-authentication. :param kwargs: Optional arguments to the the request. :return: A valid request to the token resource. """ if urlQuery: url = '?'.join((url, urlQuery)) request = MockRequest('POST', url, **kwargs) request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') if authentication is not None: AbstractTokenResourceTest._addAuthenticationToRequestHeader( request, authentication) return request def assertValidTokenResponse(self, request, result, expectedAccessToken, expectedExpireTime=None, expectedTokenType='Bearer', expectedRefreshToken=None, expectedScope=None, expectedAdditionalData=None): """ Assert that the request succeeded and the token resource returned a correct response. :param request: The request. :param result: The return value of the render_POST function of the token resource. :param expectedAccessToken: The new token that the token resource should have created. :param expectedExpireTime: The expire time of the new token. :param expectedTokenType: The expected type of the token. :param expectedRefreshToken: The expected optional refresh token that the token resource should have created. :param expectedScope: The expected scope of all new created tokens. :param expectedAdditionalData: The optional additional data of the new tokens. """ self.assertEquals( 'application/json;charset=UTF-8', request.getResponseHeader('Content-Type'), msg= 'Expected the token resource to return the token in the json format.' ) self.assertEquals( 'no-store', request.getResponseHeader('Cache-Control'), msg= 'Expected the token resource to set Cache-Control to "no-store".') self.assertEquals( 'no-cache', request.getResponseHeader('Pragma'), msg='Expected the token resource to set Pragma to "no-cache".') self.assertEquals(200, request.responseCode, msg='Expected the token resource to return ' 'a new token with the HTTP code 200 OK.') jsonResult = json.loads(result.decode('utf-8'), encoding='utf-8') self.assertIn('access_token', jsonResult, msg='Expected the result from the token resource ' 'to contain an access_token parameter.') self.assertEquals( jsonResult['access_token'], expectedAccessToken, msg= 'The token resource returned a different access token than expected.' ) self.assertIn('token_type', jsonResult, msg='Expected the result from the token resource ' 'to contain a token_type parameter.') self.assertEquals( jsonResult['token_type'].lower(), expectedTokenType.lower(), msg= 'The token resource returned a different access token type than expected.' ) if expectedExpireTime is None: self.assertNotIn('expires_in', jsonResult, msg='Expected the result from the token resource ' 'to not contain an expires_in parameter.') else: self.assertIn('expires_in', jsonResult, msg='Expected the result from the token resource ' 'to contain an expires_in parameter.') self.assertEquals(jsonResult['expires_in'], expectedExpireTime, msg='The token resource returned a different ' 'access token expire time than expected.') if expectedRefreshToken is None: self.assertNotIn('refresh_token', jsonResult, msg='Expected the result from the token resource ' 'to not contain a refresh_token parameter.') else: self.assertIn('refresh_token', jsonResult, msg='Expected the result from the token resource ' 'to contain a refresh_token parameter.') self.assertEquals(jsonResult['refresh_token'], expectedRefreshToken, msg='The token resource returned a different ' 'refresh token than expected.') if expectedScope is None: self.assertNotIn('scope', jsonResult, msg='Expected the result from the token resource ' 'to not contain a scope parameter.') expectedScope = self._VALID_SCOPE else: self.assertIn('scope', jsonResult, msg='Expected the result from the token resource ' 'to contain a scope parameter.') self.assertListEqual(jsonResult['scope'].split(), expectedScope, msg='The token resource returned a different ' 'scope than expected.') self.assertTrue( self._AUTH_TOKEN_STORAGE.contains(expectedAccessToken), msg='Expected the token storage to contain the new access token.') self.assertTrue( self._AUTH_TOKEN_STORAGE.hasAccess(expectedAccessToken, expectedScope), msg= 'Expected the new access token to have access to the expected scope.' ) self.assertEquals( expectedAdditionalData, self._AUTH_TOKEN_STORAGE.getTokenAdditionalData( expectedAccessToken), msg= 'Expected the new access token to have the expected additional data.' ) if expectedRefreshToken is not None: self.assertTrue( self._REFRESH_TOKEN_STORAGE.contains(expectedRefreshToken), msg='Expected the token storage to contain the refresh token.') self.assertTrue( self._REFRESH_TOKEN_STORAGE.hasAccess(expectedRefreshToken, expectedScope), msg= 'Expected the refresh token to have access to the expected scope.' ) self.assertEquals( expectedAdditionalData, self._REFRESH_TOKEN_STORAGE.getTokenAdditionalData( expectedAccessToken), msg= 'Expected the new refresh token to have the expected additional data.' ) def assertFailedTokenRequest(self, request, result, expectedError, msg): """ Assert that the request did not succeed and that the token resource returned an appropriate error response. :param request: The request. :param result: The return value of the render_POST function of the token resource. :param expectedError: The expected error. :param msg: The assertion error message. """ if result == NOT_DONE_YET: result = request.getResponse() if msg.endswith('.'): msg = msg[:-1] self.assertEquals( 'application/json;charset=UTF-8', request.getResponseHeader('Content-Type'), msg= 'Expected the token resource to return an error in the json format.' ) self.assertEquals( 'no-store', request.getResponseHeader('Cache-Control'), msg= 'Expected the token resource to set Cache-Control to "no-store".') self.assertEquals( 'no-cache', request.getResponseHeader('Pragma'), msg='Expected the token resource to set Pragma to "no-cache".') self.assertEquals( expectedError.code, request.responseCode, msg='Expected the token resource to return a response ' 'with the HTTP code {code}.'.format(code=expectedError.code)) errorResult = json.loads(result.decode('utf-8'), encoding='utf-8') self.assertIn('error', errorResult, msg=msg + ': Missing error parameter in response.') self.assertEquals( errorResult['error'], expectedError.message, msg=msg + ': Result contained a different error than expected.') self.assertIn('error_description', errorResult, msg=msg + ': Missing error_description parameter in response.') self.assertEquals( errorResult['error_description'], expectedError.detail, msg=msg + ': Result contained a different error description than expected.') if expectedError.errorUri is not None: self.assertIn('error_uri', errorResult, msg=msg + ': Missing error_uri parameter in response.') self.assertEquals(errorResult['error_uri'], expectedError.errorUri, msg=msg + ': Result contained an unexpected error_uri.') if expectedError.message == 'invalid_client': self.assertEquals( 401, request.responseCode, msg= 'Expected the token resource to return UNAUTHORIZED as the response code.' ) authorizationHeader = request.getHeader(b'Authorization') if authorizationHeader is not None: authenticateResponse = request.getResponseHeader( 'WWW-Authenticate') self.assertIsNotNone( authenticateResponse, msg= 'If the request has authentication via the "Authorization" header field, ' 'the result must include the "WWW-Authenticate" response header field.' ) authenticateResponse = authenticateResponse.encode('utf-8') authType, realm = authenticateResponse.split() self.assertTrue( authorizationHeader.startswith(authType), msg= 'Expected an WWW-Authenticate response matching the request.' ) expectedHeaderValue = b'realm="' + request.prePathURL() + b'"' self.assertIn( expectedHeaderValue, authenticateResponse, msg= 'The "realm" auth-parameter does not contain the expected value: ' + expectedHeaderValue.decode('utf-8'))