def test_register(self): registration_endpoint = self.PROVIDER_BASEURL + '/register' responses.add(responses.POST, registration_endpoint, json=self.CLIENT_METADATA.to_dict()) provider_metadata = self.PROVIDER_METADATA.copy(registration_endpoint=registration_endpoint) unregistered = ProviderConfiguration(provider_metadata=provider_metadata, client_registration_info=ClientRegistrationInfo()) facade = PyoidcFacade(unregistered, self.REDIRECT_URI) facade.register() assert facade.is_registered() is True
def test_token_request_handles_error_response(self): token_endpoint = self.PROVIDER_BASEURL + '/token' token_response = TokenErrorResponse(error='invalid_request', error_description='test error description') responses.add(responses.POST, token_endpoint, json=token_response.to_dict(), status=400) provider_metadata = self.PROVIDER_METADATA.copy(token_endpoint=token_endpoint) facade = PyoidcFacade(ProviderConfiguration(provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA), self.REDIRECT_URI) assert facade.token_request('1234') == token_response
def test_no_userinfo_request_is_made_if_no_userinfo_endpoint_is_configured( self): facade = PyoidcFacade( ProviderConfiguration( provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA, ), self.REDIRECT_URI, ) assert facade.userinfo_request("test_token") is None
def test_parse_authentication_response(self): facade = PyoidcFacade(ProviderConfiguration(provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA), self.REDIRECT_URI) auth_code = 'auth_code-1234' state = 'state-1234' auth_response = AuthorizationResponse(**{'state': state, 'code': auth_code}) parsed_auth_response = facade.parse_authentication_response(auth_response.to_dict()) assert isinstance(parsed_auth_response, AuthorizationResponse) assert parsed_auth_response.to_dict() == auth_response.to_dict()
def test_no_userinfo_request_is_made_if_no_access_token(self): provider_metadata = self.PROVIDER_METADATA.copy( userinfo_endpoint=self.PROVIDER_BASEURL + "/userinfo") facade = PyoidcFacade( ProviderConfiguration( provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA, ), self.REDIRECT_URI, ) assert facade.userinfo_request(None) is None
def test_configurable_userinfo_endpoint_method_is_used(self, userinfo_http_method): userinfo_endpoint = self.PROVIDER_BASEURL + '/userinfo' userinfo_response = OpenIDSchema(sub='user1') responses.add(userinfo_http_method, userinfo_endpoint, json=userinfo_response.to_dict()) provider_metadata = self.PROVIDER_METADATA.copy(userinfo_endpoint=userinfo_endpoint) facade = PyoidcFacade(ProviderConfiguration(provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA, userinfo_http_method=userinfo_http_method), self.REDIRECT_URI) assert facade.userinfo_request('test_token') == userinfo_response
def test_parse_authentication_response_handles_error_response(self): facade = PyoidcFacade( ProviderConfiguration(provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA), REDIRECT_URI) error_response = AuthorizationErrorResponse(**{ 'error': 'invalid_request', 'state': 'state-1234' }) parsed_auth_response = facade.parse_authentication_response( error_response) assert isinstance(parsed_auth_response, AuthorizationErrorResponse) assert parsed_auth_response.to_dict() == error_response.to_dict()
def test_token_request(self): token_endpoint = self.PROVIDER_BASEURL + "/token" now = int(time.time()) id_token_claims = { "iss": self.PROVIDER_METADATA["issuer"], "sub": "test_user", "aud": [self.CLIENT_METADATA["client_id"]], "exp": now + 1, "iat": now, "nonce": "test_nonce", } id_token_jwt, id_token_signing_key = signed_id_token(id_token_claims) token_response = AccessTokenResponse(access_token="test_access_token", token_type="Bearer", id_token=id_token_jwt) responses.add(responses.POST, token_endpoint, json=token_response.to_dict()) provider_metadata = self.PROVIDER_METADATA.copy( token_endpoint=token_endpoint) facade = PyoidcFacade( ProviderConfiguration( provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA, ), self.REDIRECT_URI, ) auth_code = "auth_code-1234" responses.add( responses.GET, self.PROVIDER_METADATA["jwks_uri"], json={"keys": [id_token_signing_key.serialize()]}, ) with self.app.app_context(): token_response = facade.token_request(auth_code) assert isinstance(token_response, AccessTokenResponse) expected_token_response = token_response.to_dict() expected_token_response["id_token"] = id_token_claims expected_token_response["id_token_jwt"] = id_token_jwt assert token_response.to_dict() == expected_token_response token_request = dict(parse_qsl(responses.calls[0].request.body)) expected_token_request = { "grant_type": "authorization_code", "code": auth_code, "redirect_uri": self.FULL_REDIRECT_URI } assert token_request == expected_token_request
def test_should_detect_nonce_mismatch(self, client_mock): client = PyoidcFacade( ProviderConfiguration( provider_metadata=ProviderMetadata(issuer=self.ISSUER), client_metadata=ClientMetadata(client_id=self.CLIENT_ID)), redirect_uri='https://client.example.com/redirect') client.exchange_authorization_code = MagicMock( return_value=self.TOKEN_RESPONSE) auth_request = { 'state': self.AUTH_RESPONSE['state'], 'nonce': 'other_nonce' } with pytest.raises(InvalidIdTokenError): AuthResponseHandler(client).process_auth_response( self.AUTH_RESPONSE, auth_request)
def test_token_request(self): token_endpoint = self.PROVIDER_BASEURL + '/token' now = int(time.time()) id_token_claims = { 'iss': self.PROVIDER_METADATA['issuer'], 'sub': 'test_user', 'aud': [self.CLIENT_METADATA['client_id']], 'exp': now + 1, 'iat': now, 'nonce': 'test_nonce' } id_token_jwt, id_token_signing_key = signed_id_token(id_token_claims) token_response = AccessTokenResponse(access_token='test_access_token', token_type='Bearer', id_token=id_token_jwt) responses.add(responses.POST, token_endpoint, json=token_response.to_dict()) provider_metadata = self.PROVIDER_METADATA.copy( token_endpoint=token_endpoint) facade = PyoidcFacade( ProviderConfiguration(provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA), self.REDIRECT_URI) auth_code = 'auth_code-1234' responses.add(responses.GET, self.PROVIDER_METADATA['jwks_uri'], json={'keys': [id_token_signing_key.serialize()]}) token_response = facade.token_request(auth_code) assert isinstance(token_response, AccessTokenResponse) expected_token_response = token_response.to_dict() expected_token_response['id_token'] = id_token_claims expected_token_response['id_token_jwt'] = id_token_jwt assert token_response.to_dict() == expected_token_response token_request = dict(parse_qsl(responses.calls[0].request.body)) expected_token_request = { 'grant_type': 'authorization_code', 'code': auth_code, 'redirect_uri': self.REDIRECT_URI } assert token_request == expected_token_request
def test_token_request(self, request_func, expected_token_request): token_endpoint = self.PROVIDER_BASEURL + '/token' now = int(time.time()) id_token_claims = { 'iss': self.PROVIDER_METADATA['issuer'], 'sub': 'test_user', 'aud': [self.CLIENT_METADATA['client_id']], 'exp': now + 1, 'iat': now, 'nonce': 'test_nonce' } id_token_jwt, id_token_signing_key = signed_id_token(id_token_claims) token_response = AccessTokenResponse(access_token='test_access_token', refresh_token='refresh-token', token_type='Bearer', id_token=id_token_jwt, expires_in=now + 1) responses.add(responses.POST, token_endpoint, json=token_response.to_dict()) provider_metadata = self.PROVIDER_METADATA.copy( token_endpoint=token_endpoint) facade = PyoidcFacade( ProviderConfiguration(provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA), REDIRECT_URI) grant = Grant(resp=token_response) grant.grant_expiration_time = now + grant.exp_in facade._client.grant = {'test-state': grant} responses.add(responses.GET, self.PROVIDER_METADATA['jwks_uri'], json={'keys': [id_token_signing_key.serialize()]}) token_response = request_func(facade) assert isinstance(token_response, AccessTokenResponse) expected_token_response = token_response.to_dict() expected_token_response['id_token'] = id_token_claims expected_token_response['id_token_jwt'] = id_token_jwt assert token_response.to_dict() == expected_token_response token_request = dict(parse_qsl(responses.calls[0].request.body)) assert token_request == expected_token_request
def test_client_credentials_grant(self, scope, extra_args): token_endpoint = f'{self.PROVIDER_BASEURL}/token' provider_metadata = self.PROVIDER_METADATA.copy( token_endpoint=token_endpoint) facade = PyoidcFacade( ProviderConfiguration(provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA), REDIRECT_URI) client_credentials_grant_response = { 'access_token': 'access_token', 'expires_in': 60, 'not-before-policy': 0, 'refresh_expires_in': 0, 'scope': 'read write', 'token_type': 'Bearer' } responses.add(responses.POST, token_endpoint, json=client_credentials_grant_response) assert client_credentials_grant_response == facade.client_credentials_grant( scope=scope, **extra_args).to_dict()
def test_parse_authentication_response_preserves_id_token_jwt(self): facade = PyoidcFacade(ProviderConfiguration(provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA), self.REDIRECT_URI) state = 'state-1234' now = int(time.time()) id_token, id_token_signing_key = signed_id_token({ 'iss': self.PROVIDER_METADATA['issuer'], 'sub': 'test_sub', 'aud': 'client1', 'exp': now + 1, 'iat': now }) responses.add(responses.GET, self.PROVIDER_METADATA['jwks_uri'], json={'keys': [id_token_signing_key.serialize()]}) auth_response = AuthorizationResponse(**{'state': state, 'id_token': id_token}) parsed_auth_response = facade.parse_authentication_response(auth_response) assert isinstance(parsed_auth_response, AuthorizationResponse) assert parsed_auth_response['state'] == state assert parsed_auth_response['id_token_jwt'] == id_token
def test_token_request_handles_error_response(self): token_endpoint = self.PROVIDER_BASEURL + '/token' token_response = TokenErrorResponse( error='invalid_request', error_description='test error description') responses.add(responses.POST, token_endpoint, json=token_response.to_dict(), status=400) provider_metadata = self.PROVIDER_METADATA.copy( token_endpoint=token_endpoint) facade = PyoidcFacade( ProviderConfiguration(provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA), REDIRECT_URI) state = 'test-state' grant = Grant() grant.grant_expiration_time = int(time.time()) + grant.exp_in facade._client.grant = {state: grant} assert facade.exchange_authorization_code('1234', state) == token_response
def test_token_request_handles_error_response(self): token_endpoint = self.PROVIDER_BASEURL + "/token" token_response = TokenErrorResponse( error="invalid_request", error_description="test error description") responses.add(responses.POST, token_endpoint, json=token_response.to_dict(), status=400) provider_metadata = self.PROVIDER_METADATA.copy( token_endpoint=token_endpoint) facade = PyoidcFacade( ProviderConfiguration( provider_metadata=provider_metadata, client_metadata=self.CLIENT_METADATA, ), self.REDIRECT_URI, ) with self.app.app_context(): assert facade.token_request("1234") == token_response
def test_parse_authentication_response_preserves_id_token_jwt(self): facade = PyoidcFacade( ProviderConfiguration( provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA, ), self.REDIRECT_URI, ) state = "state-1234" now = int(time.time()) id_token, id_token_signing_key = signed_id_token({ "iss": self.PROVIDER_METADATA["issuer"], "sub": "test_sub", "aud": "client1", "exp": now + 1, "iat": now, }) responses.add( responses.GET, self.PROVIDER_METADATA["jwks_uri"], json={"keys": [id_token_signing_key.serialize()]}, ) auth_response = AuthorizationResponse(**{ "state": state, "id_token": id_token }) parsed_auth_response = facade.parse_authentication_response( auth_response) assert isinstance(parsed_auth_response, AuthorizationResponse) assert parsed_auth_response["state"] == state assert parsed_auth_response["id_token_jwt"] == id_token
def test_no_registered_client_metadata_is_handled(self): config = ProviderConfiguration( provider_metadata=self.PROVIDER_METADATA, client_registration_info=ClientRegistrationInfo()) facade = PyoidcFacade(config, REDIRECT_URI) assert not facade._client.registration_response
def test_registered_client_metadata_is_forwarded_to_pyoidc(self): config = ProviderConfiguration( provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA) facade = PyoidcFacade(config, REDIRECT_URI) assert facade._client.registration_response
def test_token_request_handles_missing_provider_token_endpoint(self): facade = PyoidcFacade( ProviderConfiguration(provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA), REDIRECT_URI) assert facade.exchange_authorization_code('1234') is None
def test_no_userinfo_request_is_made_if_no_userinfo_http_method_is_configured(self): facade = PyoidcFacade(ProviderConfiguration(provider_metadata=self.PROVIDER_METADATA, client_metadata=self.CLIENT_METADATA, userinfo_http_method=None), self.REDIRECT_URI) assert facade.userinfo_request('test_token') is None