class TestOICProvider(object): def setup_class(self): self.server = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB, AUTHN_BROKER, USERINFO, AUTHZ, verify_client, SYMKEY, urlmap=URLMAP, keyjar=KEYJAR) 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.debug = True self.cons.keyjar[""] = KC_RSA def test_server_init(self): assert self.server assert self.server.authn_broker == AUTHN_BROKER print self.server.urlmap assert self.server.urlmap["client_1"] == ["https://example.com/authz"] def test_server_authorization_endpoint(self): bib = {"scope": ["openid"], "state": "id-6da9ca0cc23959f5f33e8becd9b08cae", "redirect_uri": "http://*****:*****@example.com"] 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 test_provider_key_setup(self): provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None, None, None, None, None, "") provider.baseurl = "http://www.example.com/" provider.key_setup("static", sig={"format": "jwk", "alg": "RSA"}) keys = provider.keyjar.get_signing_key("RSA") assert len(keys) == 1 assert provider.jwks_uri == "http://www.example.com/static/jwks" def _client_id(self, cdb): cid = None for k, item in cdb.items(): if item in cdb.keys(): cid = item break return cid 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
class TestProvider(object): @pytest.fixture(autouse=True) def create_provider(self, session_db_factory): self.provider = Provider(SERVER_INFO["issuer"], session_db_factory(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_providerinfo(self): self.provider.baseurl = 'http://example.com/path1/path2' resp = self.provider.create_providerinfo() assert resp.to_dict( )['authorization_endpoint'] == 'http://example.com/path1/path2/authorization' def test_providerinfo_trailing(self): self.provider.baseurl = 'http://example.com/path1/path2/' resp = self.provider.create_providerinfo() assert resp.to_dict( )['authorization_endpoint'] == 'http://example.com/path1/path2/authorization' def test_authorization_endpoint(self): bib = { "scope": ["openid"], "state": "id-6da9ca0cc23959f5f33e8becd9b08cae", "redirect_uri": "http://*****:*****@patch('oic.oic.provider.utc_time_sans_frac', Mock(return_value=123456)) def test_client_secret_expiration_time(self): exp_time = self.provider.client_secret_expiration_time() assert exp_time == 209856 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_registration_endpoint_unicode(self): data = 'application_type=web&client_name=M%C3%A1+supe%C5%99+service&' \ 'redirect_uris=http%3A%2F%2Fexample.com%2Fauthz&response_types=code' resp = self.provider.registration_endpoint(request=data) regresp = RegistrationResponse().deserialize(resp.message, "json") assert _eq(regresp.keys(), [ 'redirect_uris', '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" def test_provider_key_setup(self, tmpdir, session_db_factory): path = tmpdir.strpath provider = Provider("pyoicserv", session_db_factory(SERVER_INFO["issuer"]), None, 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", ]) 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_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_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 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_verify_sector_identifier_ru_missing_in_si(self): """Redirect_uris is not present in the sector_identifier_uri content.""" rr = RegistrationRequest(operation="register", sector_identifier_uri="https://example.com", redirect_uris=["http://example.com/missing"]) with responses.RequestsMock() as rsps, LogCapture( level=logging.DEBUG) as logcap: rsps.add(rsps.GET, "https://example.com", body=json.dumps(["http://example.com/present"])) with pytest.raises( InvalidSectorIdentifier, message="redirect uri missing from sector_identifiers"): self.provider._verify_sector_identifier(rr) assert len(logcap.records) == 2 assert logcap.records[0].msg == "sector_identifier_uri => %s" assert logcap.records[0].args == ('["http://example.com/present"]', ) assert logcap.records[1].msg == "redirect_uris: %s" assert logcap.records[1].args == (["http://example.com/missing"], ) def test_verify_sector_identifier_ru_missing(self): """Redirect_uris is not present in the request.""" rr = RegistrationRequest(operation="register", sector_identifier_uri="https://example.com") redirects = ["http://example.com/present"] with responses.RequestsMock() as rsps, LogCapture( level=logging.DEBUG) as logcap: rsps.add(rsps.GET, "https://example.com", body=json.dumps(redirects)) si_redirects, si_url = self.provider._verify_sector_identifier(rr) assert si_url == "https://example.com" assert si_redirects == redirects assert len(logcap.records) == 1 assert logcap.records[0].msg == "sector_identifier_uri => %s" assert logcap.records[0].args == ('["http://example.com/present"]', ) def test_verify_sector_identifier_ru_ok(self): """Redirect_uris is present in the sector_identifier_uri content.""" rr = RegistrationRequest(operation="register", sector_identifier_uri="https://example.com", redirect_uris=["http://example.com/present"]) redirects = ["http://example.com/present"] with responses.RequestsMock() as rsps, LogCapture( level=logging.DEBUG) as logcap: rsps.add(rsps.GET, "https://example.com", body=json.dumps(redirects)) si_redirects, si_url = self.provider._verify_sector_identifier(rr) assert si_url == "https://example.com" assert si_redirects == redirects assert len(logcap.records) == 2 assert logcap.records[0].msg == "sector_identifier_uri => %s" assert logcap.records[0].args == ('["http://example.com/present"]', ) assert logcap.records[1].msg == "redirect_uris: %s" assert logcap.records[1].args == (["http://example.com/present"], ) @pytest.mark.parametrize("uri", [ "http://example.org/cb", "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_verify_redirect_uri_native_http_localhost(self): areq = RegistrationRequest(redirect_uris=["http://localhost/cb"], application_type='native') self.provider.verify_redirect_uris(areq) def test_verify_redirect_uri_native_loopback(self): areq = RegistrationRequest(redirect_uris=["http://127.0.0.1/cb"], application_type='native') self.provider.verify_redirect_uris(areq) def test_verify_redirect_uri_native_http_non_localhost(self): areq = RegistrationRequest(redirect_uris=["http://example.org/cb"], application_type='native') try: self.provider.verify_redirect_uris(areq) except InvalidRedirectURIError: assert True def test_verify_redirect_uri_native_custom(self): areq = RegistrationRequest( redirect_uris=["com.example.app:/oauth2redirect"], application_type='native') self.provider.verify_redirect_uris(areq) 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_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_wrong_authn(self): resp = self.provider.read_registration('wrong string', 'request') assert resp.status == '400 Bad Request' assert json.loads(resp.message) == { 'error': 'invalid_request', 'error_description': None } def test_key_rollover(self): provider2 = Provider("FOOP", {}, {}, None, 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, SeeOther) 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, session_db_factory): provider = Provider(SERVER_INFO["issuer"], session_db_factory(SERVER_INFO["issuer"]), CDB, AUTHN_BROKER, USERINFO, AUTHZ, verify_client, SYMKEY, urlmap=URLMAP, keyjar=KEYJAR) provider.capabilities.update( {"check_session_iframe": "https://op.example.com/check_session"}) req_args = { "scope": ["openid"], "redirect_uri": "http://localhost:8087/authz", "response_type": ["code"], "client_id": "number5" } 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() try: cookies_string = cookies_string.decode() except (AttributeError, UnicodeDecodeError): pass all_cookies.load(cookies_string) now = datetime.datetime.utcnow() # 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"] def test_id_token_RS512_sign(self): self.provider.capabilities['id_token_signing_alg_values_supported'] = [ 'RS512' ] self.provider.build_jwx_def() id_token = self._auth_with_id_token() assert id_token.jws_header['alg'] == "RS512" def test_refresh_access_token_request(self): authreq = AuthorizationRequest(state="state", redirect_uri="http://example.com/authz", client_id=CLIENT_ID, response_type="code", scope=["openid", 'offline_access'], prompt='consent') _sdb = self.provider.sdb sid = _sdb.access_token.key(user="******", areq=authreq) access_grant = _sdb.access_token(sid=sid) ae = AuthnEvent("user", "salt") _sdb[sid] = { "oauth_state": "authz", "authn_event": ae.to_json(), "authzreq": authreq.to_json(), "client_id": CLIENT_ID, "code": access_grant, "code_used": False, "scope": ["openid", 'offline_access'], "redirect_uri": "http://example.com/authz", } _sdb.do_sub(sid, "client_salt") # Construct Access token request areq = AccessTokenRequest(code=access_grant, client_id=CLIENT_ID, redirect_uri="http://example.com/authz", client_secret=CLIENT_SECRET, grant_type='authorization_code') txt = areq.to_urlencoded() resp = self.provider.token_endpoint(request=txt) atr = AccessTokenResponse().deserialize(resp.message, "json") rareq = RefreshAccessTokenRequest(grant_type="refresh_token", refresh_token=atr['refresh_token'], client_id=CLIENT_ID, client_secret=CLIENT_SECRET, scope=['openid']) resp = self.provider.token_endpoint(request=rareq.to_urlencoded()) atr2 = AccessTokenResponse().deserialize(resp.message, "json") assert atr2['access_token'] != atr['access_token'] assert atr2['refresh_token'] == atr['refresh_token'] assert atr2['token_type'] == 'Bearer'
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"]
class TestOICProvider(object): def setup_class(self): self.server = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB, AUTHN_BROKER, USERINFO, AUTHZ, verify_client, SYMKEY, urlmap=URLMAP, keyjar=KEYJAR) 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.debug = True self.cons.keyjar[""] = KC_RSA def test_server_init(self): assert self.server assert self.server.authn_broker == AUTHN_BROKER print self.server.urlmap assert self.server.urlmap["client_1"] == ["https://example.com/authz"] def test_server_authorization_endpoint(self): bib = { "scope": ["openid"], "state": "id-6da9ca0cc23959f5f33e8becd9b08cae", "redirect_uri": "http://*****:*****@example.com"] 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 test_provider_key_setup(self): provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None, None, None, None, None, "") provider.baseurl = "http://www.example.com/" provider.key_setup("static", sig={"format": "jwk", "alg": "RSA"}) keys = provider.keyjar.get_signing_key("RSA") assert len(keys) == 1 assert provider.jwks_uri == "http://www.example.com/static/jwks" def _client_id(self, cdb): cid = None for k, item in cdb.items(): if item in cdb.keys(): cid = item break return cid 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