From dc2ebc87dcc8d8e699c59f2e21eb53492e899d87 Mon Sep 17 00:00:00 2001 From: David Salvisberg Date: Thu, 19 Dec 2024 08:52:02 +0100 Subject: [PATCH] User: Adds scope setting to OIDC authentication provider TYPE: Feature LINK: OGC-1767 --- src/onegov/user/auth/clients/oidc.py | 7 ++++++- tests/onegov/user/test_oauth_oidc.py | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/onegov/user/auth/clients/oidc.py b/src/onegov/user/auth/clients/oidc.py index 0c042479f4..01adbc1297 100644 --- a/src/onegov/user/auth/clients/oidc.py +++ b/src/onegov/user/auth/clients/oidc.py @@ -73,6 +73,9 @@ class OIDCClient: primary: bool = attrib() + # Required OAuth scope in addition to "openid" + scope: list[str] = attrib(factory=list) + # Override/amend discovered metadata fixed_metadata: dict[str, Any] = attrib(factory=dict) @@ -84,12 +87,13 @@ def session( request: 'CoreRequest' ) -> OAuth2Session: """ Returns a requests session tied to a OAuth2 client """ + assert isinstance(self.scope, list), 'Invalid scope, expected list' provider_cls = type(provider) redirect_url = request.class_link( provider_cls, {'name': provider.name}, name='redirect') return OAuth2Session( self.client_id, - scope=['openid'], + scope=['openid', *self.scope], redirect_uri=redirect_url, ) @@ -206,6 +210,7 @@ def from_cfg(cls, config: dict[str, Any]) -> Self: issuer=cfg['issuer'], client_id=cfg['client_id'], client_secret=cfg['client_secret'], + scope=cfg.get('scope', []), attributes=OIDCAttributes.from_cfg( cfg.get('attributes', {}) ), diff --git a/tests/onegov/user/test_oauth_oidc.py b/tests/onegov/user/test_oauth_oidc.py index e105cf1b56..2328da8097 100644 --- a/tests/onegov/user/test_oauth_oidc.py +++ b/tests/onegov/user/test_oauth_oidc.py @@ -46,6 +46,9 @@ def configure_provider(app, metadata=None, primary=False): issuer: https://oidc.test/ client_id: test client_secret: secret + scope: + - profile + - email button_text: Login with OIDC fixed_metadata: {json.dumps(metadata or {})} roles: @@ -72,6 +75,7 @@ def test_oidc_configuration(app): assert client.attributes.last_name == 'family_name' assert client.attributes.preferred_username == 'preferred_username' assert client.primary is False + assert client.scope == ['profile', 'email'] assert provider.roles.app_specific(app) == { 'admins': 'ads', 'editors': 'eds', 'members': 'mems' @@ -93,6 +97,7 @@ def test_oidc_configuration_primary(app): assert client.attributes.last_name == 'family_name' assert client.attributes.preferred_username == 'preferred_username' assert client.primary is True + assert client.scope == ['profile', 'email'] assert provider.roles.app_specific(app) == { 'admins': 'ads', 'editors': 'eds', 'members': 'mems' @@ -181,7 +186,7 @@ def test_oicd_authenticate_request(app): location = response.headers['Location'] assert location.startswith('https://oidc.test/authorize') assert 'state=oauth_state' in location - assert 'scope=openid' in location + assert 'scope=openid+profile+email' in location assert browser_session['login_to'] == '/'