diff --git a/CHANGES.md b/CHANGES.md index 6f25b26a556e7a4ba376e370283758bc64d80d4e..b41a627cb818f2e892128f669f3fb0ddfbd3d9e5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,10 +1,11 @@ Next version ============ -* Two new templates (`sso_auth_confirm.html` and `sso_account_deactivated.html`) - were added to Synapse. If your Synapse is configured to use SSO and a custom - `sso_redirect_confirm_template_dir` configuration then these templates will - need to be duplicated into that directory. +* New templates (`sso_auth_confirm.html`, `sso_auth_success.html`, and + `sso_account_deactivated.html`) were added to Synapse. If your Synapse is + configured to use SSO and a custom `sso_redirect_confirm_template_dir` + configuration then these templates will need to be duplicated into that + directory. * Plugins using the `complete_sso_login` method of `synapse.module_api.ModuleApi` should update to using the async/await version `complete_sso_login_async` which diff --git a/changelog.d/7279.feature b/changelog.d/7279.feature new file mode 100644 index 0000000000000000000000000000000000000000..9aed0754744bc51a3d64ad81969429ceec7a767c --- /dev/null +++ b/changelog.d/7279.feature @@ -0,0 +1 @@ + Support SSO in the user interactive authentication workflow. diff --git a/synapse/config/sso.py b/synapse/config/sso.py index 686678a3b7c92914555f56e98c9fd9e842f48aed..6cd37d432477ffd5974ba4cdcbb9e7afbe6dddcc 100644 --- a/synapse/config/sso.py +++ b/synapse/config/sso.py @@ -43,6 +43,12 @@ class SSOConfig(Config): ), "sso_account_deactivated_template", ) + self.sso_auth_success_template = self.read_file( + os.path.join( + self.sso_redirect_confirm_template_dir, "sso_auth_success.html" + ), + "sso_auth_success_template", + ) self.sso_client_whitelist = sso_config.get("client_whitelist") or [] diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index 0aae929eccb9eb31ced3d8224d4bbbf482ebe853..bda279ab8b0276cb882b1d40e1c64f37fc6f58b1 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -51,31 +51,6 @@ from ._base import BaseHandler logger = logging.getLogger(__name__) -SUCCESS_TEMPLATE = """ -<html> -<head> -<title>Success!</title> -<meta name='viewport' content='width=device-width, initial-scale=1, - user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'> -<link rel="stylesheet" href="/_matrix/static/client/register/style.css"> -<script> -if (window.onAuthDone) { - window.onAuthDone(); -} else if (window.opener && window.opener.postMessage) { - window.opener.postMessage("authDone", "*"); -} -</script> -</head> -<body> - <div> - <p>Thank you</p> - <p>You may now close this window and return to the application</p> - </div> -</body> -</html> -""" - - class AuthHandler(BaseHandler): SESSION_EXPIRE_MS = 48 * 60 * 60 * 1000 @@ -159,6 +134,11 @@ class AuthHandler(BaseHandler): self._sso_auth_confirm_template = load_jinja2_templates( hs.config.sso_redirect_confirm_template_dir, ["sso_auth_confirm.html"], )[0] + # The following template is shown after a successful user interactive + # authentication session. It tells the user they can close the window. + self._sso_auth_success_template = hs.config.sso_auth_success_template + # The following template is shown during the SSO authentication process if + # the account is deactivated. self._sso_account_deactivated_template = ( hs.config.sso_account_deactivated_template ) @@ -1080,7 +1060,7 @@ class AuthHandler(BaseHandler): self._save_session(sess) # Render the HTML and return. - html_bytes = SUCCESS_TEMPLATE.encode("utf8") + html_bytes = self._sso_auth_success_template.encode("utf-8") request.setResponseCode(200) request.setHeader(b"Content-Type", b"text/html; charset=utf-8") request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),)) @@ -1106,12 +1086,12 @@ class AuthHandler(BaseHandler): # flow. deactivated = await self.store.get_user_deactivated_status(registered_user_id) if deactivated: - html = self._sso_account_deactivated_template.encode("utf-8") + html_bytes = self._sso_account_deactivated_template.encode("utf-8") request.setResponseCode(403) request.setHeader(b"Content-Type", b"text/html; charset=utf-8") - request.setHeader(b"Content-Length", b"%d" % (len(html),)) - request.write(html) + request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),)) + request.write(html_bytes) finish_request(request) return @@ -1153,7 +1133,7 @@ class AuthHandler(BaseHandler): # URL we redirect users to. redirect_url_no_params = client_redirect_url.split("?")[0] - html = self._sso_redirect_confirm_template.render( + html_bytes = self._sso_redirect_confirm_template.render( display_url=redirect_url_no_params, redirect_url=redirect_url, server_name=self._server_name, @@ -1161,8 +1141,8 @@ class AuthHandler(BaseHandler): request.setResponseCode(200) request.setHeader(b"Content-Type", b"text/html; charset=utf-8") - request.setHeader(b"Content-Length", b"%d" % (len(html),)) - request.write(html) + request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),)) + request.write(html_bytes) finish_request(request) @staticmethod diff --git a/synapse/res/templates/sso_auth_success.html b/synapse/res/templates/sso_auth_success.html new file mode 100644 index 0000000000000000000000000000000000000000..03f14194673a559954c3587e34b0286b1c77ae8e --- /dev/null +++ b/synapse/res/templates/sso_auth_success.html @@ -0,0 +1,18 @@ +<html> +<head> + <title>Authentication Successful</title> + <script> + if (window.onAuthDone) { + window.onAuthDone(); + } else if (window.opener && window.opener.postMessage) { + window.opener.postMessage("authDone", "*"); + } + </script> +</head> + <body> + <div> + <p>Thank you</p> + <p>You may now close this window and return to the application</p> + </div> + </body> +</html> diff --git a/synapse/rest/client/v2_alpha/auth.py b/synapse/rest/client/v2_alpha/auth.py index 13f9604407e8954a29ed5d7f20a0a4d6ba502d1f..11599f50054a7b3de397fcc074e67f3ff00c39d6 100644 --- a/synapse/rest/client/v2_alpha/auth.py +++ b/synapse/rest/client/v2_alpha/auth.py @@ -18,7 +18,6 @@ import logging from synapse.api.constants import LoginType from synapse.api.errors import SynapseError from synapse.api.urls import CLIENT_API_PREFIX -from synapse.handlers.auth import SUCCESS_TEMPLATE from synapse.http.server import finish_request from synapse.http.servlet import RestServlet, parse_string @@ -90,6 +89,30 @@ TERMS_TEMPLATE = """ </html> """ +SUCCESS_TEMPLATE = """ +<html> +<head> +<title>Success!</title> +<meta name='viewport' content='width=device-width, initial-scale=1, + user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'> +<link rel="stylesheet" href="/_matrix/static/client/register/style.css"> +<script> +if (window.onAuthDone) { + window.onAuthDone(); +} else if (window.opener && window.opener.postMessage) { + window.opener.postMessage("authDone", "*"); +} +</script> +</head> +<body> + <div> + <p>Thank you</p> + <p>You may now close this window and return to the application</p> + </div> +</body> +</html> +""" + class AuthRestServlet(RestServlet): """