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.
This commit is contained in:
@@ -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,9 +1756,16 @@ class AuthHandler:
|
||||
# it not being offered.
|
||||
raise SynapseError(400, "User has no SSO identities")
|
||||
|
||||
# for now, just pick one
|
||||
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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user