def init_oidc_provider(app): with app.app_context(): issuer = url_for('oidc_provider.index')[:-1] authentication_endpoint = url_for('oidc_provider.authentication_endpoint') jwks_uri = url_for('oidc_provider.jwks_uri') token_endpoint = url_for('oidc_provider.token_endpoint') userinfo_endpoint = url_for('oidc_provider.userinfo_endpoint') registration_endpoint = url_for('oidc_provider.registration_endpoint') end_session_endpoint = url_for('oidc_provider.end_session_endpoint') userinfo_ldap = LdapUserInfo() configuration_information = { 'issuer': issuer, 'authorization_endpoint': authentication_endpoint, 'jwks_uri': jwks_uri, 'token_endpoint': token_endpoint, 'userinfo_endpoint': userinfo_endpoint, 'registration_endpoint': registration_endpoint, 'end_session_endpoint': end_session_endpoint, 'scopes_supported': ['openid', 'profile'], 'response_types_supported': ['code', 'code id_token', 'code token', 'code id_token token'], # code and hybrid 'response_modes_supported': ['query', 'fragment'], 'grant_types_supported': ['authorization_code', 'implicit'], 'subject_types_supported': ['pairwise'], 'token_endpoint_auth_methods_supported': ['client_secret_basic'], 'claims_parameter_supported': True } signing_key = RSAKey(key=rsa_load('signing_key.pem'), alg='RS256') provider = Provider(signing_key, configuration_information, AuthorizationState(HashBasedSubjectIdentifierFactory(app.config['SUBJECT_ID_HASH_SALT'])), {}, userinfo_ldap) return provider
def test_rejects_mismatching_request(self, client_preference, provider_capability, client_value, provider_value): request = {'redirect_uris': ['https://client.example.com/redirect']} provider_capabilities = provide_configuration() if client_preference.startswith( ('request_object_encryption', 'id_token_encrypted', 'userinfo_encrypted')): # provide default value for the metadata params that come in pairs param = client_preference[:-4] alg_param = param + '_alg' request[alg_param] = 'RSA-OAEP' provider_capabilities[PREFERENCE2PROVIDER[alg_param]] = [ 'RSA-OAEP' ] enc_param = param + '_enc' request[enc_param] = 'A192CBC-HS256' provider_capabilities[PREFERENCE2PROVIDER[enc_param]] = [ 'A192CBC-HS256' ] request[client_preference] = client_value provider_capabilities[provider_capability] = provider_value provider = Provider( rsa_key(), provider_capabilities, AuthorizationState(HashBasedSubjectIdentifierFactory('salt')), {}, None) with pytest.raises(InvalidClientRegistrationRequest): provider.handle_client_registration_request(json.dumps(request))
def inject_provider(request): clients = { TEST_CLIENT_ID: { 'subject_type': 'pairwise', 'redirect_uris': [TEST_REDIRECT_URI], 'response_types': ['code'], 'client_secret': TEST_CLIENT_SECRET, 'token_endpoint_auth_method': 'client_secret_post', 'post_logout_redirect_uris': ['https://client.example.com/post_logout'] } } userinfo = Userinfo({ TEST_USER_ID: { 'name': 'The T. Tester', 'family_name': 'Tester', 'given_name': 'The', 'middle_name': 'Theodore', 'nickname': 'testster', 'email': '*****@*****.**', } }) request.instance.provider = Provider( rsa_key(), {'issuer': ISSUER}, AuthorizationState(HashBasedSubjectIdentifierFactory('salt')), clients, userinfo)
def _create_provider(self, endpoint_baseurl): response_types_supported = self.config["provider"].get("response_types_supported", ["id_token"]) subject_types_supported = self.config["provider"].get("subject_types_supported", ["pairwise"]) scopes_supported = self.config["provider"].get("scopes_supported", ["openid"]) capabilities = { "issuer": self.base_url, "authorization_endpoint": "{}/{}".format(endpoint_baseurl, AuthorizationEndpoint.url), "jwks_uri": "{}/jwks".format(endpoint_baseurl), "response_types_supported": response_types_supported, "id_token_signing_alg_values_supported": [self.signing_key.alg], "response_modes_supported": ["fragment", "query"], "subject_types_supported": subject_types_supported, "claim_types_supported": ["normal"], "claims_parameter_supported": True, "claims_supported": [attribute_map["openid"][0] for attribute_map in self.internal_attributes["attributes"].values() if "openid" in attribute_map], "request_parameter_supported": False, "request_uri_parameter_supported": False, "scopes_supported": scopes_supported } if self.config["provider"].get("client_registration_supported", False): capabilities["registration_endpoint"] = "{}/{}".format(endpoint_baseurl, RegistrationEndpoint.url) authz_state = self._init_authorization_state() db_uri = self.config.get("db_uri") cdb = MongoWrapper(db_uri, "satosa", "clients") if db_uri else {} self.user_db = MongoWrapper(db_uri, "satosa", "authz_codes") if db_uri else {} self.provider = Provider(self.signing_key, capabilities, authz_state, cdb, Userinfo(self.user_db))
def init_oidc_provider(app): with app.app_context(): issuer = url_for("oidc_provider.index")[:-1] authentication_endpoint = url_for("oidc_provider.authentication_endpoint") jwks_uri = url_for("oidc_provider.jwks_uri") token_endpoint = url_for("oidc_provider.token_endpoint") userinfo_endpoint = url_for("oidc_provider.userinfo_endpoint") registration_endpoint = url_for("oidc_provider.registration_endpoint") end_session_endpoint = url_for("oidc_provider.end_session_endpoint") configuration_information = { "issuer": issuer, "authorization_endpoint": authentication_endpoint, "jwks_uri": jwks_uri, "token_endpoint": token_endpoint, "userinfo_endpoint": userinfo_endpoint, "registration_endpoint": registration_endpoint, "end_session_endpoint": end_session_endpoint, "scopes_supported": ["openid", "profile"], "response_types_supported": [ "code", "code id_token", "code token", "code id_token token", ], # code and hybrid "response_modes_supported": ["query", "fragment"], "grant_types_supported": ["authorization_code", "implicit"], "subject_types_supported": ["pairwise"], "token_endpoint_auth_methods_supported": [ "client_secret_post", "client_secret_basic", ], "claims_parameter_supported": True, } clients = { "sample": { "client_secret": "sample", "redirect_uris": ["http://localhost:5000/test_auth_callback",], "response_types": ["code"], } } userinfo_db = Userinfo(app.users) signing_key = RSAKey(key=rsa_load("signing_key.pem"), alg="RS256") provider = Provider( signing_key, configuration_information, AuthorizationState( HashBasedSubjectIdentifierFactory(app.config["SUBJECT_ID_HASH_SALT"]) ), clients, userinfo_db, ) return provider
def test_matches_common_set_of_metadata_values(self, client_preference, provider_capability, client_value, provider_value): provider_capabilities = provide_configuration() provider_capabilities.update({provider_capability: provider_value}) provider = Provider( rsa_key(), provider_capabilities, AuthorizationState(HashBasedSubjectIdentifierFactory('salt')), {}, None) request = { 'redirect_uris': ['https://client.example.com/redirect'], client_preference: client_value } response = provider.handle_client_registration_request( json.dumps(request)) expected_values = set(client_value).intersection(provider_value) assert Counter(frozenset(v.split()) for v in response[client_preference]) == \ Counter(frozenset(v.split()) for v in expected_values)
def plugin_enable(self) -> None: # pylint: disable=attribute-defined-outside-init self.signing_key = RSAKey(key=rsa_load("signing_key.pem"), use="sig", alg="RS256") # pylint: disable=attribute-defined-outside-init self.oidc_configuration_information = { "issuer": self.app.config["URL_BASE"].replace("http://", "https://"), "authorization_endpoint": self.app.config["URL_BASE"] + "/oidc/authorization", "jwks_uri": self.app.config["URL_BASE"] + "/oidc/jwks", "token_endpoint": self.app.config["URL_BASE"] + "/oidc/token", "userinfo_endpoint": self.app.config["URL_BASE"] + "/oidc/userinfo", "response_types_supported": ["code"], "id_token_signing_alg_values_supported": [self.signing_key.alg], "response_modes_supported": ["fragment", "query"], "subject_types_supported": ["public", "pairwise"], "grant_types_supported": ["authorization_code", "implicit"], "claim_types_supported": ["normal"], "claims_parameter_supported": True, "claims_supported": ["sub", "name", "given_name", "family_name", "email", "profile"], "scopes_supported": ["openid", "email", "profile"] } subject_id_factory = HashBasedSubjectIdentifierFactory( self.app.config["SECRET_KEY"]) # pylint: disable=attribute-defined-outside-init self.provider = Provider( self.signing_key, self.oidc_configuration_information, AuthorizationState( subject_id_factory, SQLWrapper(self.storage, 'authz_codes'), SQLWrapper(self.storage, 'access_tokens'), SQLWrapper(self.storage, 'refresh_tokens'), SQLWrapper(self.storage, 'subject_identifiers', True), ), SQLWrapper(self.storage, 'clients'), Userinfo(PersonWrapper(self.storage)))
def _create_provider( provider_config, endpoint_baseurl, internal_attributes, signing_key, authz_state, user_db, cdb, ): response_types_supported = provider_config.get("response_types_supported", ["id_token"]) subject_types_supported = provider_config.get("subject_types_supported", ["pairwise"]) scopes_supported = provider_config.get("scopes_supported", ["openid"]) extra_scopes = provider_config.get("extra_scopes") capabilities = { "issuer": provider_config["issuer"], "authorization_endpoint": "{}/{}".format(endpoint_baseurl, AuthorizationEndpoint.url), "jwks_uri": "{}/jwks".format(endpoint_baseurl), "response_types_supported": response_types_supported, "id_token_signing_alg_values_supported": [signing_key.alg], "response_modes_supported": ["fragment", "query"], "subject_types_supported": subject_types_supported, "claim_types_supported": ["normal"], "claims_parameter_supported": True, "claims_supported": [ attribute_map["openid"][0] for attribute_map in internal_attributes["attributes"].values() if "openid" in attribute_map ], "request_parameter_supported": False, "request_uri_parameter_supported": False, "scopes_supported": scopes_supported } if 'code' in response_types_supported: capabilities["token_endpoint"] = "{}/{}".format( endpoint_baseurl, TokenEndpoint.url) if provider_config.get("client_registration_supported", False): capabilities["registration_endpoint"] = "{}/{}".format( endpoint_baseurl, RegistrationEndpoint.url) provider = Provider( signing_key, capabilities, authz_state, cdb, Userinfo(user_db), extra_scopes=extra_scopes, id_token_lifetime=provider_config.get("id_token_lifetime", 3600), ) return provider
def test_jwks(self): provider = Provider(rsa_key(), provide_configuration(), None, None, None) assert provider.jwks == {'keys': [provider.signing_key.serialize()]}
def test_provider_configuration(self): config = provide_configuration() config.update({'foo': 'bar', 'abc': 'xyz'}) provider = Provider(None, config, None, None, None) provider_config = provider.provider_configuration assert all(k in provider_config for k in config)
def test_jwks(self): provider = Provider(rsa_key(), {'issuer': ISSUER}, None, None, None) assert provider.jwks == {'keys': [provider.signing_key.serialize()]}
def test_provider_configuration(self): config = {'issuer': ISSUER, 'foo': 'bar', 'abc': 'xyz'} provider = Provider(None, config, None, None, None) provider_config = provider.provider_configuration assert all(k in provider_config for k in config)
def init_oidc_provider(app): with app.app_context(): config = { 'issuer': app.config['OIDC_PROVIDER']['issuer'], 'authorization_endpoint': url_for('oidc_provider.auth'), 'jwks_uri': url_for('oidc_provider.jwks'), 'token_endpoint': url_for('oidc_provider.token'), 'userinfo_endpoint': url_for('oidc_provider.userinfo'), 'registration_endpoint': url_for('oidc_provider.register'), 'end_session_endpoint': url_for('oidc_provider.logout'), 'scopes_supported': ['openid', 'profile'], 'response_types_supported': ['code', 'code id_token', 'code token', 'code id_token token'], 'response_modes_supported': ['query', 'fragment'], 'grant_types_supported': ['authorization_code', 'implicit'], 'subject_types_supported': ['pairwise'], 'token_endpoint_auth_methods_supported': ['client_secret_basic'], 'claims_parameter_supported': True } userinfo_db = Userinfo() signing_key = RSAKey(key=rsa_load('signing_key.pem'), alg='RS256') authz_state = AuthorizationState( HashBasedSubjectIdentifierFactory( app.config['OIDC_PROVIDER']['subject_id_hash_salt'])) clients = { 'notify-test': { 'client_name': 'GOV.UK Notify', 'client_secret': 'notify-secret', 'client_uri': 'https://admin-ags.notify.works/', 'post_logout_redirect_uris': [ 'https://admin-ags.notify.works/sign-out', 'http://localhost:6012/sign-out', ], 'redirect_uris': [ 'https://admin-ags.notify.works/oidc_callback', 'http://localhost:6012/oidc_callback', ], 'response_types': [ 'code', ], }, 'test-client': { 'client_name': 'Test', 'client_secret': 'test-secret', 'post_logout_redirect_uris': [ 'http://example.com/sign-out', 'https://sue-my-brother.cloudapps.digital/sign-out', ], 'redirect_uris': [ 'http://example.com/oidc_callback', 'https://sue-my-brother.cloudapps.digital/oidc_callback', ], 'response_types': [ 'code', ], }, } provider = Provider(signing_key, config, authz_state, clients, userinfo_db) return provider
def init_oidc_provider(app): with app.app_context(): issuer = url_for("oidc_provider.index")[:-1] authentication_endpoint = url_for( "oidc_provider.authentication_endpoint") jwks_uri = url_for("oidc_provider.jwks_uri") token_endpoint = url_for("oidc_provider.token_endpoint") userinfo_endpoint = url_for("oidc_provider.userinfo_endpoint") registration_endpoint = url_for("oidc_provider.registration_endpoint") end_session_endpoint = url_for("oidc_provider.end_session_endpoint") configuration_information = { "issuer": issuer, "authorization_endpoint": authentication_endpoint, "jwks_uri": jwks_uri, "token_endpoint": token_endpoint, "userinfo_endpoint": userinfo_endpoint, "registration_endpoint": registration_endpoint, "end_session_endpoint": end_session_endpoint, "scopes_supported": app.config["OIDC_SCOPES_SUPPORTED"], "response_types_supported": app.config["OIDC_RESPONSE_TYPES_SUPPORTED"], "response_modes_supported": app.config["OIDC_RESPONSE_MODES_SUPPORTED"], "grant_types_supported": app.config["OIDC_GRANT_TYPES_SUPPORTED"], "subject_types_supported": app.config["OIDC_SUBJECT_TYPE_SUPPORTED"], "token_endpoint_auth_methods_supported": app.config["OIDC_TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED"], "userinfo_signing_alg_values_supported": app.config["OIDC_USERINFO_SIGNING_ALG_VALUES_SUPPORTED"], "claims_parameter_supported": app.config["OIDC_CLAIMS_PARAMETER_SUPPORTED"], "claims_supported": app.config["OIDC_CLAIMS_SUPPORTED"], } userinfo_db = Userinfo(app.sql_backend) signing_key = RSAKey(key=rsa_load(app.config["SIGNING_KEY_FILE"]), alg=app.config["SIGNING_KEY_ALG"], kid=app.config["SIGNING_KEY_ID"]) provider = Provider( signing_key, configuration_information, AuthorizationState( HashBasedSubjectIdentifierFactory( app.config["SUBJECT_ID_HASH_SALT"])), ClientRPSQLWrapper(), userinfo_db, ) return provider