This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to perform password reset via email without trusting the …
…identity server (#5377) Sends password reset emails from the homeserver instead of proxying to the identity server. This is now the default behaviour for security reasons. If you wish to continue proxying password reset requests to the identity server you must now enable the email.trust_identity_server_for_password_resets option. This PR is a culmination of 3 smaller PRs which have each been separately reviewed: * #5308 * #5345 * #5368
- Loading branch information
1 parent
9fbb20a
commit 3719680
Showing
20 changed files
with
922 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add ability to perform password reset via email without trusting the identity server. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1065,33 +1065,73 @@ password_config: | |
|
||
|
||
|
||
# Enable sending emails for notification events or expiry notices | ||
# Defining a custom URL for Riot is only needed if email notifications | ||
# should contain links to a self-hosted installation of Riot; when set | ||
# the "app_name" setting is ignored. | ||
# Enable sending emails for password resets, notification events or | ||
# account expiry notices | ||
# | ||
# If your SMTP server requires authentication, the optional smtp_user & | ||
# smtp_pass variables should be used | ||
# | ||
#email: | ||
# enable_notifs: false | ||
# smtp_host: "localhost" | ||
# smtp_port: 25 | ||
# smtp_port: 25 # SSL: 465, STARTTLS: 587 | ||
# smtp_user: "exampleusername" | ||
# smtp_pass: "examplepassword" | ||
# require_transport_security: False | ||
# notif_from: "Your Friendly %(app)s Home Server <[email protected]>" | ||
# app_name: Matrix | ||
# # if template_dir is unset, uses the example templates that are part of | ||
# # the Synapse distribution. | ||
# | ||
# # Enable email notifications by default | ||
# notif_for_new_users: True | ||
# | ||
# # Defining a custom URL for Riot is only needed if email notifications | ||
# # should contain links to a self-hosted installation of Riot; when set | ||
# # the "app_name" setting is ignored | ||
# riot_base_url: "http://localhost/riot" | ||
# | ||
# # Enable sending password reset emails via the configured, trusted | ||
# # identity servers | ||
# # | ||
# # IMPORTANT! This will give a malicious or overtaken identity server | ||
# # the ability to reset passwords for your users! Make absolutely sure | ||
# # that you want to do this! It is strongly recommended that password | ||
# # reset emails be sent by the homeserver instead | ||
# # | ||
# # If this option is set to false and SMTP options have not been | ||
# # configured, resetting user passwords via email will be disabled | ||
# #trust_identity_server_for_password_resets: false | ||
# | ||
# # Configure the time that a validation email or text message code | ||
# # will expire after sending | ||
# # | ||
# # This is currently used for password resets | ||
# #validation_token_lifetime: 1h | ||
# | ||
# # Template directory. All template files should be stored within this | ||
# # directory | ||
# # | ||
# #template_dir: res/templates | ||
# | ||
# # Templates for email notifications | ||
# # | ||
# notif_template_html: notif_mail.html | ||
# notif_template_text: notif_mail.txt | ||
# # Templates for account expiry notices. | ||
# | ||
# # Templates for account expiry notices | ||
# # | ||
# expiry_template_html: notice_expiry.html | ||
# expiry_template_text: notice_expiry.txt | ||
# notif_for_new_users: True | ||
# riot_base_url: "http://localhost/riot" | ||
# | ||
# # Templates for password reset emails sent by the homeserver | ||
# # | ||
# #password_reset_template_html: password_reset.html | ||
# #password_reset_template_text: password_reset.txt | ||
# | ||
# # Templates for password reset success and failure pages that a user | ||
# # will see after attempting to reset their password | ||
# # | ||
# #password_reset_template_success_html: password_reset_success.html | ||
# #password_reset_template_failure_html: password_reset_failure.html | ||
|
||
|
||
#password_providers: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,11 @@ def read_config(self, config): | |
else: | ||
self.email_app_name = "Matrix" | ||
|
||
# TODO: Rename notif_from to something more generic, or have a separate | ||
# from for password resets, message notifications, etc? | ||
# Currently the email section is a bit bogged down with settings for | ||
# multiple functions. Would be good to split it out into separate | ||
# sections and only put the common ones under email: | ||
self.email_notif_from = email_config.get("notif_from", None) | ||
if self.email_notif_from is not None: | ||
# make sure it's valid | ||
|
@@ -74,14 +79,96 @@ def read_config(self, config): | |
"account_validity", {}, | ||
).get("renew_at") | ||
|
||
if self.email_enable_notifs or account_validity_renewal_enabled: | ||
email_trust_identity_server_for_password_resets = email_config.get( | ||
"trust_identity_server_for_password_resets", False, | ||
) | ||
self.email_password_reset_behaviour = ( | ||
"remote" if email_trust_identity_server_for_password_resets else "local" | ||
) | ||
if self.email_password_reset_behaviour == "local" and email_config == {}: | ||
logger.warn( | ||
"User password resets have been disabled due to lack of email config" | ||
) | ||
self.email_password_reset_behaviour = "off" | ||
|
||
# Get lifetime of a validation token in milliseconds | ||
self.email_validation_token_lifetime = self.parse_duration( | ||
email_config.get("validation_token_lifetime", "1h") | ||
) | ||
|
||
if ( | ||
self.email_enable_notifs | ||
or account_validity_renewal_enabled | ||
or self.email_password_reset_behaviour == "local" | ||
): | ||
# make sure we can import the required deps | ||
import jinja2 | ||
import bleach | ||
# prevent unused warnings | ||
jinja2 | ||
bleach | ||
|
||
if self.email_password_reset_behaviour == "local": | ||
required = [ | ||
"smtp_host", | ||
"smtp_port", | ||
"notif_from", | ||
] | ||
|
||
missing = [] | ||
for k in required: | ||
if k not in email_config: | ||
missing.append(k) | ||
|
||
if (len(missing) > 0): | ||
raise RuntimeError( | ||
"email.password_reset_behaviour is set to 'local' " | ||
"but required keys are missing: %s" % | ||
(", ".join(["email." + k for k in missing]),) | ||
) | ||
|
||
# Templates for password reset emails | ||
self.email_password_reset_template_html = email_config.get( | ||
"password_reset_template_html", "password_reset.html", | ||
) | ||
self.email_password_reset_template_text = email_config.get( | ||
"password_reset_template_text", "password_reset.txt", | ||
) | ||
self.email_password_reset_failure_template = email_config.get( | ||
"password_reset_failure_template", "password_reset_failure.html", | ||
) | ||
# This template does not support any replaceable variables, so we will | ||
# read it from the disk once during setup | ||
email_password_reset_success_template = email_config.get( | ||
"password_reset_success_template", "password_reset_success.html", | ||
) | ||
|
||
# Check templates exist | ||
for f in [self.email_password_reset_template_html, | ||
self.email_password_reset_template_text, | ||
self.email_password_reset_failure_template, | ||
email_password_reset_success_template]: | ||
p = os.path.join(self.email_template_dir, f) | ||
if not os.path.isfile(p): | ||
raise ConfigError("Unable to find template file %s" % (p, )) | ||
|
||
# Retrieve content of web templates | ||
filepath = os.path.join( | ||
self.email_template_dir, | ||
email_password_reset_success_template, | ||
) | ||
self.email_password_reset_success_html_content = self.read_file( | ||
filepath, | ||
"email.password_reset_template_success_html", | ||
) | ||
|
||
if config.get("public_baseurl") is None: | ||
raise RuntimeError( | ||
"email.password_reset_behaviour is set to 'local' but no " | ||
"public_baseurl is set. This is necessary to generate password " | ||
"reset links" | ||
) | ||
|
||
if self.email_enable_notifs: | ||
required = [ | ||
"smtp_host", | ||
|
@@ -121,10 +208,6 @@ def read_config(self, config): | |
self.email_riot_base_url = email_config.get( | ||
"riot_base_url", None | ||
) | ||
else: | ||
self.email_enable_notifs = False | ||
# Not much point setting defaults for the rest: it would be an | ||
# error for them to be used. | ||
|
||
if account_validity_renewal_enabled: | ||
self.email_expiry_template_html = email_config.get( | ||
|
@@ -141,31 +224,71 @@ def read_config(self, config): | |
|
||
def default_config(self, config_dir_path, server_name, **kwargs): | ||
return """ | ||
# Enable sending emails for notification events or expiry notices | ||
# Defining a custom URL for Riot is only needed if email notifications | ||
# should contain links to a self-hosted installation of Riot; when set | ||
# the "app_name" setting is ignored. | ||
# Enable sending emails for password resets, notification events or | ||
# account expiry notices | ||
# | ||
# If your SMTP server requires authentication, the optional smtp_user & | ||
# smtp_pass variables should be used | ||
# | ||
#email: | ||
# enable_notifs: false | ||
# smtp_host: "localhost" | ||
# smtp_port: 25 | ||
# smtp_port: 25 # SSL: 465, STARTTLS: 587 | ||
# smtp_user: "exampleusername" | ||
# smtp_pass: "examplepassword" | ||
# require_transport_security: False | ||
# notif_from: "Your Friendly %(app)s Home Server <[email protected]>" | ||
# app_name: Matrix | ||
# # if template_dir is unset, uses the example templates that are part of | ||
# # the Synapse distribution. | ||
# | ||
# # Enable email notifications by default | ||
# notif_for_new_users: True | ||
# | ||
# # Defining a custom URL for Riot is only needed if email notifications | ||
# # should contain links to a self-hosted installation of Riot; when set | ||
# # the "app_name" setting is ignored | ||
# riot_base_url: "http://localhost/riot" | ||
# | ||
# # Enable sending password reset emails via the configured, trusted | ||
# # identity servers | ||
# # | ||
# # IMPORTANT! This will give a malicious or overtaken identity server | ||
# # the ability to reset passwords for your users! Make absolutely sure | ||
# # that you want to do this! It is strongly recommended that password | ||
# # reset emails be sent by the homeserver instead | ||
# # | ||
# # If this option is set to false and SMTP options have not been | ||
# # configured, resetting user passwords via email will be disabled | ||
# #trust_identity_server_for_password_resets: false | ||
# | ||
# # Configure the time that a validation email or text message code | ||
# # will expire after sending | ||
# # | ||
# # This is currently used for password resets | ||
# #validation_token_lifetime: 1h | ||
# | ||
# # Template directory. All template files should be stored within this | ||
# # directory | ||
# # | ||
# #template_dir: res/templates | ||
# | ||
# # Templates for email notifications | ||
# # | ||
# notif_template_html: notif_mail.html | ||
# notif_template_text: notif_mail.txt | ||
# # Templates for account expiry notices. | ||
# | ||
# # Templates for account expiry notices | ||
# # | ||
# expiry_template_html: notice_expiry.html | ||
# expiry_template_text: notice_expiry.txt | ||
# notif_for_new_users: True | ||
# riot_base_url: "http://localhost/riot" | ||
# | ||
# # Templates for password reset emails sent by the homeserver | ||
# # | ||
# #password_reset_template_html: password_reset.html | ||
# #password_reset_template_text: password_reset.txt | ||
# | ||
# # Templates for password reset success and failure pages that a user | ||
# # will see after attempting to reset their password | ||
# # | ||
# #password_reset_template_success_html: password_reset_success.html | ||
# #password_reset_template_failure_html: password_reset_failure.html | ||
""" |
Oops, something went wrong.