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

Replace trust_identity_server_for_password_resets with account_threepid_delegate #5876

Merged
merged 23 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions changelog.d/5876.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Replace `trust_identity_server_for_password_resets` config option with `account_threepid_delegate`.
32 changes: 19 additions & 13 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,25 @@ uploads_path: "DATADIR/uploads"
# - matrix.org
# - vector.im

# Handle threepid (email/phone etc) registration and password resets
# through an identity server. Only change if you know what you are
# doing
#
# IMPORTANT! This will give a malicious or overtaken identity server
# the ability to reset passwords for your users and/or learn your
# user's email/phone numbers! Make absolutely sure that you want to do
# this! It is strongly recommended that these messages be sent by the
# homeserver instead
#
# If this option is an empty string and SMTP options have not been
# configured, registration by email and resetting user passwords via
# email will be disabled
#
# Otherwise, to enable set this option to the reachable domain name, including protocol
# definition, for an identity server (e.g "https://matrix.org")
#
#account_threepid_delegate: ""

# Users who register on this homeserver will automatically be joined
# to these rooms
#
Expand Down Expand Up @@ -1155,19 +1174,6 @@ password_config:
# #
# 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
# #
Expand Down
49 changes: 25 additions & 24 deletions synapse/config/emailconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,33 @@ def read_config(self, config, **kwargs):
"renew_at"
)

email_trust_identity_server_for_password_resets = email_config.get(
"trust_identity_server_for_password_resets", False
self.email_threepid_behaviour = (
# Have Synapse handle the email sending if account_threepid_delegate
# is not defined
"remote"
if self.account_threepid_delegate
else "local"
)
self.email_password_reset_behaviour = (
"remote" if email_trust_identity_server_for_password_resets else "local"
)
self.password_resets_were_disabled_due_to_email_config = False
if self.email_password_reset_behaviour == "local" and email_config == {}:
# Prior to Synapse v1.4.0, there used to be another option that defined whether Synapse
# would use an identity server to password reset tokens on its behalf. We now warn the
# user if they have this set and tell them to use the updated option.
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't warn but kills synapse. I'd strongly prefer to avoid doing this, as otherwise we need to scream from the roof tops that the upgrade may cause your synapse to not start. Can we do something backwards compatible?

Copy link
Member Author

Choose a reason for hiding this comment

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

We need to know what identity server they'd prefer to use to handle registration and password resets. We could just warn them with a message on startup without blocking Synapse start? Not exactly sure where in the codebase we could put the message though, given we can't log here.

Copy link
Member

@erikjohnston erikjohnston Aug 19, 2019

Choose a reason for hiding this comment

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

Can we keep the old behaviour? Of using the first entry in trusted_id_servers, or whatever it does now?

Copy link
Member Author

Choose a reason for hiding this comment

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

We can, though that's another thing relying on the trusted id servers list.

Though this should also be eventually removed, so I say that could probably work.

Copy link
Member Author

Choose a reason for hiding this comment

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

Though if their trusted_third_party_id_servers is empty and trust_identity_server_for_password_resets is set we'll just ConfigError?

Copy link
Member Author

Choose a reason for hiding this comment

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

Though if their trusted_third_party_id_servers is empty and trust_identity_server_for_password_resets is set we'll just ConfigError?

This is what I've done.

# TODO: Eventually we want to remove the functionality of having an identity server
# send tokens on behalf of the homeserver. At that point, we should remove this check
if config.get("trust_identity_server_for_password_resets", False) is True:
raise ConfigError(
'The config option "trust_identity_server_for_password_resets" '
'has been replaced by "account_threepid_delegate". Please '
"consult the default config at docs/sample_config.yaml for "
"details and update your config file."
)

self.local_threepid_emails_disabled_due_to_config = False
if self.email_threepid_behaviour == "local" and email_config == {}:
# We cannot warn the user this has happened here
# Instead do so when a user attempts to reset their password
self.password_resets_were_disabled_due_to_email_config = True
self.local_threepid_emails_disabled_due_to_config = True

self.email_password_reset_behaviour = "off"
self.email_threepid_behaviour = "off"

# Get lifetime of a validation token in milliseconds
self.email_validation_token_lifetime = self.parse_duration(
Expand All @@ -96,7 +110,7 @@ def read_config(self, config, **kwargs):
if (
self.email_enable_notifs
or account_validity_renewal_enabled
or self.email_password_reset_behaviour == "local"
or self.email_threepid_behaviour == "local"
):
# make sure we can import the required deps
import jinja2
Expand All @@ -106,7 +120,7 @@ def read_config(self, config, **kwargs):
jinja2
bleach

if self.email_password_reset_behaviour == "local":
if self.email_threepid_behaviour == "local":
required = ["smtp_host", "smtp_port", "notif_from"]

missing = []
Expand Down Expand Up @@ -239,19 +253,6 @@ def generate_config_section(self, config_dir_path, server_name, **kwargs):
# #
# 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
# #
Expand Down
20 changes: 20 additions & 0 deletions synapse/config/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def read_config(self, config, **kwargs):
self.trusted_third_party_id_servers = config.get(
"trusted_third_party_id_servers", ["matrix.org", "vector.im"]
)
self.account_threepid_delegate = config.get("account_threepid_delegate")
self.default_identity_server = config.get("default_identity_server")
self.allow_guest_access = config.get("allow_guest_access", False)

Expand Down Expand Up @@ -261,6 +262,25 @@ def generate_config_section(self, generate_secrets=False, **kwargs):
# - matrix.org
# - vector.im

# Handle threepid (email/phone etc) registration and password resets
# through an identity server. Only change if you know what you are
# doing
#
# IMPORTANT! This will give a malicious or overtaken identity server
# the ability to reset passwords for your users and/or learn your
# user's email/phone numbers! Make absolutely sure that you want to do
# this! It is strongly recommended that these messages be sent by the
# homeserver instead
#
# If this option is an empty string and SMTP options have not been
# configured, registration by email and resetting user passwords via
# email will be disabled
#
# Otherwise, to enable set this option to the reachable domain name, including protocol
# definition, for an identity server (e.g "https://matrix.org")
#
#account_threepid_delegate: ""

# Users who register on this homeserver will automatically be joined
# to these rooms
#
Expand Down
7 changes: 2 additions & 5 deletions synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,9 @@ def _check_threepid(self, medium, authdict, password_servlet=False, **kwargs):
identity_handler = self.hs.get_handlers().identity_handler

logger.info("Getting validated threepid. threepidcreds: %r", (threepid_creds,))
if (
not password_servlet
or self.hs.config.email_password_reset_behaviour == "remote"
):
if not password_servlet or self.hs.config.email_threepid_behaviour == "remote":
Copy link
Member

Choose a reason for hiding this comment

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

Is doing this for non password reset still the correct thing to do?

Copy link
Member Author

@anoadragon453 anoadragon453 Aug 20, 2019

Choose a reason for hiding this comment

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

This is going to be removed in part 2 of #5835

threepid = yield identity_handler.threepid_from_creds(threepid_creds)
elif self.hs.config.email_password_reset_behaviour == "local":
elif self.hs.config.email_threepid_behaviour == "local":
row = yield self.store.get_threepid_validation_session(
medium,
threepid_creds["client_secret"],
Expand Down
55 changes: 31 additions & 24 deletions synapse/handlers/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@

from twisted.internet import defer

from synapse.api.errors import (
CodeMessageException,
Codes,
HttpResponseException,
SynapseError,
)
from synapse.api.errors import CodeMessageException, HttpResponseException, SynapseError

from ._base import BaseHandler

Expand Down Expand Up @@ -227,14 +222,19 @@ def try_unbind_threepid_with_id_server(self, mxid, threepid, id_server):
return changed

@defer.inlineCallbacks
def requestEmailToken(
self, id_server, email, client_secret, send_attempt, next_link=None
):
if not self._should_trust_id_server(id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server, Codes.SERVER_NOT_TRUSTED
)

def requestEmailToken(self, email, client_secret, send_attempt, next_link=None, **kwargs):
"""
Request an external server send an email on our behalf for the purposes of threepid
validation.
Args:
email (str): The email to send the message to
client_secret (str): The unique client_secret sends by the user
send_attempt (int): Which attempt this is
next_link: A link to redirect the user to once they submit the token
kwargs: extra arguments to send to the server
Returns:
The json response body from the server
"""
params = {
"email": email,
"client_secret": client_secret,
Expand All @@ -245,9 +245,9 @@ def requestEmailToken(
params.update({"next_link": next_link})

try:
id_server = self.hs.config.account_threepid_delegate
data = yield self.http_client.post_json_get_json(
"https://%s%s"
% (id_server, "/_matrix/identity/api/v1/validate/email/requestToken"),
id_server + "/_matrix/identity/api/v1/validate/email/requestToken",
params,
)
return data
Expand All @@ -257,13 +257,20 @@ def requestEmailToken(

@defer.inlineCallbacks
def requestMsisdnToken(
self, id_server, country, phone_number, client_secret, send_attempt, **kwargs
self, country, phone_number, client_secret, send_attempt, **kwargs
):
if not self._should_trust_id_server(id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server, Codes.SERVER_NOT_TRUSTED
)

"""
Request an external server send an SMS message on our behalf for the purposes of
threepid validation.
Args:
country (str): The country code of the phone number
phone_number (str): The number to send the message to
client_secret (str): The unique client_secret sends by the user
send_attempt (int): Which attempt this is
kwargs: extra arguments to send to the server
Returns:
The json response body from the server
"""
params = {
"country": country,
"phone_number": phone_number,
Expand All @@ -273,9 +280,9 @@ def requestMsisdnToken(
params.update(kwargs)

try:
id_server = self.hs.config.account_threepid_delegate
data = yield self.http_client.post_json_get_json(
"https://%s%s"
% (id_server, "/_matrix/identity/api/v1/validate/msisdn/requestToken"),
id_server + "/_matrix/identity/api/v1/validate/msisdn/requestToken",
params,
)
return data
Expand Down
8 changes: 4 additions & 4 deletions synapse/rest/client/v2_alpha/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def __init__(self, hs):
self.config = hs.config
self.identity_handler = hs.get_handlers().identity_handler

if self.config.email_password_reset_behaviour == "local":
if self.config.email_threepid_behaviour == "local":
from synapse.push.mailer import Mailer, load_jinja2_templates

templates = load_jinja2_templates(
Expand All @@ -67,7 +67,7 @@ def __init__(self, hs):

@defer.inlineCallbacks
def on_POST(self, request):
if self.config.email_password_reset_behaviour == "off":
if self.config.email_threepid_behaviour == "off":
if self.config.password_resets_were_disabled_due_to_email_config:
logger.warn(
"User password resets have been disabled due to lack of email config"
Expand Down Expand Up @@ -100,7 +100,7 @@ def on_POST(self, request):
if existingUid is None:
raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)

if self.config.email_password_reset_behaviour == "remote":
if self.config.email_threepid_behaviour == "remote":
if "id_server" not in body:
raise SynapseError(400, "Missing 'id_server' param in body")

Expand Down Expand Up @@ -249,7 +249,7 @@ def on_GET(self, request, medium):
raise SynapseError(
400, "This medium is currently not supported for password resets"
)
if self.config.email_password_reset_behaviour == "off":
if self.config.email_threepid_behaviour == "off":
if self.config.password_resets_were_disabled_due_to_email_config:
logger.warn(
"User password resets have been disabled due to lack of email config"
Expand Down