Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

UI Auth via SSO: redirect the user to an appropriate SSO. #9081

Merged
merged 7 commits into from
Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -1346,12 +1346,12 @@ def _do_validate_hash(checked_hash: bytes):
else:
return False

async def start_sso_ui_auth(self, redirect_url: str, session_id: str) -> str:
async def start_sso_ui_auth(self, request: SynapseRequest, session_id: str) -> str:
"""
Get the HTML for the SSO redirect confirmation page.

Args:
redirect_url: The URL to redirect to the SSO provider.
request: The incoming HTTP request
session_id: The user interactive authentication session ID.

Returns:
Expand All @@ -1361,6 +1361,35 @@ async def start_sso_ui_auth(self, redirect_url: str, session_id: str) -> str:
session = await self.store.get_ui_auth_session(session_id)
except StoreError:
raise SynapseError(400, "Unknown session ID: %s" % (session_id,))

user_id_to_verify = await self.get_session_data(
session_id, UIAuthSessionDataConstants.REGISTERED_USER_ID
) # type: str

idps = await self.hs.get_sso_handler().get_identity_providers_for_user(
user_id_to_verify
)

if not idps:
# we checked that the user had some remote identities before offering an SSO
# flow, so either it's been deleted or the client has requested SSO despite
# it not being offered.
raise SynapseError(400, "User has no SSO identities")
Comment on lines +1374 to +1377
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point in the flow should we be rendering JSON or HTML errors? (Should this use sso_handler.render_error?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that said... there are plenty of other places we are raising SynapseErrors in this method. Ideally they'd all be caught and sent to sso_handler.render_error instead, and while we're at it I think start_sso_ui_auth probably just wants to move into SsoHandler, but that feels like a bigger refactor.


# for now, just pick one
idp_id, sso_auth_provider = next(iter(idps.items()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This theoretically isn't stable before Python 3.7. I suspect we don't care since they can use any identity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed. the first is no better than the last.

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,
)

redirect_url = await sso_auth_provider.handle_redirect_request(
request, None, session_id
)

return self._sso_auth_confirm_template.render(
description=session.description, redirect_url=redirect_url,
)
Expand Down
33 changes: 1 addition & 32 deletions synapse/rest/client/v2_alpha/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from synapse.api.constants import LoginType
from synapse.api.errors import SynapseError
from synapse.api.urls import CLIENT_API_PREFIX
from synapse.handlers.sso import SsoIdentityProvider
from synapse.http.server import respond_with_html
from synapse.http.servlet import RestServlet, parse_string

Expand All @@ -46,22 +45,6 @@ def __init__(self, hs: "HomeServer"):
self.auth = hs.get_auth()
self.auth_handler = hs.get_auth_handler()
self.registration_handler = hs.get_registration_handler()

# SSO configuration.
self._cas_enabled = hs.config.cas_enabled
if self._cas_enabled:
self._cas_handler = hs.get_cas_handler()
self._cas_server_url = hs.config.cas_server_url
self._cas_service_url = hs.config.cas_service_url
self._saml_enabled = hs.config.saml2_enabled
if self._saml_enabled:
self._saml_handler = hs.get_saml_handler()
self._oidc_enabled = hs.config.oidc_enabled
if self._oidc_enabled:
self._oidc_handler = hs.get_oidc_handler()
self._cas_server_url = hs.config.cas_server_url
self._cas_service_url = hs.config.cas_service_url

self.recaptcha_template = hs.config.recaptcha_template
self.terms_template = hs.config.terms_template
self.success_template = hs.config.fallback_success_template
Expand Down Expand Up @@ -90,21 +73,7 @@ async def on_GET(self, request, stagetype):
elif stagetype == LoginType.SSO:
# Display a confirmation page which prompts the user to
# re-authenticate with their SSO provider.

if self._cas_enabled:
sso_auth_provider = self._cas_handler # type: SsoIdentityProvider
elif self._saml_enabled:
sso_auth_provider = self._saml_handler
elif self._oidc_enabled:
sso_auth_provider = self._oidc_handler
else:
raise SynapseError(400, "Homeserver not configured for SSO.")

sso_redirect_url = await sso_auth_provider.handle_redirect_request(
request, None, session
)

html = await self.auth_handler.start_sso_ui_auth(sso_redirect_url, session)
html = await self.auth_handler.start_sso_ui_auth(request, session)

else:
raise SynapseError(404, "Unknown auth stage type")
Expand Down