示例#1
0
 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.')
示例#2
0
 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)
示例#3
0
 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.')
示例#5
0
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.'
                )
示例#6
0
 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.')
示例#7
0
 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.')
示例#8
0
 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.')
示例#9
0
 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')
示例#10
0
 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.'
     )
示例#11
0
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.'
        )
示例#12
0
 def setUpClass(cls):
     tokenStorage = DictTokenStorage()
     setattr(TokenResource, '_OAuthTokenStorage', tokenStorage)
     tokenStorage.store(cls.VALID_TOKEN, getTestPasswordClient(),
                        cls.VALID_TOKEN_SCOPE)
示例#13
0
    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')
示例#14
0
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'))