diff --git a/auth_oidc/README.rst b/auth_oidc/README.rst index 837cc8704b..8b5d59bc65 100644 --- a/auth_oidc/README.rst +++ b/auth_oidc/README.rst @@ -90,6 +90,9 @@ or |image2| +- Auth Link Params: Add {'prompt':'select_account'} to the auth link to + get the account selection screen |image3| + Setup for Keycloak ------------------ @@ -126,6 +129,7 @@ In Odoo, create a new Oauth Provider with the following parameters: .. |image| image:: https://raw.githubusercontent.com/OCA/server-auth/17.0/auth_oidc/static/description/oauth-microsoft_azure-api_permissions.png .. |image1| image:: https://raw.githubusercontent.com/OCA/server-auth/17.0/auth_oidc/static/description/oauth-microsoft_azure-optional_claims.png .. |image2| image:: https://raw.githubusercontent.com/OCA/server-auth/17.0/auth_oidc/static/description/odoo-azure_ad_multitenant.png +.. |image3| image:: https://raw.githubusercontent.com/OCA/server-auth/17.0/auth_oidc/static/description/oauth-microsoft_azure-select_account.png Usage ===== 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..d05197da72 100644 --- a/auth_oidc/models/auth_oauth_provider.py +++ b/auth_oidc/models/auth_oauth_provider.py @@ -46,6 +46,10 @@ 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/index.html b/auth_oidc/static/description/index.html index 412ba2dc79..f96bca5d48 100644 --- a/auth_oidc/static/description/index.html +++ b/auth_oidc/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -448,6 +449,10 @@

Setup for Microsoft Azure

replace {tenant_id} in urls with your Azure tenant id

image2

+

Setup for Keycloak

@@ -582,7 +587,9 @@

Contributors

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

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 @@ + + +