This commit is contained in:
Olivier D 2025-03-13 17:32:09 +01:00 committed by GitHub
commit 46568e0885
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 6 deletions

View file

@ -0,0 +1 @@
Add support for the `login_hint` parameter in OIDC authentication flow to pre-fill user identification.

View file

@ -990,6 +990,7 @@ class OidcProvider:
- ``state``: a random string
- ``nonce``: a random string
- ``code_challenge``: a RFC7636 code challenge (if PKCE is supported)
- ``login_hint``: provide login to avoid re-entering it in the upstream idp
In addition to generating a redirect URL, we are setting a cookie with
a signed macaroon token containing the state, the nonce, the
@ -1005,7 +1006,6 @@ class OidcProvider:
when everything is done (or None for UI Auth)
ui_auth_session_id: The session ID of the ongoing UI Auth (or
None if this is a login).
Returns:
The redirect URL to the authorization endpoint.
@ -1077,6 +1077,11 @@ class OidcProvider:
options,
)
)
# gather login_hint from query string
login_hint = parse_string(request, "login_hint")
if login_hint:
additional_authorization_parameters.update({"login_hint": login_hint})
authorization_endpoint = metadata.get("authorization_endpoint")
return prepare_grant_uri(

View file

@ -59,6 +59,7 @@ BASE_URL = "https://synapse/"
CALLBACK_URL = BASE_URL + "_synapse/client/oidc/callback"
TEST_REDIRECT_URI = "https://test/oidc/callback"
SCOPES = ["openid"]
LOGIN_HINT = "aaa@example.com"
# config for common cases
DEFAULT_CONFIG = {
@ -439,8 +440,10 @@ class OidcHandlerTestCase(HomeserverTestCase):
@override_config({"oidc_config": DEFAULT_CONFIG})
def test_redirect_request(self) -> None:
"""The redirect request has the right arguments & generates a valid session cookie."""
req = Mock(spec=["cookies"])
req = Mock(spec=["cookies", "args"])
req.cookies = []
req.args = {}
req.args[b"login_hint"] = [LOGIN_HINT.encode("utf-8")]
url = urlparse(
self.get_success(
@ -461,6 +464,8 @@ class OidcHandlerTestCase(HomeserverTestCase):
self.assertEqual(len(params["state"]), 1)
self.assertEqual(len(params["nonce"]), 1)
self.assertNotIn("code_challenge", params)
# Verify that login_hint is properly set
self.assertEqual(params["login_hint"], [LOGIN_HINT])
# Check what is in the cookies
self.assertEqual(len(req.cookies), 2) # two cookies
@ -487,8 +492,9 @@ class OidcHandlerTestCase(HomeserverTestCase):
@override_config({"oidc_config": DEFAULT_CONFIG})
def test_redirect_request_with_code_challenge(self) -> None:
"""The redirect request has the right arguments & generates a valid session cookie."""
req = Mock(spec=["cookies"])
req = Mock(spec=["cookies", "args"])
req.cookies = []
req.args = {}
with self.metadata_edit({"code_challenge_methods_supported": ["S256"]}):
url = urlparse(
@ -522,8 +528,9 @@ class OidcHandlerTestCase(HomeserverTestCase):
@override_config({"oidc_config": {**DEFAULT_CONFIG, "pkce_method": "always"}})
def test_redirect_request_with_forced_code_challenge(self) -> None:
"""The redirect request has the right arguments & generates a valid session cookie."""
req = Mock(spec=["cookies"])
req = Mock(spec=["cookies", "args"])
req.cookies = []
req.args = {}
url = urlparse(
self.get_success(
@ -554,8 +561,9 @@ class OidcHandlerTestCase(HomeserverTestCase):
@override_config({"oidc_config": {**DEFAULT_CONFIG, "pkce_method": "never"}})
def test_redirect_request_with_disabled_code_challenge(self) -> None:
"""The redirect request has the right arguments & generates a valid session cookie."""
req = Mock(spec=["cookies"])
req = Mock(spec=["cookies", "args"])
req.cookies = []
req.args = {}
# The metadata should state that PKCE is enabled.
with self.metadata_edit({"code_challenge_methods_supported": ["S256"]}):
@ -592,8 +600,9 @@ class OidcHandlerTestCase(HomeserverTestCase):
)
def test_redirect_request_with_overridden_redirect_uri(self) -> None:
"""The authorization endpoint redirect has the overridden `redirect_uri` value."""
req = Mock(spec=["cookies"])
req = Mock(spec=["cookies", "args"])
req.cookies = []
req.args = {}
url = urlparse(
self.get_success(