Give the user a better error when they present bad SSO creds
If a user tries to do UI Auth via SSO, but uses the wrong account on the SSO IdP, try to give them a better error. Previously, the UIA would claim to be successful, but then the operation in question would simply fail with "auth fail". Instead, serve up an error page which explains the failure.
This commit is contained in:
parent
233c8b9fce
commit
5310808d3b
|
@ -0,0 +1 @@
|
||||||
|
During user-interactive authentication via single-sign-on, give a better error if the user uses the wrong account on the SSO IdP.
|
|
@ -1969,6 +1969,14 @@ sso:
|
||||||
#
|
#
|
||||||
# This template has no additional variables.
|
# This template has no additional variables.
|
||||||
#
|
#
|
||||||
|
# * HTML page shown after a user-interactive authentication session which
|
||||||
|
# does not map correctly onto the expected user: 'sso_auth_bad_user.html'.
|
||||||
|
#
|
||||||
|
# When rendering, this template is given the following variables:
|
||||||
|
# * server_name: the homeserver's name.
|
||||||
|
# * user_id_to_verify: the MXID of the user that we are trying to
|
||||||
|
# validate.
|
||||||
|
#
|
||||||
# * HTML page shown during single sign-on if a deactivated user (according to Synapse's database)
|
# * HTML page shown during single sign-on if a deactivated user (according to Synapse's database)
|
||||||
# attempts to login: 'sso_account_deactivated.html'.
|
# attempts to login: 'sso_account_deactivated.html'.
|
||||||
#
|
#
|
||||||
|
|
|
@ -37,6 +37,7 @@ class SSOConfig(Config):
|
||||||
self.sso_error_template,
|
self.sso_error_template,
|
||||||
sso_account_deactivated_template,
|
sso_account_deactivated_template,
|
||||||
sso_auth_success_template,
|
sso_auth_success_template,
|
||||||
|
self.sso_auth_bad_user_template,
|
||||||
) = self.read_templates(
|
) = self.read_templates(
|
||||||
[
|
[
|
||||||
"sso_login_idp_picker.html",
|
"sso_login_idp_picker.html",
|
||||||
|
@ -45,6 +46,7 @@ class SSOConfig(Config):
|
||||||
"sso_error.html",
|
"sso_error.html",
|
||||||
"sso_account_deactivated.html",
|
"sso_account_deactivated.html",
|
||||||
"sso_auth_success.html",
|
"sso_auth_success.html",
|
||||||
|
"sso_auth_bad_user.html",
|
||||||
],
|
],
|
||||||
template_dir,
|
template_dir,
|
||||||
)
|
)
|
||||||
|
@ -160,6 +162,14 @@ class SSOConfig(Config):
|
||||||
#
|
#
|
||||||
# This template has no additional variables.
|
# This template has no additional variables.
|
||||||
#
|
#
|
||||||
|
# * HTML page shown after a user-interactive authentication session which
|
||||||
|
# does not map correctly onto the expected user: 'sso_auth_bad_user.html'.
|
||||||
|
#
|
||||||
|
# When rendering, this template is given the following variables:
|
||||||
|
# * server_name: the homeserver's name.
|
||||||
|
# * user_id_to_verify: the MXID of the user that we are trying to
|
||||||
|
# validate.
|
||||||
|
#
|
||||||
# * HTML page shown during single sign-on if a deactivated user (according to Synapse's database)
|
# * HTML page shown during single sign-on if a deactivated user (according to Synapse's database)
|
||||||
# attempts to login: 'sso_account_deactivated.html'.
|
# attempts to login: 'sso_account_deactivated.html'.
|
||||||
#
|
#
|
||||||
|
|
|
@ -23,6 +23,7 @@ from typing_extensions import NoReturn, Protocol
|
||||||
from twisted.web.http import Request
|
from twisted.web.http import Request
|
||||||
|
|
||||||
from synapse.api.errors import Codes, RedirectException, SynapseError
|
from synapse.api.errors import Codes, RedirectException, SynapseError
|
||||||
|
from synapse.handlers.ui_auth import UIAuthSessionDataConstants
|
||||||
from synapse.http import get_request_user_agent
|
from synapse.http import get_request_user_agent
|
||||||
from synapse.http.server import respond_with_html
|
from synapse.http.server import respond_with_html
|
||||||
from synapse.http.site import SynapseRequest
|
from synapse.http.site import SynapseRequest
|
||||||
|
@ -147,6 +148,7 @@ class SsoHandler:
|
||||||
self._server_name = hs.hostname
|
self._server_name = hs.hostname
|
||||||
self._registration_handler = hs.get_registration_handler()
|
self._registration_handler = hs.get_registration_handler()
|
||||||
self._error_template = hs.config.sso_error_template
|
self._error_template = hs.config.sso_error_template
|
||||||
|
self._bad_user_template = hs.config.sso_auth_bad_user_template
|
||||||
self._auth_handler = hs.get_auth_handler()
|
self._auth_handler = hs.get_auth_handler()
|
||||||
|
|
||||||
# a lock on the mappings
|
# a lock on the mappings
|
||||||
|
@ -577,20 +579,41 @@ class SsoHandler:
|
||||||
auth_provider_id, remote_user_id,
|
auth_provider_id, remote_user_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
user_id_to_verify = await self._auth_handler.get_session_data(
|
||||||
|
ui_auth_session_id, UIAuthSessionDataConstants.REQUEST_USER_ID
|
||||||
|
) # type: str
|
||||||
|
|
||||||
if not user_id:
|
if not user_id:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Remote user %s/%s has not previously logged in here: UIA will fail",
|
"Remote user %s/%s has not previously logged in here: UIA will fail",
|
||||||
auth_provider_id,
|
auth_provider_id,
|
||||||
remote_user_id,
|
remote_user_id,
|
||||||
)
|
)
|
||||||
# Let the UIA flow handle this the same as if they presented creds for a
|
elif user_id != user_id_to_verify:
|
||||||
# different user.
|
logger.warning(
|
||||||
user_id = ""
|
"Remote user %s/%s mapped onto incorrect user %s: UIA will fail",
|
||||||
|
auth_provider_id,
|
||||||
|
remote_user_id,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# success!
|
||||||
|
await self._auth_handler.complete_sso_ui_auth(
|
||||||
|
user_id, ui_auth_session_id, request
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
await self._auth_handler.complete_sso_ui_auth(
|
# the user_id didn't match: mark the stage of the authentication as unsuccessful
|
||||||
user_id, ui_auth_session_id, request
|
await self._store.mark_ui_auth_stage_complete(
|
||||||
|
ui_auth_session_id, LoginType.SSO, ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# render an error page.
|
||||||
|
html = self._bad_user_template.render(
|
||||||
|
server_name=self._server_name, user_id_to_verify=user_id_to_verify,
|
||||||
|
)
|
||||||
|
respond_with_html(request, 200, html)
|
||||||
|
|
||||||
async def check_username_availability(
|
async def check_username_availability(
|
||||||
self, localpart: str, session_id: str,
|
self, localpart: str, session_id: str,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Authentication Failed</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
We were unable to validate your <tt>{{server_name | e}}</tt> account via
|
||||||
|
single-sign-on (SSO), because the SSO Identity Provider returned
|
||||||
|
different details than when you logged in.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Try the operation again, and ensure that you use the same details on
|
||||||
|
the Identity Provider as when you log into your account.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue