def test_deserialize(self): msg = { "application_type": "web", "redirect_uris": [ "https://client.example.org/callback", "https://client.example.org/callback2" ], "client_name": "My Example", "client_name#ja-Jpan-JP": "クライアント名", "logo_uri": "https://client.example.org/logo.png", "subject_type": "pairwise", "sector_identifier_uri": "https://other.example.net/file_of_redirect_uris.json", "token_endpoint_auth_method": "client_secret_basic", "jwks_uri": "https://client.example.org/my_public_keys.jwks", "userinfo_encrypted_response_alg": "RSA1_5", "userinfo_encrypted_response_enc": "A128CBC+HS256", "contacts": ["*****@*****.**", "*****@*****.**"], "request_uris": [ "https://client.example.org/rf.txt" "#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA" ] } reg = RegistrationRequest().deserialize(json.dumps(msg), "json") assert _eq(list(msg.keys()) + ['response_types'], reg.keys())
def test_registration_endpoint_openid4us(self): req = RegistrationRequest( **{'token_endpoint_auth_method': u'client_secret_post', 'redirect_uris': [ u'https://connect.openid4.us:5443/phpRp/index.php/callback', u'https://connect.openid4.us:5443/phpRp/authcheck.php/authcheckcb'], 'jwks_uri': u'https://connect.openid4.us:5443/phpRp/rp/rp.jwk', 'userinfo_encrypted_response_alg': u'RSA1_5', 'contacts': [u'*****@*****.**'], 'userinfo_encrypted_response_enc': u'A128CBC-HS256', 'application_type': u'web', 'client_name': u'ABRP-17', 'grant_types': [u'authorization_code', u'implicit'], 'post_logout_redirect_uris': [ u'https://connect.openid4.us:5443/phpRp/index.php/logoutcb'], 'subject_type': u'public', 'response_types': [u'code', u'token', u'id_token', u'code token', u'code id_token', u'id_token token', u'code id_token token'], 'policy_uri': u'https://connect.openid4.us:5443/phpRp/index.php/policy', 'logo_uri': u'https://connect.openid4.us:5443/phpRp/media/logo.png'}) resp = self.provider.registration_endpoint(request=req.to_json()) regresp = RegistrationResponse().deserialize(resp.message, "json") assert _eq(regresp.keys(), list(req.keys()) + ['registration_client_uri', 'client_secret_expires_at', 'registration_access_token', 'client_id', 'client_secret', 'client_id_issued_at'])
def create_registration_request(self, **kwargs): """ Create a registration request :param kwargs: parameters to the registration request :return: """ req = RegistrationRequest() for prop in req.parameters(): try: req[prop] = kwargs[prop] except KeyError: try: req[prop] = self.behaviour[prop] except KeyError: pass if "post_logout_redirect_uris" not in req: try: req[ "post_logout_redirect_uris"] = self.post_logout_redirect_uris except AttributeError: pass if "redirect_uris" not in req: try: req["redirect_uris"] = self.redirect_uris except AttributeError: raise MissingRequiredAttribute("redirect_uris", req) return req
def test_registration_endpoint(self): req = RegistrationRequest() req["application_type"] = "web" req["client_name"] = "My super service" req["redirect_uris"] = ["http://example.com/authz"] req["contacts"] = ["*****@*****.**"] req["response_types"] = ["code"] resp = self.provider.registration_endpoint(request=req.to_json()) regresp = RegistrationResponse().deserialize(resp.message, "json") assert _eq( regresp.keys(), [ "redirect_uris", "contacts", "application_type", "client_name", "registration_client_uri", "client_secret_expires_at", "registration_access_token", "client_id", "client_secret", "client_id_issued_at", "response_types", ], )
def register(self, url, **kwargs): """ Register the client at an OP :param url: The OPs registration endpoint :param kwargs: parameters to the registration request :return: """ req = RegistrationRequest() for prop in req.parameters(): try: req[prop] = kwargs[prop] except KeyError: try: req[prop] = self.behaviour[prop] except KeyError: pass if "redirect_uris" not in req: try: req["redirect_uris"] = self.redirect_uris except AttributeError: raise MissingRequiredAttribute("redirect_uris") headers = {"content-type": "application/json"} rsp = self.http_request(url, "POST", data=req.to_json(), headers=headers) return self.handle_registration_info(rsp)
def test_registration_request(self): req = RegistrationRequest( operation="register", default_max_age=10, require_auth_time=True, default_acr="foo", application_type="web", redirect_uris=["https://example.com/authz_cb"]) js = req.to_json() js_obj = json.loads(js) expected_js_obj = { "redirect_uris": ["https://example.com/authz_cb"], "application_type": "web", "default_acr": "foo", "require_auth_time": True, "operation": "register", "default_max_age": 10, "response_types": ["code"] } assert js_obj == expected_js_obj flattened_list_dict = { k: v[0] if isinstance(v, list) else v for k, v in expected_js_obj.items() } assert query_string_compare(req.to_urlencoded(), urlencode(flattened_list_dict))
def test_parse_registration_request(self): regreq = RegistrationRequest( contacts=["*****@*****.**"], redirect_uris=["http://example.org/jqauthz"], application_name="pacubar", client_id=CLIENT_ID, operation="register", application_type="web", ) request = self.srv.parse_registration_request(data=regreq.to_urlencoded()) assert isinstance(request, RegistrationRequest) assert _eq( request.keys(), [ "redirect_uris", "contacts", "client_id", "application_name", "operation", "application_type", "response_types", ], ) assert request["application_name"] == "pacubar" assert request["operation"] == "register"
def test_full_flow(self, context, frontend_with_extra_scopes): redirect_uri = "https://client.example.com/redirect" response_type = "code id_token token" mock_callback = Mock() frontend_with_extra_scopes.auth_req_callback_func = mock_callback # discovery http_response = frontend_with_extra_scopes.provider_config(context) provider_config = ProviderConfigurationResponse().deserialize(http_response.message, "json") # client registration registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=[response_type]) context.request = registration_request.to_dict() http_response = frontend_with_extra_scopes.client_registration(context) registration_response = RegistrationResponse().deserialize(http_response.message, "json") # authentication request authn_req = AuthorizationRequest( redirect_uri=redirect_uri, client_id=registration_response["client_id"], response_type=response_type, scope="openid email eduperson", state="state", nonce="nonce", ) context.request = dict(parse_qsl(authn_req.to_urlencoded())) frontend_with_extra_scopes.handle_authn_request(context) assert mock_callback.call_count == 1 # fake authentication response from backend internal_response = self.setup_for_authn_response( context, frontend_with_extra_scopes, authn_req ) http_response = frontend_with_extra_scopes.handle_authn_response( context, internal_response ) authn_resp = AuthorizationResponse().deserialize(urlparse(http_response.message).fragment, "urlencoded") assert "code" in authn_resp assert "access_token" in authn_resp assert "id_token" in authn_resp # token request context.request = AccessTokenRequest(redirect_uri=authn_req["redirect_uri"], code=authn_resp["code"]).to_dict() credentials = "{}:{}".format(registration_response["client_id"], registration_response["client_secret"]) basic_auth = urlsafe_b64encode(credentials.encode("utf-8")).decode("utf-8") context.request_authorization = "Basic {}".format(basic_auth) http_response = frontend_with_extra_scopes.token_endpoint(context) parsed = AccessTokenResponse().deserialize(http_response.message, "json") assert "access_token" in parsed assert "id_token" in parsed # userinfo request context.request = {} context.request_authorization = "Bearer {}".format(parsed["access_token"]) http_response = frontend_with_extra_scopes.userinfo_endpoint(context) parsed = OpenIDSchema().deserialize(http_response.message, "json") assert "email" in parsed assert "eduperson_principal_name" in parsed assert "eduperson_scoped_affiliation" in parsed
def test_registration_request_with_coupled_encryption_params(self, enc_param): registration_params = { "redirect_uris": ["https://example.com/authz_cb"], enc_param: "RS25asdasd6", } registration_req = RegistrationRequest(**registration_params) with pytest.raises(AssertionError): registration_req.verify()
def test_registration_request_with_coupled_encryption_params(self, enc_param): registration_params = { "redirect_uris": ["https://example.com/authz_cb"], enc_param: "RS25asdasd6"} registration_req = RegistrationRequest(**registration_params) with pytest.raises(AssertionError): registration_req.verify()
def test_register_client_with_wrong_response_type(self, context, frontend): redirect_uri = "https://client.example.com" registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=["id_token token"]) context.request = registration_request.to_dict() registration_response = frontend.client_registration(context) assert registration_response.status == "400 Bad Request" error_response = ClientRegistrationErrorResponse().deserialize(registration_response.message, "json") assert error_response["error"] == "invalid_request" assert "response_type" in error_response["error_description"]
def test_registration_request(): req = RegistrationRequest(type="client_associate", default_max_age=10, require_auth_time=True, default_acr="foo") js = req.to_json() print js assert js == '{"require_auth_time": true, "default_acr": "foo", "type": "client_associate", "default_max_age": 10}' ue = req.to_urlencoded() print ue assert ue == 'default_acr=foo&type=client_associate&default_max_age=10&require_auth_time=True'
def test_verify_redirect_uri_correct_without_query(self, uri): rr = RegistrationRequest(operation="register", redirect_uris=["http://example.org/cb"], response_types=["code"]) registration_req = rr.to_json() resp = self.provider.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) cid = regresp["client_id"] areq = AuthorizationRequest(redirect_uri=uri, client_id=cid, response_type="code", scope="openid") self.provider._verify_redirect_uri(areq)
def test_registration_request(): req = RegistrationRequest(operation="register", default_max_age=10, require_auth_time=True, default_acr="foo", application_type="web", redirect_uris=["https://example.com/authz_cb"]) js = req.to_json() print js assert js == '{"redirect_uris": ["https://example.com/authz_cb"], "application_type": "web", "default_acr": "foo", "require_auth_time": true, "operation": "register", "default_max_age": 10}' ue = req.to_urlencoded() print ue assert ue == 'redirect_uris=https%3A%2F%2Fexample.com%2Fauthz_cb&application_type=web&default_acr=foo&require_auth_time=True&operation=register&default_max_age=10'
def test_register_client_with_wrong_response_type(self, context, frontend): redirect_uri = "https://client.example.com" registration_request = RegistrationRequest( redirect_uris=[redirect_uri], response_types=["id_token token"]) context.request = registration_request.to_dict() registration_response = frontend.client_registration(context) assert registration_response.status == "400 Bad Request" error_response = ClientRegistrationErrorResponse().deserialize( registration_response.message, "json") assert error_response["error"] == "invalid_request" assert "response_type" in error_response["error_description"]
def test_registration_endpoint_with_non_https_redirect_uri_implicit_flow( self): params = {"application_type": "web", "redirect_uris": ["http://example.com/authz"], "response_types": ["id_token", "token"]} req = RegistrationRequest(**params) resp = self.provider.registration_endpoint(request=req.to_json()) assert resp.status == "400 Bad Request" error = json.loads(resp.message) assert error["error"] == "invalid_redirect_uri"
def test_register_client(self, context, frontend): redirect_uri = "https://client.example.com" registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=["id_token"]) context.request = registration_request.to_dict() registration_response = frontend.client_registration(context) assert registration_response.status == "201 Created" reg_resp = RegistrationResponse().deserialize(registration_response.message, "json") assert "client_id" in reg_resp assert reg_resp["redirect_uris"] == [redirect_uri] assert reg_resp["response_types"] == ["id_token"]
def test_full_flow(self, context, frontend): redirect_uri = "https://client.example.com/redirect" response_type = "code id_token token" mock_callback = Mock() frontend.auth_req_callback_func = mock_callback # discovery http_response = frontend.provider_config(context) provider_config = ProviderConfigurationResponse().deserialize(http_response.message, "json") # client registration registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=[response_type]) context.request = registration_request.to_dict() http_response = frontend.client_registration(context) registration_response = RegistrationResponse().deserialize(http_response.message, "json") # authentication request authn_req = AuthorizationRequest( redirect_uri=redirect_uri, client_id=registration_response["client_id"], response_type=response_type, scope="openid email", state="state", nonce="nonce", ) context.request = dict(parse_qsl(authn_req.to_urlencoded())) frontend.handle_authn_request(context) assert mock_callback.call_count == 1 # fake authentication response from backend internal_response = self.setup_for_authn_response(context, frontend, authn_req) http_response = frontend.handle_authn_response(context, internal_response) authn_resp = AuthorizationResponse().deserialize(urlparse(http_response.message).fragment, "urlencoded") assert "code" in authn_resp assert "access_token" in authn_resp assert "id_token" in authn_resp # token request context.request = AccessTokenRequest(redirect_uri=authn_req["redirect_uri"], code=authn_resp["code"]).to_dict() credentials = "{}:{}".format(registration_response["client_id"], registration_response["client_secret"]) basic_auth = urlsafe_b64encode(credentials.encode("utf-8")).decode("utf-8") context.request_authorization = "Basic {}".format(basic_auth) http_response = frontend.token_endpoint(context) parsed = AccessTokenResponse().deserialize(http_response.message, "json") assert "access_token" in parsed assert "id_token" in parsed # userinfo request context.request = {} context.request_authorization = "Bearer {}".format(parsed["access_token"]) http_response = frontend.userinfo_endpoint(context) parsed = OpenIDSchema().deserialize(http_response.message, "json") assert "email" in parsed
def registration_endpoint(self, environ, start_response, **kwargs): logger.debug("@registration_endpoint") try: query = kwargs["query"] except KeyError: try: query = get_or_post(environ) except UnsupportedMethod: resp = BadRequest("Unsupported method") return resp(environ, start_response) request = RegistrationRequest().deserialize(query, "urlencoded") logger.info("registration_request:%s" % request.to_dict()) _keystore = self.server.keystore if request["type"] == "client_associate": # create new id och secret client_id = rndstr(12) while client_id in self.cdb: client_id = rndstr(12) client_secret = secret(self.seed, client_id) self.cdb[client_id] = { "client_secret":client_secret } _cinfo = self.cdb[client_id] if "redirect_uris" in request: for uri in request["redirect_uris"]: if urlparse.urlparse(uri).fragment: err = ClientRegistrationErrorResponse( error="invalid_configuration_parameter", error_description="redirect_uri contains fragment") resp = Response(err.to_json(), content="application/json", status="400 Bad Request") return resp(environ, start_response) for key,val in request.items(): _cinfo[key] = val try: self.keystore.load_keys(request, client_id) except Exception, err: logger.error("Failed to load client keys: %s" % request.to_dict()) err = ClientRegistrationErrorResponse( error="invalid_configuration_parameter", error_description="%s" % err) resp = Response(err.to_json(), content="application/json", status="400 Bad Request") return resp(environ, start_response) response = RegistrationResponseCARS(client_id=client_id)
def test_registration_with_non_https(provider): redirect_uris = ["http://example.org"] registration_params = { "application_type": "web", "response_types": ["id_token", "token"], "redirect_uris": redirect_uris} req = RegistrationRequest(**registration_params) resp = provider.registration_endpoint(req.to_urlencoded()) resp = RegistrationResponse().from_json(resp.message) assert resp["client_id"] is not None assert resp["client_secret"] is not None assert resp["redirect_uris"] == redirect_uris
def test_registration_request(): req = RegistrationRequest(operation="register", default_max_age=10, require_auth_time=True, default_acr="foo", application_type="web", redirect_uris=["https://example.com/authz_cb"]) js = req.to_json() js_obj = json.loads(js) expected_js_obj = {"redirect_uris": ["https://example.com/authz_cb"], "application_type": "web", "default_acr": "foo", "require_auth_time": True, "operation": "register", "default_max_age": 10} assert js_obj == expected_js_obj ue = req.to_urlencoded() ue_splits = ue.split('&') expected_ue_splits = 'redirect_uris=https%3A%2F%2Fexample.com%2Fauthz_cb&application_type=web&default_acr=foo&require_auth_time=True&operation=register&default_max_age=10'.split('&') assert _eq(ue_splits, expected_ue_splits)
def test_read_registration(self): rr = RegistrationRequest( operation="register", redirect_uris=["http://example.org/new"], response_types=["code"] ) registration_req = rr.to_json() resp = self.provider.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) authn = " ".join(["Bearer", regresp["registration_access_token"]]) query = "=".join(["client_id", regresp["client_id"]]) resp = self.provider.read_registration(authn, query) assert json.loads(resp.message) == regresp.to_dict()
def test_read_registration(self): rr = RegistrationRequest(operation="register", redirect_uris=["http://example.org/new"], response_types=["code"]) registration_req = rr.to_json() resp = self.provider.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) authn = ' '.join(['Bearer', regresp['registration_access_token']]) query = '='.join(['client_id', regresp['client_id']]) resp = self.provider.read_registration(authn, query) assert json.loads(resp.message) == regresp.to_dict()
def test_registered_redirect_uri_faulty_with_query_component(self, uri): rr = RegistrationRequest( operation="register", redirect_uris=["http://example.org/cb?foo=bar"], response_types=["code"] ) registration_req = rr.to_json() resp = self.provider.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) cid = regresp["client_id"] areq = AuthorizationRequest(redirect_uri=uri, client_id=cid, scope="openid", response_type="code") with pytest.raises(RedirectURIError): self.provider._verify_redirect_uri(areq)
def test_registration_with_non_https(provider): redirect_uris = ["http://example.org"] registration_params = { "application_type": "web", "response_types": ["id_token", "token"], "redirect_uris": redirect_uris } req = RegistrationRequest(**registration_params) resp = provider.registration_endpoint(req.to_urlencoded()) resp = RegistrationResponse().from_json(resp.message) assert resp["client_id"] is not None assert resp["client_secret"] is not None assert resp["redirect_uris"] == redirect_uris
def registration_endpoint(self, request, authn=None, **kwargs): try: reg_req = RegistrationRequest().deserialize(request, "json") except ValueError: reg_req = RegistrationRequest().deserialize(request) self.events.store(EV_PROTOCOL_REQUEST, reg_req) try: response_type_cmp(kwargs['test_cnf']['response_type'], reg_req['response_types']) except KeyError: pass try: provider.Provider.verify_redirect_uris(reg_req) except InvalidRedirectURIError as err: return error( error="invalid_configuration_parameter", descr="Invalid redirect_uri: {}".format(err)) # Do initial verification that all endpoints from the client uses # https for endp in ["jwks_uri", "initiate_login_uri"]: try: uris = reg_req[endp] except KeyError: continue if not isinstance(uris, list): uris = [uris] for uri in uris: if not uri.startswith("https://"): return error( error="invalid_configuration_parameter", descr="Non-HTTPS endpoint in '{}'".format(endp)) _response = provider.Provider.registration_endpoint(self, request, authn, **kwargs) self.events.store(EV_HTTP_RESPONSE, _response) self.init_keys = [] if "jwks_uri" in reg_req: if _response.status == "200 OK": # find the client id req_resp = RegistrationResponse().from_json( _response.message) for kb in self.keyjar[req_resp["client_id"]]: if kb.imp_jwks: self.events.store("Client JWKS", kb.imp_jwks) return _response
def test_registration_request(self): req = RegistrationRequest(operation="register", default_max_age=10, require_auth_time=True, default_acr="foo", application_type="web", redirect_uris=[ "https://example.com/authz_cb"]) js = req.to_json() js_obj = json.loads(js) expected_js_obj = {"redirect_uris": ["https://example.com/authz_cb"], "application_type": "web", "default_acr": "foo", "require_auth_time": True, "operation": "register", "default_max_age": 10} assert js_obj == expected_js_obj assert query_string_compare(req.to_urlencoded(), "redirect_uris=https%3A%2F%2Fexample.com%2Fauthz_cb&application_type=web&default_acr=foo&require_auth_time=True&operation=register&default_max_age=10")
def test_registered_redirect_uri_with_query_component(self): provider2 = Provider("FOOP", {}, {}, None, None, None, None, "") rr = RegistrationRequest(operation="register", redirect_uris=["http://example.org/cb?foo=bar"], response_types=["code"]) registration_req = rr.to_json() resp = provider2.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) print regresp.to_dict() faulty = [ "http://example.org/cb", "http://example.org/cb/foo", "http://example.org/cb?got=you", "http://example.org/cb?foo=you" "http://example.org/cb?foo=bar&got=you", "http://example.org/cb?foo=you&foo=bar" ] correct = [ "http://example.org/cb?foo=bar", ] cid = regresp["client_id"] for ruri in faulty: areq = AuthorizationRequest(redirect_uri=ruri, client_id=cid, scope="openid", response_type="code") print areq try: provider2._verify_redirect_uri(areq) except RedirectURIError: pass for ruri in correct: areq = AuthorizationRequest(redirect_uri=ruri, client_id=cid, scope="openid", response_type="code") resp = provider2._verify_redirect_uri(areq) print resp assert resp is None
def test_registered_redirect_uri_with_query_component(self): provider2 = Provider("FOOP", {}, {}, None, None, None, None, "") rr = RegistrationRequest( operation="register", redirect_uris=["http://example.org/cb?foo=bar"], response_types=["code"]) registration_req = rr.to_json() resp = provider2.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) print regresp.to_dict() faulty = [ "http://example.org/cb", "http://example.org/cb/foo", "http://example.org/cb?got=you", "http://example.org/cb?foo=you" "http://example.org/cb?foo=bar&got=you", "http://example.org/cb?foo=you&foo=bar" ] correct = [ "http://example.org/cb?foo=bar", ] cid = regresp["client_id"] for ruri in faulty: areq = AuthorizationRequest(redirect_uri=ruri, client_id=cid, scope="openid", response_type="code") print areq try: provider2._verify_redirect_uri(areq) except RedirectURIError: pass for ruri in correct: areq = AuthorizationRequest(redirect_uri=ruri, client_id=cid, scope="openid", response_type="code") resp = provider2._verify_redirect_uri(areq) print resp assert resp is None
def _create_client(provider_metadata, client_metadata, verify_ssl=True): """ Create a pyoidc client instance. :param provider_metadata: provider configuration information :type provider_metadata: Mapping[str, Union[str, Sequence[str]]] :param client_metadata: client metadata :type client_metadata: Mapping[str, Union[str, Sequence[str]]] :return: client instance to use for communicating with the configured provider :rtype: oic.oic.Client """ client = oic.Client( client_authn_method=CLIENT_AUTHN_METHOD, verify_ssl=verify_ssl ) # Provider configuration information if "authorization_endpoint" in provider_metadata: # no dynamic discovery necessary client.handle_provider_config(ProviderConfigurationResponse(**provider_metadata), provider_metadata["issuer"]) else: # do dynamic discovery client.provider_config(provider_metadata["issuer"]) # Client information if "client_id" in client_metadata: # static client info provided client.store_registration_info(RegistrationRequest(**client_metadata)) else: # do dynamic registration client.register(client.provider_info['registration_endpoint'], **client_metadata) client.subject_type = (client.registration_response.get("subject_type") or client.provider_info["subject_types_supported"][0]) return client
def handle_client_registration_request(self, request, http_headers=None): # type: (Optional[str], Optional[Mapping[str, str]]) -> oic.oic.message.RegistrationResponse """ Handles a client registration request. :param request: JSON request from POST body :param http_headers: http headers """ registration_req = RegistrationRequest().deserialize(request, 'json') for validator in self.registration_request_validators: validator(registration_req) logger.debug('parsed authentication_request: %s', registration_req) client_id, client_secret = self._issue_new_client() credentials = { 'client_id': client_id, 'client_id_issued_at': int(time.time()), 'client_secret': client_secret, 'client_secret_expires_at': 0 # never expires } response_params = self.match_client_preferences_with_provider_capabilities( registration_req) response_params.update(credentials) self.clients[client_id] = copy.deepcopy(response_params) registration_resp = RegistrationResponse(**response_params) logger.debug('registration_resp=%s from registration_req=%s', registration_resp, registration_req) return registration_resp
def test_registration_request(self): req = RegistrationRequest(operation="register", default_max_age=10, require_auth_time=True, default_acr="foo", application_type="web", redirect_uris=[ "https://example.com/authz_cb"]) js = req.to_json() js_obj = json.loads(js) expected_js_obj = {"redirect_uris": ["https://example.com/authz_cb"], "application_type": "web", "default_acr": "foo", "require_auth_time": True, "operation": "register", "default_max_age": 10, "response_types": ["code"]} assert js_obj == expected_js_obj flattened_list_dict = {k: v[0] if isinstance(v, list) else v for k, v in expected_js_obj.items()} assert query_string_compare(req.to_urlencoded(), urlencode(flattened_list_dict))
def registration_endpoint(self, request, authn=None, **kwargs): logger.debug("@registration_endpoint: <<{}>>".format( sanitize(request))) if isinstance(request, dict): request = ClientMetadataStatement(**request) else: try: request = ClientMetadataStatement().deserialize( request, "json") except ValueError: request = ClientMetadataStatement().deserialize(request) logger.info("registration_request:{}".format( sanitize(request.to_dict()))) request_args = self.get_metadata_statement(request) request = RegistrationRequest(**request_args) result = self.client_registration_setup(request) if isinstance(result, Response): return result return Created(result.to_json(), content="application/json", headers=[("Cache-Control", "no-store")])
def test_verify_redirect_uris_with_https_code_flow(self): params = {"application_type": "web", "redirect_uris": ["http://example.com/authz"], "response_types": ["code"]} request = RegistrationRequest(**params) verified_uris = self.provider._verify_redirect_uris(request) assert verified_uris == [("http://example.com/authz", None)]
def test_registered_redirect_uri_without_query_component(self): provider = Provider("FOO", {}, {}, None, None, None, None, "") rr = RegistrationRequest(operation="register", redirect_uris=["http://example.org/cb"], response_types=["code"]) registration_req = rr.to_json() provider.registration_endpoint(request=registration_req) correct = [ "http://example.org/cb", "http://example.org/cb/foo", ] faulty = [ "http://example.org/foo", "http://example.com/cb", "http://example.org/cb?got=you", "http://example.org/cb/foo?got=you" ] cid = self._client_id(provider.cdb) for ruri in faulty: areq = AuthorizationRequest(redirect_uri=ruri, client_id=cid, response_type="code", scope="openid") print areq try: provider._verify_redirect_uri(areq) assert False except RedirectURIError: pass for ruri in correct: areq = AuthorizationRequest(redirect_uri=ruri, client_id=cid, response_type="code", scope="openid") print areq try: provider._verify_redirect_uri(areq) except RedirectURIError, err: print err assert False
def test_register_client(self): redirect_uri = "https://client.example.com" registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=["id_token"]) context = Context() context.request = registration_request.to_dict() registration_response = self.instance._register_client(context) assert registration_response.status == "201 Created" reg_resp = RegistrationResponse().deserialize(registration_response.message, "json") assert "client_id" in reg_resp assert reg_resp["client_id"] in self.instance.provider.cdb # no need to issue client secret since to token endpoint is published assert "client_secret" not in reg_resp assert reg_resp["redirect_uris"] == [redirect_uri] assert reg_resp["response_types"] == ["id_token"] assert reg_resp["id_token_signed_response_alg"] == "RS256"
def test_verify_redirect_uri_native_https(self): areq = RegistrationRequest(redirect_uris=["https://example.org/cb"], application_type='native') try: self.provider.verify_redirect_uris(areq) except InvalidRedirectURIError: assert True
def test_parse_registration_request(self): regreq = RegistrationRequest(contacts=["*****@*****.**"], redirect_uris=[ "http://example.org/jqauthz"], application_name="pacubar", client_id=CLIENT_ID, operation="register", application_type="web") request = self.srv.parse_registration_request( data=regreq.to_urlencoded()) assert isinstance(request, RegistrationRequest) assert _eq(request.keys(), ['redirect_uris', 'contacts', 'client_id', 'application_name', 'operation', 'application_type', 'response_types']) assert request["application_name"] == "pacubar" assert request["operation"] == "register"
def register(self, url, operation="register", application_type="web", **kwargs): req = RegistrationRequest(operation=operation, application_type=application_type) if operation == "update": req["client_id"] = self.client_id req["client_secret"] = self.client_secret for prop in req.parameters(): if prop in ["operation", "client_id", "client_secret"]: continue try: req[prop] = kwargs[prop] except KeyError: try: req[prop] = self.behaviour[prop] except KeyError: pass if "redirect_uris" not in req: try: req["redirect_uris"] = self.redirect_uris except AttributeError: raise MissingRequiredAttribute("redirect_uris") headers = {"content-type": "application/x-www-form-urlencoded"} if operation == "client_update": headers["Authorization"] = "Bearer %s" % self.registration_access_token rsp = self.http_request(url, "POST", data=req.to_urlencoded(), headers=headers) if rsp.status_code == 200: resp = RegistrationResponse().deserialize(rsp.text, "json") self.client_secret = resp["client_secret"] self.client_id = resp["client_id"] self.registration_expires = resp["expires_at"] self.registration_access_token = resp["registration_access_token"] else: err = ErrorResponse().deserialize(rsp.text, "json") raise Exception("Registration failed: %s" % err.get_json()) return resp
def test_registration_endpoint(self): req = RegistrationRequest() req["application_type"] = "web" req["client_name"] = "My super service" req["redirect_uris"] = ["http://example.com/authz"] req["contacts"] = ["*****@*****.**"] req["response_types"] = ["code"] resp = self.provider.registration_endpoint(request=req.to_json()) regresp = RegistrationResponse().deserialize(resp.message, "json") assert _eq(regresp.keys(), [ 'redirect_uris', 'contacts', 'application_type', 'client_name', 'registration_client_uri', 'client_secret_expires_at', 'registration_access_token', 'client_id', 'client_secret', 'client_id_issued_at', 'response_types' ])
def test_registered_redirect_uri_faulty_with_query_component(self, uri): rr = RegistrationRequest(operation="register", redirect_uris=[ "http://example.org/cb?foo=bar"], response_types=["code"]) registration_req = rr.to_json() resp = self.provider.registration_endpoint(request=registration_req) regresp = RegistrationResponse().from_json(resp.message) cid = regresp["client_id"] areq = AuthorizationRequest(redirect_uri=uri, client_id=cid, scope="openid", response_type="code") with pytest.raises(RedirectURIError): self.provider._verify_redirect_uri(areq)
def test_verify_sector_identifier_nonreachable(self): rr = RegistrationRequest(operation="register", sector_identifier_uri="https://example.com") with responses.RequestsMock() as rsps, LogCapture(level=logging.DEBUG) as logcap: rsps.add(rsps.GET, "https://example.com", status=404) message = "Couldn't open sector_identifier_uri" with pytest.raises(InvalidSectorIdentifier, message=message): self.provider._verify_sector_identifier(rr) assert len(logcap.records) == 0
def test_registration_endpoint(): server = provider_init req = RegistrationRequest(operation="register") req["application_type"] = "web" req["client_name"] = "My super service" req["redirect_uris"] = ["http://example.com/authz"] req["contacts"] = ["*****@*****.**"] environ = BASE_ENVIRON.copy() environ["QUERY_STRING"] = req.to_urlencoded() resp = server.registration_endpoint(environ, start_response) print resp regresp = RegistrationResponse().deserialize(resp[0], "json") print regresp.keys() assert _eq(regresp.keys(), ['redirect_uris', 'application_type', 'expires_at', 'registration_access_token', 'client_id', 'client_secret', 'client_name', "contacts"]) # --- UPDATE ---- req = RegistrationRequest(operation="client_update") req["application_type"] = "web" req["client_name"] = "My super duper service" req["redirect_uris"] = ["http://example.com/authz"] req["contacts"] = ["*****@*****.**"] environ = BASE_ENVIRON.copy() environ["QUERY_STRING"] = req.to_urlencoded() environ["HTTP_AUTHORIZATION"] = "Bearer %s" % regresp["registration_access_token"] resp = server.registration_endpoint(environ, start_response) print resp update = RegistrationResponse().deserialize(resp[0], "json") print update.keys() assert _eq(update.keys(), ['redirect_uris', 'application_type', 'expires_at', 'registration_access_token', 'client_id', 'client_secret', 'client_name', 'contacts'])
def test_registered_redirect_uri_with_query_component(): provider2 = Provider("FOOP", {}, {}, None, None) environ = {} rr = RegistrationRequest(operation="register", redirect_uris=["http://example.org/cb?foo=bar"]) registration_req = rr.to_urlencoded() resp = provider2.registration_endpoint(environ, start_response, query=registration_req) regresp = RegistrationResponse().from_json(resp[0]) print regresp.to_dict() faulty = [ "http://example.org/cb", "http://example.org/cb/foo", "http://example.org/cb?got=you", "http://example.org/cb?foo=you" ] correct = [ "http://example.org/cb?foo=bar", "http://example.org/cb?foo=bar&got=you", "http://example.org/cb?foo=bar&foo=you" ] for ruri in faulty: areq = AuthorizationRequest(redirect_uri=ruri, client_id=regresp["client_id"], scope="openid", response_type="code") print areq assert provider2._verify_redirect_uri(areq) != None for ruri in correct: areq = AuthorizationRequest(redirect_uri= ruri, client_id=regresp["client_id"]) resp = provider2._verify_redirect_uri(areq) print resp assert resp == None
def test_verify_redirect_uris_with_non_https_redirect_uri_implicit_flow(self): params = {"application_type": "web", "redirect_uris": ["http://example.com/authz"], "response_types": ["id_token", "token"]} request = RegistrationRequest(**params) with pytest.raises(InvalidRedirectURIError) as exc_info: self.provider._verify_redirect_uris(request) assert str(exc_info.value) == "None https redirect_uri not allowed"
def register(self, server, type="client_associate", **kwargs): req = RegistrationRequest(type=type) if type == "client_update" or type == "rotate_secret": req["client_id"] = self.client_id req["client_secret"] = self.client_secret for prop in req.parameters(): if prop in ["type", "client_id", "client_secret"]: continue try: val = getattr(self, prop) if val: req[prop] = val except Exception: val = None if not val: try: req[prop] = kwargs[prop] except KeyError: pass headers = {"content-type": "application/x-www-form-urlencoded"} rsp = self.http_request(server, "POST", data=req.to_urlencoded(), headers=headers) if rsp.status_code == 200: if type == "client_associate" or type == "rotate_secret": rr = RegistrationResponseCARS() else: rr = RegistrationResponseCU() resp = rr.deserialize(rsp.text, "json") self.client_secret = resp["client_secret"] self.client_id = resp["client_id"] self.registration_expires = resp["expires_at"] else: err = ErrorResponse().deserialize(rsp.text, "json") raise Exception("Registration failed: %s" % err.get_json()) return resp
def init_oidc_client(app): oidc_client = Client(client_authn_method=CLIENT_AUTHN_METHOD) oidc_client.store_registration_info(RegistrationRequest(**app.config['CLIENT_REGISTRATION_INFO'])) provider = app.config['PROVIDER_CONFIGURATION_INFO']['issuer'] try: oidc_client.provider_config(provider) except ConnectionError as e: app.logger.critical('No connection to provider {!s}. Can not start without provider configuration.'.format( provider)) raise e return oidc_client
def test_verify_sector_identifier_error(self): rr = RegistrationRequest(operation="register", sector_identifier_uri="https://example.com") error = ConnectionError('broken connection') with responses.RequestsMock() as rsps, LogCapture(level=logging.DEBUG) as logcap: rsps.add(rsps.GET, "https://example.com", body=error) with pytest.raises(InvalidSectorIdentifier, message="Couldn't open sector_identifier_uri"): self.provider._verify_sector_identifier(rr) assert len(logcap.records) == 2 # First log record is from server... assert logcap.records[1].msg == error
def l_registration_endpoint(self, request, authn=None, **kwargs): _log_debug = logger.debug _log_info = logger.info _log_debug("@registration_endpoint") request = RegistrationRequest().deserialize(request, "json") _log_info("registration_request:%s" % request.to_dict()) resp_keys = request.keys() try: request.verify() except MessageException, err: if "type" not in request: return self._error(error="invalid_type", descr="%s" % err) else: return self._error(error="invalid_configuration_parameter", descr="%s" % err)
def test_verify_sector_identifier_malformed(self): rr = RegistrationRequest(operation="register", sector_identifier_uri="https://example.com") body = "This is not the JSON you are looking for" with responses.RequestsMock() as rsps, LogCapture(level=logging.DEBUG) as logcap: rsps.add(rsps.GET, "https://example.com", body=body) with pytest.raises(InvalidSectorIdentifier, message="Error deserializing sector_identifier_uri content"): self.provider._verify_sector_identifier(rr) assert len(logcap.records) == 1 assert logcap.records[0].msg == "sector_identifier_uri => %s" assert logcap.records[0].args == (body,)
def test_dynamic_client(provider_info, browser): redirect_uri = "http://localhost" # Dynamic registration reg_req = RegistrationRequest(**{"redirect_uris": [redirect_uri], "response_types": ["id_token"]}) resp = requests.post(reg_req.request(provider_info["registration_endpoint"])) reg_resp = RegistrationResponse().from_json(resp.text) # Authentication auth_req = AuthorizationRequest( **{"client_id": reg_resp["client_id"], "scope": "openid", "response_type": "id_token", "redirect_uri": redirect_uri, "state": "state0", "nonce": "nonce0"}) browser.get(auth_req.request(provider_info["authorization_endpoint"])) fill_login_details(browser) # Authentication response urlencoded_resp = urlparse(browser.current_url).fragment auth_resp = AuthorizationResponse().from_urlencoded(urlencoded_resp) idt = IdToken().from_jwt(auth_resp["id_token"], verify=False) assert browser.current_url.startswith(redirect_uri) assert auth_resp["state"] == "state0" assert idt["nonce"] == "nonce0"
def test_registration_endpoint(self): req = RegistrationRequest() req["application_type"] = "web" req["client_name"] = "My super service" req["redirect_uris"] = ["http://example.com/authz"] req["contacts"] = ["*****@*****.**"] req["response_types"] = ["code"] print req.to_dict() resp = self.server.registration_endpoint(request=req.to_json()) print resp.message regresp = RegistrationResponse().deserialize(resp.message, "json") print regresp.keys() assert _eq(regresp.keys(), ['redirect_uris', 'contacts', 'application_type', 'client_name', 'registration_client_uri', 'client_secret_expires_at', 'registration_access_token', 'client_id', 'client_secret', 'client_id_issued_at', 'response_types'])
def registration_endpoint(self, request, authn=None, **kwargs): """ :param request: :param authn: :param kwargs: :return: """ logger.debug("@registration_endpoint: <<{}>>".format(sanitize(request))) if isinstance(request, dict): request = ClientMetadataStatement(**request) else: try: request = ClientMetadataStatement().deserialize(request, "json") except ValueError: request = ClientMetadataStatement().deserialize(request) try: request.verify() except Exception as err: return error('Invalid request') logger.info( "registration_request:{}".format(sanitize(request.to_dict()))) ms_list = self.federation_entity.get_metadata_statement(request, 'registration') if ms_list: ms = self.federation_entity.pick_by_priority(ms_list) self.federation = ms.fo else: # Nothing I can use return error(error='invalid_request', descr='No signed metadata statement I could use') request = RegistrationRequest(**ms.le) result = self.client_registration_setup(request) if isinstance(result, Response): return result # TODO This is where the OP should sign the response if ms.fo: _fo = ms.fo sms = self.signer.create_signed_metadata_statement( result, 'response', [_fo], single=True) self.federation_entity.extend_with_ms(result, {_fo: sms}) return Created(result.to_json(), content="application/json", headers=[("Cache-Control", "no-store")])