Use a template for the SSO success page to allow for customization. (#7279)

This commit is contained in:
Patrick Cloke 2020-04-17 13:34:55 -04:00 committed by GitHub
parent 701788a227
commit 054c231e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 37 deletions

View File

@ -1,10 +1,11 @@
Next version Next version
============ ============
* Two new templates (`sso_auth_confirm.html` and `sso_account_deactivated.html`) * New templates (`sso_auth_confirm.html`, `sso_auth_success.html`, and
were added to Synapse. If your Synapse is configured to use SSO and a custom `sso_account_deactivated.html`) were added to Synapse. If your Synapse is
`sso_redirect_confirm_template_dir` configuration then these templates will configured to use SSO and a custom `sso_redirect_confirm_template_dir`
need to be duplicated into that directory. configuration then these templates will need to be duplicated into that
directory.
* Plugins using the `complete_sso_login` method of `synapse.module_api.ModuleApi` * 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 should update to using the async/await version `complete_sso_login_async` which

1
changelog.d/7279.feature Normal file
View File

@ -0,0 +1 @@
Support SSO in the user interactive authentication workflow.

View File

@ -43,6 +43,12 @@ class SSOConfig(Config):
), ),
"sso_account_deactivated_template", "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 [] self.sso_client_whitelist = sso_config.get("client_whitelist") or []

View File

@ -51,31 +51,6 @@ from ._base import BaseHandler
logger = logging.getLogger(__name__) 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): class AuthHandler(BaseHandler):
SESSION_EXPIRE_MS = 48 * 60 * 60 * 1000 SESSION_EXPIRE_MS = 48 * 60 * 60 * 1000
@ -159,6 +134,11 @@ class AuthHandler(BaseHandler):
self._sso_auth_confirm_template = load_jinja2_templates( self._sso_auth_confirm_template = load_jinja2_templates(
hs.config.sso_redirect_confirm_template_dir, ["sso_auth_confirm.html"], hs.config.sso_redirect_confirm_template_dir, ["sso_auth_confirm.html"],
)[0] )[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 = ( self._sso_account_deactivated_template = (
hs.config.sso_account_deactivated_template hs.config.sso_account_deactivated_template
) )
@ -1080,7 +1060,7 @@ class AuthHandler(BaseHandler):
self._save_session(sess) self._save_session(sess)
# Render the HTML and return. # 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.setResponseCode(200)
request.setHeader(b"Content-Type", b"text/html; charset=utf-8") request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),)) request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
@ -1106,12 +1086,12 @@ class AuthHandler(BaseHandler):
# flow. # flow.
deactivated = await self.store.get_user_deactivated_status(registered_user_id) deactivated = await self.store.get_user_deactivated_status(registered_user_id)
if deactivated: 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.setResponseCode(403)
request.setHeader(b"Content-Type", b"text/html; charset=utf-8") request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
request.setHeader(b"Content-Length", b"%d" % (len(html),)) request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
request.write(html) request.write(html_bytes)
finish_request(request) finish_request(request)
return return
@ -1153,7 +1133,7 @@ class AuthHandler(BaseHandler):
# URL we redirect users to. # URL we redirect users to.
redirect_url_no_params = client_redirect_url.split("?")[0] 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, display_url=redirect_url_no_params,
redirect_url=redirect_url, redirect_url=redirect_url,
server_name=self._server_name, server_name=self._server_name,
@ -1161,8 +1141,8 @@ class AuthHandler(BaseHandler):
request.setResponseCode(200) request.setResponseCode(200)
request.setHeader(b"Content-Type", b"text/html; charset=utf-8") request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
request.setHeader(b"Content-Length", b"%d" % (len(html),)) request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
request.write(html) request.write(html_bytes)
finish_request(request) finish_request(request)
@staticmethod @staticmethod

View File

@ -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>

View File

@ -18,7 +18,6 @@ import logging
from synapse.api.constants import LoginType from synapse.api.constants import LoginType
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
from synapse.api.urls import CLIENT_API_PREFIX 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.server import finish_request
from synapse.http.servlet import RestServlet, parse_string from synapse.http.servlet import RestServlet, parse_string
@ -90,6 +89,30 @@ TERMS_TEMPLATE = """
</html> </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): class AuthRestServlet(RestServlet):
""" """