class TestProvider(object): @pytest.fixture(autouse=True) def create_provider(self): self.provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB, AUTHN_BROKER, USERINFO, AUTHZ, verify_client, SYMKEY, urlmap=URLMAP, keyjar=KEYJAR) self.provider.baseurl = self.provider.name self.cons = Consumer({}, CONSUMER_CONFIG, CLIENT_CONFIG, server_info=SERVER_INFO, ) self.cons.behaviour = { "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]} self.cons.keyjar[""] = KC_RSA def test_authorization_endpoint(self): bib = {"scope": ["openid"], "state": "id-6da9ca0cc23959f5f33e8becd9b08cae", "redirect_uri": "http://*****:*****@example.com"] 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_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_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_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" @pytest.mark.network 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 test_provider_key_setup(self, tmpdir): path = tmpdir.strpath provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None, None, None, None, None, "") provider.baseurl = "http://www.example.com" provider.key_setup(path, path, sig={"format": "jwk", "alg": "RSA"}) keys = provider.keyjar.get_signing_key("RSA") assert len(keys) == 1 assert provider.jwks_uri == "http://www.example.com/{}/jwks".format( path) @pytest.mark.parametrize("uri", [ "http://example.org/foo", "http://example.com/cb", "http://example.org/cb?got=you", "http://example.org/cb/foo?got=you" ]) def test_verify_redirect_uri_faulty_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") with pytest.raises(RedirectURIError): self.provider._verify_redirect_uri(areq) @pytest.mark.parametrize("uri", [ "http://example.org/cb", "http://example.org/cb/foo" ]) 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) @pytest.mark.parametrize("uri", [ "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" ]) 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_registered_redirect_uri_correct_with_query_component(self): 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="http://example.org/cb?foo=bar", client_id=cid, scope="openid", response_type="code") self.provider._verify_redirect_uri(areq) def test_key_rollover(self): provider2 = Provider("FOOP", {}, {}, None, None, None, None, "") provider2.keyjar = KEYJAR # Number of KeyBundles assert len(provider2.keyjar.issuer_keys[""]) == 1 kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]}) provider2.do_key_rollover(json.loads(kb.jwks()), "b%d") assert len(provider2.keyjar.issuer_keys[""]) == 2 kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]}) provider2.do_key_rollover(json.loads(kb.jwks()), "b%d") assert len(provider2.keyjar.issuer_keys[""]) == 3 provider2.remove_inactive_keys(-1) assert len(provider2.keyjar.issuer_keys[""]) == 2 def test_endsession_endpoint(self): resp = self.provider.endsession_endpoint("") self._assert_cookies_expired(resp.headers) # End session not allowed if no cookie is sent (can't determine session) resp = self.provider.endsession_endpoint("", cookie="FAIL") assert resp.status == "400 Bad Request" def test_endsession_endpoint_with_id_token_hint(self): id_token = self._auth_with_id_token() assert self.provider.sdb.get_sids_by_sub( id_token["sub"]) # verify we got valid session id_token_hint = id_token.to_jwt(algorithm="none") resp = self.provider.endsession_endpoint( urlencode({"id_token_hint": id_token_hint})) assert not self.provider.sdb.get_sids_by_sub( id_token["sub"]) # verify session has been removed self._assert_cookies_expired(resp.headers) def test_endsession_endpoint_with_post_logout_redirect_uri(self): id_token = self._auth_with_id_token() assert self.provider.sdb.get_sids_by_sub( id_token["sub"]) # verify we got valid session post_logout_redirect_uri = \ CDB[CLIENT_CONFIG["client_id"]]["post_logout_redirect_uris"][0][0] resp = self.provider.endsession_endpoint(urlencode( {"post_logout_redirect_uri": post_logout_redirect_uri})) assert isinstance(resp, Redirect) assert not self.provider.sdb.get_sids_by_sub( id_token["sub"]) # verify session has been removed self._assert_cookies_expired(resp.headers) def test_session_state_in_auth_req_for_session_support(self): provider = Provider("foo", SessionDB(SERVER_INFO["issuer"]), CDB, AUTHN_BROKER, USERINFO, AUTHZ, verify_client, SYMKEY, urlmap=URLMAP, keyjar=KEYJAR, capabilities={ "check_session_iframe": "https://op.example.com/check_session"}) req_args = {"scope": ["openid"], "redirect_uri": "http://localhost:8087/authz", "response_type": ["code"], "client_id": "a1b2c3" } areq = AuthorizationRequest(**req_args) resp = provider.authorization_endpoint( request=areq.to_urlencoded()) aresp = self.cons.parse_response(AuthorizationResponse, resp.message, sformat="urlencoded") assert "session_state" in aresp def _assert_cookies_expired(self, http_headers): cookies_string = ";".join( [c[1] for c in http_headers if c[0] == "Set-Cookie"]) all_cookies = SimpleCookie() all_cookies.load(cookies_string) now = datetime.datetime.now() for c in [self.provider.cookie_name, self.provider.session_cookie_name]: dt = datetime.datetime.strptime(all_cookies[c]["expires"], "%a, %d-%b-%Y %H:%M:%S GMT") assert dt < now # make sure the cookies have expired to be cleared def _auth_with_id_token(self): state, location = self.cons.begin("openid", "id_token", path="http://localhost:8087") resp = self.provider.authorization_endpoint( request=location.split("?")[1]) aresp = self.cons.parse_response(AuthorizationResponse, resp.message, sformat="urlencoded") return aresp["id_token"]