def duplicate(self, sinfo): _dic = copy.copy(sinfo) areq = AuthorizationRequest().from_json(_dic["authzreq"]) sid = self.token_factory["code"].key(user=_dic["sub"], areq=areq) _dic["code"] = self.token_factory["code"](sid=sid, sinfo=sinfo) _dic["code_used"] = False for key in [ "access_token", "access_token_scope", "oauth_state", "token_type", "token_expires_at", "expires_in", "client_id_issued_at", "id_token", "oidreq", "refresh_token", ]: try: del _dic[key] except KeyError: pass self._db[sid] = _dic self.uid2sid[_dic["sub"]] = sid return sid
def test_get_or_post_with_qp(): uri = u"https://localhost:8092/authorization?test=testslice" method = "GET" values = { "acr_values": "PASSWORD", "state": "urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a", "redirect_uri": "https://localhost:8666/919D3F697FDAAF138124B83E09ECB0B7", "response_type": "code", "client_id": "ok8tx7ulVlNV", "scope": "openid profile email address phone", } request = AuthorizationRequest(**values) path, body, ret_kwargs = util.get_or_post(uri, method, request) assert url_compare( path, u"https://localhost:8092/authorization?test=testslice&acr_values=PASSWORD&state=urn%3A" "uuid%3A92d81fb3-72e8-4e6c-9173-c360b782148a&" "redirect_uri=https%3A%2F%2Flocalhost%3A8666%2F919D3F697FDAAF138124B83E09ECB0B7&" "response_type=code&client_id=ok8tx7ulVlNV&scope=openid+profile+email+address+phone", ) assert not body assert not ret_kwargs
def get_aat(self, user): request_args = {"response_type": "code", "client_id": "internal", "redirect_uri": self.client.redirect_uris[0], "scope": [self.client.get_uma_scope("AAT")], "state": "_state"} areq = AuthorizationRequest(**request_args) pre_trace("C-->AS", "get_aat", query=areq.to_dict(), user=user) sid = self.srv.sdb.create_authz_session(user, areq) grant = self.srv.sdb[sid]["code"] self.client.token[user] = { "AAT": self.srv.sdb.upgrade_to_token(grant)} post_trace( "C<--AS", AAT=self.client.token[user]["AAT"]["access_token"])
def test_get_or_post_with_qp(): uri = u'https://localhost:8092/authorization?test=testslice' method = 'GET' values = { 'acr_values': 'PASSWORD', 'state': 'urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a', 'redirect_uri': 'https://localhost:8666/919D3F697FDAAF138124B83E09ECB0B7', 'response_type': 'code', 'client_id': 'ok8tx7ulVlNV', 'scope': 'openid profile email address phone' } request = AuthorizationRequest(**values) path, body, ret_kwargs = util.get_or_post(uri, method, request) assert url_compare( path, u"https://localhost:8092/authorization?test=testslice&acr_values=PASSWORD&state=urn%3A" "uuid%3A92d81fb3-72e8-4e6c-9173-c360b782148a&" "redirect_uri=https%3A%2F%2Flocalhost%3A8666%2F919D3F697FDAAF138124B83E09ECB0B7&" "response_type=code&client_id=ok8tx7ulVlNV&scope=openid+profile+email+address+phone" ) assert not body assert not ret_kwargs
def get_aat(self, user): request_args = { "response_type": "code", "client_id": "internal", "redirect_uri": self.client.redirect_uris[0], "scope": [self.client.get_uma_scope("AAT")], "state": "_state" } areq = AuthorizationRequest(**request_args) pre_trace("C-->AS", "get_aat", query=areq.to_dict(), user=user) sid = self.srv.sdb.create_authz_session(user, areq) grant = self.srv.sdb[sid]["code"] self.client.token[user] = {"AAT": self.srv.sdb.upgrade_to_token(grant)} post_trace("C<--AS", AAT=self.client.token[user]["AAT"]["access_token"])
def _handle_authentication_response(self): has_error = flask.request.args.get('error', False, lambda x: bool(int(x))) if has_error: if 'error' in flask.session: return self._show_error_response(flask.session.pop('error')) return 'Something went wrong.' try: session = UserSession(flask.session) except UninitialisedSession: return self._handle_error_response({'error': 'unsolicited_response', 'error_description': 'No initialised user session.'}) if 'auth_request' not in flask.session: return self._handle_error_response({'error': 'unsolicited_response', 'error_description': 'No authentication request stored.'}) auth_request = AuthorizationRequest().from_json(flask.session.pop('auth_request')) if flask.session.pop('fragment_encoded_response', False): return importlib_resources.read_binary('flask_pyoidc', 'parse_fragment.html').decode('utf-8') is_processing_fragment_encoded_response = flask.request.method == 'POST' if is_processing_fragment_encoded_response: auth_resp = flask.request.form else: auth_resp = flask.request.args client = self.clients[session.current_provider] authn_resp = client.parse_authentication_response(auth_resp) logger.debug('received authentication response: %s', authn_resp.to_json()) try: result = AuthResponseHandler(client).process_auth_response(authn_resp, auth_request) except AuthResponseErrorResponseError as e: return self._handle_error_response(e.error_response, is_processing_fragment_encoded_response) except AuthResponseProcessError as e: return self._handle_error_response({'error': 'unexpected_error', 'error_description': str(e)}, is_processing_fragment_encoded_response) if current_app.config.get('OIDC_SESSION_PERMANENT', True): flask.session.permanent = True UserSession(flask.session).update(access_token=result.access_token, expires_in=result.expires_in, id_token=result.id_token_claims, id_token_jwt=result.id_token_jwt, userinfo=result.userinfo_claims, refresh_token=result.refresh_token) destination = flask.session.pop('destination') if is_processing_fragment_encoded_response: # if the POST request was from the JS page handling fragment encoded responses we need to return # the destination URL as the response body return destination return redirect(destination)
def test_get_or_post(): uri = u'https://localhost:8092/authorization' method = 'GET' values = {'acr_values': 'PASSWORD', 'state': 'urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a', 'redirect_uri': 'https://localhost:8666/919D3F697FDAAF138124B83E09ECB0B7', 'response_type': 'code', 'client_id': 'ok8tx7ulVlNV', 'scope': 'openid profile email address phone'} request = AuthorizationRequest(**values) path, body, ret_kwargs = util.get_or_post(uri, method, request) assert url_compare(path, u"https://localhost:8092/authorization?acr_values=PASSWORD&state=urn%3A" "uuid%3A92d81fb3-72e8-4e6c-9173-c360b782148a&" "redirect_uri=https%3A%2F%2Flocalhost%3A8666%2F919D3F697FDAAF138124B83E09ECB0B7&" "response_type=code&client_id=ok8tx7ulVlNV&scope=openid+profile+email+address+phone") assert not body assert not ret_kwargs method = 'POST' uri = u'https://localhost:8092/token' values = { 'redirect_uri': 'https://localhost:8666/919D3F697FDAAF138124B83E09ECB0B7', 'code': 'Je1iKfPN1vCiN7L43GiXAuAWGAnm0mzA7QIjl/YLBBZDB9wefNExQlLDUIIDM2rT' '2t+gwuoRoapEXJyY2wrvg9cWTW2vxsZU+SuWzZlMDXc=', 'grant_type': 'authorization_code'} request = AccessTokenRequest(**values) kwargs = {'scope': '', 'state': 'urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a', 'authn_method': 'client_secret_basic', 'key': [], 'headers': { 'Authorization': 'Basic b2s4dHg3dWxWbE5WOjdlNzUyZDU1MTc0NzA0NzQzYjZiZWJk' 'YjU4ZjU5YWU3MmFlMGM5NDM4YTY1ZmU0N2IxMDA3OTM1'} } path, body, ret_kwargs = util.get_or_post(uri, method, request, **kwargs) assert path == u'https://localhost:8092/token' assert url_compare("http://test/#{}".format(body), 'http://test/#code=Je1iKfPN1vCiN7L43GiXAuAWGAnm0mzA7QIjl%2FYLBBZDB9wefNExQlLDUIIDM2rT2t%2BgwuoR' 'oapEXJyY2wrvg9cWTW2vxsZU%2BSuWzZlMDXc%3D&grant_type=authorization_code&redirect_uri=https%3A%2' 'F%2Flocalhost%3A8666%2F919D3F697FDAAF138124B83E09ECB0B7') assert ret_kwargs == {'scope': '', 'state': 'urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a', 'authn_method': 'client_secret_basic', 'key': [], 'headers': { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic b2s4dHg3dWxWbE5WOjdlNzUyZDU1MTc0NzA0NzQzYjZiZWJkYjU4ZjU5YWU3MmFl' 'MGM5NDM4YTY1ZmU0N2IxMDA3OTM1'}} method = 'UNSUPORTED' with pytest.raises(UnSupported): util.get_or_post(uri, method, request, **kwargs)
"redirect_uris": [callback] } ressrv.client.redirect_uris = [callback] # Register the RS as a client to the AS, this is OAuth2 dynreg registration reg_info = ressrv.client.construct_RegistrationRequest(request_args=_me) reg_resp = authzsrv.oauth_registration_endpoint(reg_info.to_json()) regresp = RegistrationResponse().from_json(reg_resp.message) ressrv.client.store_registration_info(regresp) # Get the PAT, should normally be a login and token request RESOURCE_OWNER = "linda" identity = {"uid": RESOURCE_OWNER} areq = AuthorizationRequest(client_id=regresp["client_id"], scope=[PAT]) # Authentication happens by magic :-) authn_event = AuthnEvent(RESOURCE_OWNER, 'salt', authn_info="UserPassword", time_stamp=int(time.time())) sid = authzsrv.sdb.create_authz_session(authn_event, areq) grant = authzsrv.sdb[sid]["code"] _dict = authzsrv.sdb.upgrade_to_token(grant) ressrv.rs_handler.token['PAT'] = _dict["access_token"] # ============================== 2 =========================================== # create resource set descriptions and register them. # ressrv.rs_handler.register_resource_set_description({'prim': RESOURCE_OWNER}) res_set_desc = ressrv.rs_handler.dataset.build_resource_set_descriptions(
opc.update(uma_pcr) client.handle_provider_config(uma_pcr, authzsrv.baseurl, False, True) client.provider_info = opc # Register the RS as a client to the AS, this is OAuth2 dynreg registration reg_info = client.construct_RegistrationRequest(request_args=_me) reg_resp = authzsrv.oidc_registration_endpoint(reg_info.to_json()) regresp = RegistrationResponse().from_json(reg_resp.message) client.store_registration_info(regresp) # Get the PAT, should normally be a login and token request RESOURCE_OWNER = "linda" identity = {"uid": RESOURCE_OWNER} areq = AuthorizationRequest(client_id=regresp["client_id"]) # Authentication happens by magic :-) authn_event = AuthnEvent(RESOURCE_OWNER, identity.get('salt', ''), authn_info="UserPassword", time_stamp=int(time.time())) sid = authzsrv.sdb.create_authz_session(authn_event, areq) grant = authzsrv.sdb[sid]["code"] _dict = authzsrv.sdb.upgrade_to_token(grant) # pat = _dict["access_token"] ressrv.authz_registration(RESOURCE_OWNER, _dict, opc["issuer"], RESSRV_CLI_KEY) # ============================== 2 =========================================== # create resource set descriptions and register them. res_set_desc = ressrv.dataset.build_resource_set_descriptions( {"user": RESOURCE_OWNER})
def test_get_or_post(): uri = u"https://localhost:8092/authorization" method = "GET" values = { "acr_values": "PASSWORD", "state": "urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a", "redirect_uri": "https://localhost:8666/919D3F697FDAAF138124B83E09ECB0B7", "response_type": "code", "client_id": "ok8tx7ulVlNV", "scope": "openid profile email address phone", } request = AuthorizationRequest(**values) path, body, ret_kwargs = util.get_or_post(uri, method, request) assert url_compare( path, u"https://localhost:8092/authorization?acr_values=PASSWORD&state=urn%3A" "uuid%3A92d81fb3-72e8-4e6c-9173-c360b782148a&" "redirect_uri=https%3A%2F%2Flocalhost%3A8666%2F919D3F697FDAAF138124B83E09ECB0B7&" "response_type=code&client_id=ok8tx7ulVlNV&scope=openid+profile+email+address+phone", ) assert not body assert not ret_kwargs method = "POST" uri = u"https://localhost:8092/token" values = { "redirect_uri": "https://localhost:8666/919D3F697FDAAF138124B83E09ECB0B7", "code": "Je1iKfPN1vCiN7L43GiXAuAWGAnm0mzA7QIjl/YLBBZDB9wefNExQlLDUIIDM2rT" "2t+gwuoRoapEXJyY2wrvg9cWTW2vxsZU+SuWzZlMDXc=", "grant_type": "authorization_code", } request2 = AccessTokenRequest(**values) kwargs = { "scope": "", "state": "urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a", "authn_method": "client_secret_basic", "key": [], "headers": { "Authorization": "Basic b2s4dHg3dWxWbE5WOjdlNzUyZDU1MTc0NzA0NzQzYjZiZWJk" "YjU4ZjU5YWU3MmFlMGM5NDM4YTY1ZmU0N2IxMDA3OTM1" }, } path, body, ret_kwargs = util.get_or_post(uri, method, request2, **kwargs) assert path == u"https://localhost:8092/token" assert url_compare( "http://test/#{}".format(body), "http://test/#code=Je1iKfPN1vCiN7L43GiXAuAWGAnm0mzA7QIjl%2FYLBBZDB9wefNExQlLDUIIDM2rT2t%2BgwuoR" "oapEXJyY2wrvg9cWTW2vxsZU%2BSuWzZlMDXc%3D&grant_type=authorization_code&redirect_uri=https%3A%2" "F%2Flocalhost%3A8666%2F919D3F697FDAAF138124B83E09ECB0B7", ) assert ret_kwargs == { "scope": "", "state": "urn:uuid:92d81fb3-72e8-4e6c-9173-c360b782148a", "authn_method": "client_secret_basic", "key": [], "headers": { "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Basic b2s4dHg3dWxWbE5WOjdlNzUyZDU1MTc0NzA0NzQzYjZiZWJkYjU4ZjU5YWU3MmFl" "MGM5NDM4YTY1ZmU0N2IxMDA3OTM1", }, } method = "UNSUPORTED" with pytest.raises(UnSupported): util.get_or_post(uri, method, request2, **kwargs)
class TestAuthResponseHandler: ISSUER = 'https://issuer.example.com' CLIENT_ID = 'client1' AUTH_REQUEST = AuthorizationRequest(**{ 'state': 'test_state', 'nonce': 'test_nonce' }) AUTH_RESPONSE = AuthorizationResponse(**{ 'code': 'test_auth_code', 'state': AUTH_REQUEST['state'] }) TOKEN_RESPONSE = AccessTokenResponse( **{ 'access_token': 'test_token', 'expires_in': 3600, 'id_token': _create_id_token(ISSUER, CLIENT_ID, AUTH_REQUEST['nonce']), 'id_token_jwt': 'test_id_token_jwt', 'refresh_token': 'test_refresh_token' }) USERINFO_RESPONSE = OpenIDSchema(**{'sub': 'test_sub'}) ERROR_RESPONSE = { 'error': 'test_error', 'error_description': 'something went wrong' } @pytest.fixture def client_mock(self): return create_autospec(PyoidcFacade, True, True) def test_should_detect_state_mismatch(self, client_mock): auth_request = { 'state': 'other_state', 'nonce': self.AUTH_REQUEST['nonce'] } with pytest.raises(AuthResponseUnexpectedStateError): AuthResponseHandler(client_mock).process_auth_response( self.AUTH_RESPONSE, auth_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_should_handle_auth_error_response(self, client_mock): with pytest.raises(AuthResponseErrorResponseError) as exc: AuthResponseHandler(client_mock).process_auth_response( AuthorizationErrorResponse(**self.ERROR_RESPONSE), self.AUTH_REQUEST) assert exc.value.error_response == self.ERROR_RESPONSE def test_should_handle_token_error_response(self, client_mock): client_mock.exchange_authorization_code.return_value = TokenErrorResponse( **self.ERROR_RESPONSE) with pytest.raises(AuthResponseErrorResponseError) as exc: AuthResponseHandler(client_mock).process_auth_response( AuthorizationResponse(**self.AUTH_RESPONSE), self.AUTH_REQUEST) assert exc.value.error_response == self.ERROR_RESPONSE def test_should_detect_mismatching_subject(self, client_mock): client_mock.exchange_authorization_code.return_value = AccessTokenResponse( **self.TOKEN_RESPONSE) client_mock.userinfo_request.return_value = OpenIDSchema( **{'sub': 'other_sub'}) with pytest.raises(AuthResponseMismatchingSubjectError): AuthResponseHandler(client_mock).process_auth_response( AuthorizationResponse(**self.AUTH_RESPONSE), self.AUTH_REQUEST) def test_should_handle_auth_response_with_authorization_code( self, client_mock): client_mock.exchange_authorization_code.return_value = self.TOKEN_RESPONSE client_mock.userinfo_request.return_value = self.USERINFO_RESPONSE result = AuthResponseHandler(client_mock).process_auth_response( self.AUTH_RESPONSE, self.AUTH_REQUEST) assert result.access_token == 'test_token' assert result.expires_in == self.TOKEN_RESPONSE['expires_in'] assert result.id_token_claims == self.TOKEN_RESPONSE[ 'id_token'].to_dict() assert result.id_token_jwt == self.TOKEN_RESPONSE['id_token_jwt'] assert result.userinfo_claims == self.USERINFO_RESPONSE.to_dict() assert result.refresh_token == self.TOKEN_RESPONSE['refresh_token'] def test_should_handle_auth_response_without_authorization_code( self, client_mock): auth_response = AuthorizationResponse(**self.TOKEN_RESPONSE) auth_response['state'] = 'test_state' client_mock.userinfo_request.return_value = self.USERINFO_RESPONSE result = AuthResponseHandler(client_mock).process_auth_response( auth_response, self.AUTH_REQUEST) assert not client_mock.exchange_authorization_code.called assert result.access_token == 'test_token' assert result.expires_in == self.TOKEN_RESPONSE['expires_in'] assert result.id_token_jwt == self.TOKEN_RESPONSE['id_token_jwt'] assert result.id_token_claims == self.TOKEN_RESPONSE[ 'id_token'].to_dict() assert result.userinfo_claims == self.USERINFO_RESPONSE.to_dict() assert result.refresh_token == None def test_should_handle_token_response_without_id_token(self, client_mock): token_response = {'access_token': 'test_token'} client_mock.exchange_authorization_code.return_value = AccessTokenResponse( **token_response) result = AuthResponseHandler(client_mock).process_auth_response( AuthorizationResponse(**self.AUTH_RESPONSE), self.AUTH_REQUEST) assert result.access_token == 'test_token' assert result.id_token_claims is None def test_should_handle_no_token_response(self, client_mock): client_mock.exchange_authorization_code.return_value = None client_mock.userinfo_request.return_value = None hybrid_auth_response = self.AUTH_RESPONSE.copy() hybrid_auth_response.update(self.TOKEN_RESPONSE) result = AuthResponseHandler(client_mock).process_auth_response( AuthorizationResponse(**hybrid_auth_response), self.AUTH_REQUEST) assert result.access_token == 'test_token' assert result.id_token_claims == self.TOKEN_RESPONSE[ 'id_token'].to_dict() assert result.id_token_jwt == self.TOKEN_RESPONSE['id_token_jwt'] @pytest.mark.parametrize( 'response_type, expected', [ ('code', False), # Authorization Code Flow ('id_token', True), # Implicit Flow ('id_token token', True), # Implicit Flow ('code id_token', True), # Hybrid Flow ('code token', True), # Hybrid Flow ('code id_token token', True) # Hybrid Flow ]) def test_expect_fragment_encoded_response_by_response_type( self, response_type, expected): assert AuthResponseHandler.expect_fragment_encoded_response( {'response_type': response_type}) is expected @pytest.mark.parametrize('response_type, response_mode, expected', [ ('code', 'fragment', True), ('id_token', 'query', False), ('code token', 'form_post', False), ]) def test_expect_fragment_encoded_response_with_non_default_response_mode( self, response_type, response_mode, expected): auth_req = { 'response_type': response_type, 'response_mode': response_mode } assert AuthResponseHandler.expect_fragment_encoded_response( auth_req) is expected