Beispiel #1
0
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)
Beispiel #2
0
    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))
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
 def test_code_exchange_request_without_offline_scope(self):
     self.provider.authz_state = AuthorizationState(
         HashBasedSubjectIdentifierFactory('salt'),
         refresh_token_lifetime=10,
         refresh_token_threshold=2)
     self.authorization_code_exchange_request_args[
         'code'] = self.create_authz_code()
     response = self.provider._do_code_exchange(
         self.authorization_code_exchange_request_args, None)
     assert 'refresh_token' not in response.keys()
Beispiel #6
0
 def test_refresh_request(self):
     self.provider.authz_state = AuthorizationState(
         HashBasedSubjectIdentifierFactory('salt'),
         refresh_token_lifetime=600)
     self.refresh_token_request_args[
         'refresh_token'] = self.create_refresh_token()
     response = self.provider.handle_token_request(
         urlencode(self.refresh_token_request_args))
     assert response[
         'access_token'] in self.provider.authz_state.access_tokens
     assert 'refresh_token' not in response
Beispiel #7
0
 def test_code_exchange_request_with_offline_scope_has_refresh_token(self):
     self.provider.authz_state = AuthorizationState(
         HashBasedSubjectIdentifierFactory('salt'),
         refresh_token_lifetime=10,
         refresh_token_threshold=2)
     scope_req = {'scope': 'openid offline_access'}
     self.authorization_code_exchange_request_args[
         'code'] = self.create_authz_code(extra_auth_req_params=scope_req)
     response = self.provider._do_code_exchange(
         self.authorization_code_exchange_request_args, None)
     assert 'refresh_token' in response.keys() and response[
         'refresh_token'] in self.provider.authz_state.refresh_tokens
Beispiel #8
0
 def test_refresh_request_without_scope_parameter_defaults_to_scope_from_authentication_request(
         self):
     self.provider.authz_state = AuthorizationState(
         HashBasedSubjectIdentifierFactory('salt'),
         refresh_token_lifetime=600)
     self.refresh_token_request_args[
         'refresh_token'] = self.create_refresh_token()
     del self.refresh_token_request_args['scope']
     response = self.provider.handle_token_request(
         urlencode(self.refresh_token_request_args))
     assert response[
         'access_token'] in self.provider.authz_state.access_tokens
     assert self.provider.authz_state.access_tokens[response[
         'access_token']]['scope'] == self.authn_request_args['scope']
def _init_authorization_state(provider_config, db_uri, sub_hash_salt):
    if db_uri:
        authz_code_db = StorageBase.from_uri(
            db_uri,
            db_name="satosa",
            collection="authz_codes",
            ttl=provider_config.get("authorization_code_lifetime", 600),
        )
        access_token_db = StorageBase.from_uri(
            db_uri,
            db_name="satosa",
            collection="access_tokens",
            ttl=provider_config.get("access_token_lifetime", 3600),
        )
        refresh_token_db = StorageBase.from_uri(
            db_uri,
            db_name="satosa",
            collection="refresh_tokens",
            ttl=provider_config.get("refresh_token_lifetime", None),
        )
        sub_db = StorageBase.from_uri(db_uri,
                                      db_name="satosa",
                                      collection="subject_identifiers",
                                      ttl=None)
    else:
        authz_code_db = None
        access_token_db = None
        refresh_token_db = None
        sub_db = None

    token_lifetimes = {
        k: provider_config[k]
        for k in [
            "authorization_code_lifetime",
            "access_token_lifetime",
            "refresh_token_lifetime",
            "refresh_token_threshold",
        ] if k in provider_config
    }
    return AuthorizationState(
        HashBasedSubjectIdentifierFactory(sub_hash_salt),
        authz_code_db,
        access_token_db,
        refresh_token_db,
        sub_db,
        **token_lifetimes,
    )
Beispiel #10
0
    def test_refresh_request_with_refresh_token_close_to_expiry_issues_new_refresh_token(
            self):
        self.provider.authz_state = AuthorizationState(
            HashBasedSubjectIdentifierFactory('salt'),
            refresh_token_lifetime=10,
            refresh_token_threshold=2)
        self.refresh_token_request_args[
            'refresh_token'] = self.create_refresh_token()

        close_to_expiration = int(
            time.time()) + self.provider.authz_state.refresh_token_lifetime - 1
        with patch('time.time', Mock(return_value=close_to_expiration)):
            response = self.provider.handle_token_request(
                urlencode(self.refresh_token_request_args))
        assert response[
            'access_token'] in self.provider.authz_state.access_tokens
        assert response[
            'refresh_token'] in self.provider.authz_state.refresh_tokens
Beispiel #11
0
 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)
Beispiel #12
0
 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)))
Beispiel #13
0
    def _init_authorization_state(self):
        sub_hash_salt = self.config.get("sub_hash_salt", rndstr(16))
        db_uri = self.config.get("db_uri")
        if db_uri:
            authz_code_db = MongoWrapper(db_uri, "satosa", "authz_codes")
            access_token_db = MongoWrapper(db_uri, "satosa", "access_tokens")
            refresh_token_db = MongoWrapper(db_uri, "satosa", "refresh_tokens")
            sub_db = MongoWrapper(db_uri, "satosa", "subject_identifiers")
        else:
            authz_code_db = None
            access_token_db = None
            refresh_token_db = None
            sub_db = None

        token_lifetimes = {k: self.config["provider"][k] for k in ["authorization_code_lifetime",
                                                                   "access_token_lifetime",
                                                                   "refresh_token_lifetime",
                                                                   "refresh_token_threshold"]
                           if k in self.config["provider"]}
        return AuthorizationState(HashBasedSubjectIdentifierFactory(sub_hash_salt), authz_code_db, access_token_db,
                                  refresh_token_db, sub_db, **token_lifetimes)
Beispiel #14
0
 def authorization_state_factory(self):
     return functools.partial(AuthorizationState, HashBasedSubjectIdentifierFactory('salt'))
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
Beispiel #16
0
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