diff --git a/auth_oidc/controllers/main.py b/auth_oidc/controllers/main.py index 2104a6cca0..5755491dda 100644 --- a/auth_oidc/controllers/main.py +++ b/auth_oidc/controllers/main.py @@ -6,6 +6,7 @@ import hashlib import logging import secrets +from ast import literal_eval from werkzeug.urls import url_decode, url_encode @@ -43,6 +44,12 @@ def list_providers(self): if "openid" not in provider["scope"].split(): _logger.error("openid connect scope must contain 'openid'") params["scope"] = provider["scope"] + + # append provider specific auth link params + if provider["auth_link_params"]: + params_upd = literal_eval(provider["auth_link_params"]) + params.update(params_upd) + # auth link that the user will click provider["auth_link"] = "{}?{}".format( provider["auth_endpoint"], url_encode(params) diff --git a/auth_oidc/data/auth_oauth_data.xml b/auth_oidc/data/auth_oauth_data.xml index bdeea59a5c..a095b22307 100644 --- a/auth_oidc/data/auth_oauth_data.xml +++ b/auth_oidc/data/auth_oauth_data.xml @@ -17,6 +17,7 @@ >https://login.microsoftonline.com/organizations/discovery/v2.0/keys fa fa-fw fa-windows Log in with Microsoft + {'prompt':'select_account'} Azure AD Single Tenant @@ -35,5 +36,6 @@ >https://login.microsoftonline.com/{tenant_id}/discovery/v2.0/keys fa fa-fw fa-windows Log in with Microsoft + {'prompt':'select_account'} diff --git a/auth_oidc/demo/local_keycloak.xml b/auth_oidc/demo/local_keycloak.xml index 919754db99..0362764014 100644 --- a/auth_oidc/demo/local_keycloak.xml +++ b/auth_oidc/demo/local_keycloak.xml @@ -17,4 +17,24 @@ name="jwks_uri" >http://localhost:8080/auth/realms/master/protocol/openid-connect/certs + + Azure AD Multitenant + id_token_code + auth_oidc-test + True + upn:user_id upn:email + https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize + profile openid + https://login.microsoftonline.com/organizations/oauth2/v2.0/token + https://login.microsoftonline.com/organizations/discovery/v2.0/keys + fa fa-fw fa-windows + Log in with Microsoft + {'prompt':'select_account'} + diff --git a/auth_oidc/models/auth_oauth_provider.py b/auth_oidc/models/auth_oauth_provider.py index ac498a7cdb..3862e80e79 100644 --- a/auth_oidc/models/auth_oauth_provider.py +++ b/auth_oidc/models/auth_oauth_provider.py @@ -46,6 +46,9 @@ class AuthOauthProvider(models.Model): string="Token URL", help="Required for OpenID Connect authorization code flow." ) jwks_uri = fields.Char(string="JWKS URL", help="Required for OpenID Connect.") + auth_link_params = fields.Char( + help="Additional parameters for the auth link. For example: {'prompt':'select_account'}" + ) @tools.ormcache("self.jwks_uri", "kid") def _get_keys(self, kid): diff --git a/auth_oidc/readme/CONFIGURE.md b/auth_oidc/readme/CONFIGURE.md index 275e4c0a20..8145f4faf9 100644 --- a/auth_oidc/readme/CONFIGURE.md +++ b/auth_oidc/readme/CONFIGURE.md @@ -38,6 +38,10 @@ or ![image](../static/description/odoo-azure_ad_multitenant.png) +- Auth Link Params: Add {'prompt':'select_account'} to the auth link to get the account selection screen +![image](../static/description/oauth-microsoft_azure-select_account.png) + + ## Setup for Keycloak Example configuration with OpenID Connect authorization code flow. diff --git a/auth_oidc/static/description/oauth-microsoft_azure-select_account.png b/auth_oidc/static/description/oauth-microsoft_azure-select_account.png new file mode 100644 index 0000000000..a088777403 Binary files /dev/null and b/auth_oidc/static/description/oauth-microsoft_azure-select_account.png differ diff --git a/auth_oidc/tests/test_auth_oidc_auth_code.py b/auth_oidc/tests/test_auth_oidc_auth_code.py index a1a08b0a71..43a1ec6fff 100644 --- a/auth_oidc/tests/test_auth_oidc_auth_code.py +++ b/auth_oidc/tests/test_auth_oidc_auth_code.py @@ -71,7 +71,7 @@ def setUp(self): super().setUp() # search our test provider and bind the demo user to it self.provider_rec = self.env["auth.oauth.provider"].search( - [("client_id", "=", "auth_oidc-test")] + [("name", "=", "keycloak:8080 on localhost")] ) self.assertEqual(len(self.provider_rec), 1) @@ -83,8 +83,10 @@ def test_auth_link(self): ).write(dict(enabled=False)) with MockRequest(self.env): providers = OpenIDLogin().list_providers() - self.assertEqual(len(providers), 1) - auth_link = providers[0]["auth_link"] + self.assertEqual(len(providers), 2) + auth_link = list( + filter(lambda p: p["name"] == "keycloak:8080 on localhost", providers) + )[0]["auth_link"] assert auth_link.startswith(self.provider_rec.auth_endpoint) params = parse_qs(urlparse(auth_link).query) self.assertEqual(params["response_type"], ["code"]) @@ -95,6 +97,13 @@ def test_auth_link(self): self.assertTrue(params["nonce"]) self.assertTrue(params["state"]) self.assertEqual(params["redirect_uri"], [BASE_URL + "/auth_oauth/signin"]) + self.assertFalse("prompt" in params) + + auth_link_ms = list( + filter(lambda p: p["name"] == "Azure AD Multitenant", providers) + )[0]["auth_link"] + params = parse_qs(urlparse(auth_link_ms).query) + self.assertEqual(params["prompt"], ["select_account"]) def _prepare_login_test_user(self): user = self.env.ref("base.user_demo") diff --git a/auth_oidc/views/auth_oauth_provider.xml b/auth_oidc/views/auth_oauth_provider.xml index 90c931b417..c63f2cef60 100644 --- a/auth_oidc/views/auth_oauth_provider.xml +++ b/auth_oidc/views/auth_oauth_provider.xml @@ -19,6 +19,9 @@ + + +