Compare commits

...

1 Commits

Author SHA1 Message Date
Andrew Morgan
3aaecb4f35 Add an unstable, namespaced idp_id query parameter to fallback/web
This allows clients to specify the identity provider they'd like to log
in with for SSO when they have multiple upstream IdPs associated with
their account.

Previously, Synapse would just pick one arbitrarily. But this was
undesirable as you may want to use a different one at that point in
time. When logging in, the user is able to choose when IdP they use -
during UIA (which uses fallback auth mechanism) they should be able to
do the same.
2025-10-10 17:49:04 +01:00
2 changed files with 28 additions and 12 deletions

View File

@@ -1722,13 +1722,17 @@ class AuthHandler:
else:
return False
async def start_sso_ui_auth(self, request: SynapseRequest, session_id: str) -> str:
async def start_sso_ui_auth(
self, request: SynapseRequest, session_id: str, preferred_idp_id: Optional[str]
) -> str:
"""
Get the HTML for the SSO redirect confirmation page.
Args:
request: The incoming HTTP request
session_id: The user interactive authentication session ID.
preferred_idp_id: The ID of the identity provider to use. If `None` one will
be picked randomly from those the user has already signed in with.
Returns:
The HTML to render.
@@ -1752,15 +1756,22 @@ class AuthHandler:
# it not being offered.
raise SynapseError(400, "User has no SSO identities")
# for now, just pick one
idp_id, sso_auth_provider = next(iter(idps.items()))
if len(idps) > 0:
logger.warning(
"User %r has previously logged in with multiple SSO IdPs; arbitrarily "
"picking %r",
user_id_to_verify,
idp_id,
)
if preferred_idp_id is not None:
# Use the idp specified by the client.
sso_auth_provider = idps.get(preferred_idp_id)
if sso_auth_provider is None:
raise SynapseError(400, "Unknown IdP %s" % (preferred_idp_id,))
else:
idp_id, sso_auth_provider = next(iter(idps.items()))
if len(idps) > 0:
# We arbitrarily picked an IdP from multiple potential
# candidates. This may be undesirable for the user.
logger.warning(
"User %r has previously logged in with multiple SSO IdPs; arbitrarily "
"picking %r",
user_id_to_verify,
idp_id,
)
redirect_url = await sso_auth_provider.handle_redirect_request(
request, None, session_id

View File

@@ -20,7 +20,7 @@
#
import logging
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional
from twisted.web.server import Request
@@ -67,6 +67,11 @@ class AuthRestServlet(RestServlet):
if not session:
raise SynapseError(400, "No session supplied")
# Unstable query parameter which allows clients to specify the IDP
# they wish to use for SSO.
# XXX: This needs an MSC and an experimental flag.
idp_id: Optional[str] = parse_string(request, "io.element.idp_id")
if stagetype == "org.matrix.cross_signing_reset":
if self.hs.config.mas.enabled:
assert isinstance(self.auth, MasDelegatedAuth)
@@ -114,7 +119,7 @@ class AuthRestServlet(RestServlet):
elif stagetype == LoginType.SSO:
# Display a confirmation page which prompts the user to
# re-authenticate with their SSO provider.
html = await self.auth_handler.start_sso_ui_auth(request, session)
html = await self.auth_handler.start_sso_ui_auth(request, session, idp_id)
elif stagetype == LoginType.REGISTRATION_TOKEN:
html = self.registration_token_template.render(