def testInfiniteTokenLifetime(self): """ Test that the token lifetime of the new auth token can be infinite. """ tokenLifetime = None newAuthToken = 'newAuthTokenWithoutChangedLifetime' tokenResource = TokenResource(self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, authTokenLifeTime=tokenLifetime, passwordManager=self._PASSWORD_MANAGER) request = self.generateValidTokenRequest( arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN }, authentication=self._VALID_CLIENT) self._TOKEN_FACTORY.expectTokenRequest(newAuthToken, tokenLifetime, self._VALID_CLIENT, self._VALID_SCOPE) result = tokenResource.render_POST(request) self._TOKEN_FACTORY.assertAllTokensRequested() self.assertValidTokenResponse(request, result, newAuthToken, tokenLifetime, expectedScope=self._VALID_SCOPE)
def testAuthorizedClientWithoutScope(self): """ Test that of a request without a scope is accepted if the token resource has a default scope. """ defaultScope = ['default', 'scope'] accessToken = 'clientCredentialsAccessTokenWithoutScope' tokenResource = TokenResource(self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, defaultScope=defaultScope, passwordManager=self._PASSWORD_MANAGER) request = self.generateValidTokenRequest( arguments={ 'grant_type': 'client_credentials', }, authentication=self._VALID_CLIENT) self._TOKEN_FACTORY.expectTokenRequest(accessToken, tokenResource.authTokenLifeTime, self._VALID_CLIENT, defaultScope) result = tokenResource.render_POST(request) self._TOKEN_FACTORY.assertAllTokensRequested() self.assertValidTokenResponse(request, result, accessToken, tokenResource.authTokenLifeTime, expectedScope=defaultScope)
def testRefreshTokenRenewal(self): """ Test that the refresh token is refreshed when expected. """ oldRefreshToken = 'oldRefreshToken' additionalData = 'someAdditionalData' newAuthToken = 'newAuthToken' newRefreshToken = 'newRefreshToken' self._REFRESH_TOKEN_STORAGE.store( oldRefreshToken, self._VALID_CLIENT, self._VALID_SCOPE, additionalData) tokenResource = TokenResource( self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, minRefreshTokenLifeTime=0, passwordManager=self._PASSWORD_MANAGER) request = self.generateValidTokenRequest(arguments={ 'grant_type': 'refresh_token', 'refresh_token': oldRefreshToken }, authentication=self._VALID_CLIENT) self._TOKEN_FACTORY.expectTokenRequest( newAuthToken, tokenResource.authTokenLifeTime, self._VALID_CLIENT, self._VALID_SCOPE, additionalData) self._TOKEN_FACTORY.expectTokenRequest( newRefreshToken, None, self._VALID_CLIENT, self._VALID_SCOPE, additionalData) result = tokenResource.render_POST(request) self._TOKEN_FACTORY.assertAllTokensRequested() self.assertFalse( self._REFRESH_TOKEN_STORAGE.contains(oldRefreshToken), msg='Expected the token resource to remove an old refresh token from the token storage.' ) self.assertValidTokenResponse( request, result, newAuthToken, tokenResource.authTokenLifeTime, expectedRefreshToken=newRefreshToken, expectedScope=self._VALID_SCOPE, expectedAdditionalData=additionalData)
def setUpClass(cls): super(FullExampleTestCase, cls).setUpClass() sys.path.append(os.path.abspath(os.path.join( os.path.dirname(__file__), '..', '..', 'example'))) exampleModule = importlib.import_module('main') # noinspection PyUnresolvedReferences cls._VALID_CLIENT = exampleModule.getTestClient() # noinspection PyUnresolvedReferences cls._SERVER = MockSite(exampleModule.setupTestServerResource()) TokenResource.getTokenStorageSingleton().store( cls._VALID_TOKEN, cls._VALID_CLIENT, cls._VALID_SCOPE)
def testIsValidToken(self): """ Test that the isValidToken method rejects invalid tokens and accepts valid ones. """ self.assertTrue(TokenResource.isValidToken('aValidToken'), msg='Expected isValidToken to accept a valid token.') self.assertTrue(TokenResource.isValidToken( TokenResource.VALID_TOKEN_CHARS), msg='Expected isValidToken to accept a valid token.') self.assertFalse( TokenResource.isValidToken('Token!'), msg='Expected isValidToken to accept an invalid token.') self.assertFalse( TokenResource.isValidToken('an invalid Token'), msg='Expected isValidToken to accept an invalid token.')
def testInsecureConnection(self): """ Test the rejection of a request via an insecure transport, except if allowInsecureRequestDebug is set to true. """ request = self.generateValidTokenRequest( arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN }, authentication=self._VALID_CLIENT, isSecure=False) result = self._TOKEN_RESOURCE.render_POST(request) self.assertFailedTokenRequest( request, result, InsecureConnectionError(), msg= 'Expected the token resource to reject a request made via an insecure transport' ) debugTokenResource = TokenResource( self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, allowInsecureRequestDebug=True, passwordManager=self._PASSWORD_MANAGER) request = self.generateValidTokenRequest( arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN }, authentication=self._VALID_CLIENT, isSecure=False) newAuthToken = 'tokenViaInsecureConnection' self._TOKEN_FACTORY.expectTokenRequest( newAuthToken, debugTokenResource.authTokenLifeTime, self._VALID_CLIENT, self._VALID_SCOPE) result = debugTokenResource.render_POST(request) self._TOKEN_FACTORY.assertAllTokensRequested() self.assertValidTokenResponse( request, result, newAuthToken, expectedExpireTime=debugTokenResource.authTokenLifeTime, expectedScope=self._VALID_SCOPE)
def testAuthorizedWithoutScope(self): """ Test that a request without a scope is accepted, if the token resource has a default scope. """ userName = b'validUserWithoutScope' password = b'validPasswordWithoutScope' defaultScope = ['default', 'scope'] authToken = 'resourceOwnerPasswordCredentialsTokenWithoutScope' refreshToken = 'resourceOwnerPasswordCredentialsRefreshTokenWithoutScope' tokenResource = TokenResource(self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, defaultScope=defaultScope, passwordManager=self._PASSWORD_MANAGER) request = self.generateValidTokenRequest( arguments={ 'grant_type': 'password', 'username': userName, 'password': password, }, authentication=self._VALID_CLIENT) self._PASSWORD_MANAGER.expectAuthenticateRequest(userName, password) self._TOKEN_FACTORY.expectTokenRequest(authToken, tokenResource.authTokenLifeTime, self._VALID_CLIENT, defaultScope) self._TOKEN_FACTORY.expectTokenRequest(refreshToken, None, self._VALID_CLIENT, defaultScope) result = tokenResource.render_POST(request) self.assertTrue( self._PASSWORD_MANAGER.allPasswordsChecked(), msg='Expected the token resource to check if the given ' 'user name and password combination is valid.') self._TOKEN_FACTORY.assertAllTokensRequested() self.assertValidTokenResponse(request, result, authToken, tokenResource.authTokenLifeTime, expectedScope=defaultScope, expectedRefreshToken=refreshToken)
def testWhenDisabled(self): """ Test the rejection of a password request when the grant type is disabled. """ tokenResource = TokenResource(self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, grantTypes=[]) request = self.generateValidTokenRequest( arguments={ 'grant_type': 'password', 'username': b'someUserName', 'password': b'somePassword', }, authentication=self._VALID_CLIENT) result = tokenResource.render_POST(request) self.assertFailedTokenRequest( request, result, UnsupportedGrantTypeError('password'), msg='Expected the token resource to reject a password ' 'request, if the grant type is disabled')
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 _testTokenLifetime(self, token, lifetime): """ Test that a request made to a token resource with the given default auth token lifetime is valid and generates a token with the lifetime. :param token: The token that should get generated. :param lifetime: The default and expected lifetime of the token. """ tokenResource = TokenResource( self._TOKEN_FACTORY, self._PERSISTENT_STORAGE, self._REFRESH_TOKEN_STORAGE, self._AUTH_TOKEN_STORAGE, self._CLIENT_STORAGE, authTokenLifeTime=lifetime, passwordManager=self._PASSWORD_MANAGER) request = self.generateValidTokenRequest(arguments={ 'grant_type': 'refresh_token', 'refresh_token': self._VALID_REFRESH_TOKEN }, authentication=self._VALID_CLIENT) self._TOKEN_FACTORY.expectTokenRequest( token, lifetime, self._VALID_CLIENT, self._VALID_SCOPE) result = tokenResource.render_POST(request) self._TOKEN_FACTORY.assertAllTokensRequested() self.assertValidTokenResponse(request, result, token, lifetime, expectedScope=self._VALID_SCOPE)
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)
def isAuthorized(request, scope, allowInsecureRequestDebug=False): """ Returns True if the token in the request grants access to the given scope. The token is validated via the authTokenStorage singleton given to the TokenResource instance. If the token is invalid, does not grant access to the scope or was not send via a secure protocol, False is returned, an error is written to the request and the request is closed. You can not write to the request if this function returned False! :param request: The request. :param scope: The scope or list of scopes the token must grant access to. :param allowInsecureRequestDebug: Allow requests to originate from insecure connections. Only use for local testing! :return: True, if the request is authorized, False otherwise. """ error = None scope = scope if type(scope) == list else [scope] if not (allowInsecureRequestDebug or request.isSecure()): error = InsecureConnectionError() else: try: requestToken = _getToken(request) except ValueError: error = MultipleTokensError(scope) else: if requestToken is None: error = MissingTokenError(scope) else: try: requestToken = requestToken.decode('utf-8') except UnicodeDecodeError: pass else: tokenStorage = TokenResource.getTokenStorageSingleton() if tokenStorage.contains(requestToken): if tokenStorage.hasAccess(requestToken, scope): return True else: error = InsufficientScopeRequestError(scope) if error is None: error = InvalidTokenRequestError(scope) request.write(error.generate(request)) request.finish() return False
def setupTestServerResource(): """ Setup a test server with a protected clock resource and an oauth2 endpoint. :return: The root resource of the test server """ clientStorage = setupOAuth2Clients() enabledGrantTypes = [GrantTypes.AuthorizationCode, GrantTypes.RefreshToken] tokenResource = TokenResource(UUIDTokenFactory(), PersistentStorageImp(), DictTokenStorage(), DictTokenStorage(), clientStorage, allowInsecureRequestDebug=True, grantTypes=enabledGrantTypes) root = Resource() root.putChild(b'clock', ClockPage()) root.putChild( b'oauth2', OAuth2Endpoint.initFromTokenResource(tokenResource, subPath=b'token', grantTypes=enabledGrantTypes)) return root