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

Commit

Permalink
Drop support for delegating email validation (#13192)
Browse files Browse the repository at this point in the history
* Drop support for delegating email validation

Delegating email validation to an IS is insecure (since it allows the owner of
the IS to do a password reset on your HS), and has long been deprecated. It
will now cause a config error at startup.

* Update unit test which checks for email verification

Give it an `email` config instead of a threepid delegate

* Remove unused method `requestEmailToken`

* Simplify config handling for email verification

Rather than an enum and a boolean, all we need here is a single bool, which
says whether we are or are not doing email verification.

* update docs

* changelog

* upgrade.md: fix typo

* update version number

this will be in 1.64, not 1.63

* update version number

this one too
  • Loading branch information
richvdh authored Jul 12, 2022
1 parent 3f17833 commit fa71bb1
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 253 deletions.
7 changes: 5 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Synapse vNext
=============

As of this release, Synapse no longer allows the tasks of verifying email address ownership, and password reset confirmation, to be delegated to an identity server. For more information, see the [upgrade notes](https://github.com/matrix-org/synapse/blob/release-v1.63/docs/upgrade.md#upgrading-to-v1630).

Synapse 1.63.0rc1 (2022-07-12)
==============================

Expand Down Expand Up @@ -73,15 +78,13 @@ Internal Changes
- More aggressively rotate push actions. ([\#13211](https://github.com/matrix-org/synapse/issues/13211))
- Add `max_line_length` setting for Python files to the `.editorconfig`. Contributed by @sumnerevans @ Beeper. ([\#13228](https://github.com/matrix-org/synapse/issues/13228))


Synapse 1.62.0 (2022-07-05)
===========================

No significant changes since 1.62.0rc3.

Authors of spam-checker plugins should consult the [upgrade notes](https://github.com/matrix-org/synapse/blob/release-v1.62/docs/upgrade.md#upgrading-to-v1620) to learn about the enriched signatures for spam checker callbacks, which are supported with this release of Synapse.


Synapse 1.62.0rc3 (2022-07-04)
==============================

Expand Down
1 change: 1 addition & 0 deletions changelog.d/13192.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Drop support for delegating email verification to an external server.
15 changes: 15 additions & 0 deletions docs/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ process, for example:
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
```
# Upgrading to v1.64.0
## Delegation of email validation no longer supported
As of this version, Synapse no longer allows the tasks of verifying email address
ownership, and password reset confirmation, to be delegated to an identity server.
To continue to allow users to add email addresses to their homeserver accounts,
and perform password resets, make sure that Synapse is configured with a
working email server in the `email` configuration section (including, at a
minimum, a `notif_from` setting.)
Specifying an `email` setting under `account_threepid_delegates` will now cause
an error at startup.
# Upgrading to v1.62.0
## New signatures for spam checker callbacks
Expand Down
28 changes: 12 additions & 16 deletions docs/usage/configuration/config_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2168,30 +2168,26 @@ default_identity_server: https://matrix.org
---
### `account_threepid_delegates`

Handle threepid (email/phone etc) registration and password resets through a set of
*trusted* identity servers. Note that this allows the configured identity server to
reset passwords for accounts!
Delegate verification of phone numbers to an identity server.

Be aware that if `email` is not set, and SMTP options have not been
configured in the email config block, registration and user password resets via
email will be globally disabled.
When a user wishes to add a phone number to their account, we need to verify that they
actually own that phone number, which requires sending them a text message (SMS).
Currently Synapse does not support sending those texts itself and instead delegates the
task to an identity server. The base URI for the identity server to be used is
specified by the `account_threepid_delegates.msisdn` option.

Additionally, if `msisdn` is not set, registration and password resets via msisdn
will be disabled regardless, and users will not be able to associate an msisdn
identifier to their account. This is due to Synapse currently not supporting
any method of sending SMS messages on its own.
If this is left unspecified, Synapse will not allow users to add phone numbers to
their account.

To enable using an identity server for operations regarding a particular third-party
identifier type, set the value to the URL of that identity server as shown in the
examples below.
(Servers handling the these requests must answer the `/requestToken` endpoints defined
by the Matrix Identity Service API
[specification](https://matrix.org/docs/spec/identity_service/latest).)

Servers handling the these requests must answer the `/requestToken` endpoints defined
by the Matrix Identity Service API [specification](https://matrix.org/docs/spec/identity_service/latest).
*Updated in Synapse 1.64.0*: No longer accepts an `email` option.

Example configuration:
```yaml
account_threepid_delegates:
email: https://example.com # Delegate email sending to example.com
msisdn: http://localhost:8090 # Delegate SMS sending to this local process
```
---
Expand Down
3 changes: 1 addition & 2 deletions synapse/app/homeserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
register_start,
)
from synapse.config._base import ConfigError, format_config_error
from synapse.config.emailconfig import ThreepidBehaviour
from synapse.config.homeserver import HomeServerConfig
from synapse.config.server import ListenerConfig
from synapse.federation.transport.server import TransportLayerServer
Expand Down Expand Up @@ -202,7 +201,7 @@ def _configure_named_resource(
}
)

if self.config.email.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
if self.config.email.can_verify_email:
from synapse.rest.synapse.client.password_reset import (
PasswordResetSubmitTokenResource,
)
Expand Down
45 changes: 5 additions & 40 deletions synapse/config/emailconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import email.utils
import logging
import os
from enum import Enum
from typing import Any

import attr
Expand Down Expand Up @@ -131,41 +130,22 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:

self.email_enable_notifs = email_config.get("enable_notifs", False)

self.threepid_behaviour_email = (
# Have Synapse handle the email sending if account_threepid_delegates.email
# is not defined
# msisdn is currently always remote while Synapse does not support any method of
# sending SMS messages
ThreepidBehaviour.REMOTE
if self.root.registration.account_threepid_delegate_email
else ThreepidBehaviour.LOCAL
)

if config.get("trust_identity_server_for_password_resets"):
raise ConfigError(
'The config option "trust_identity_server_for_password_resets" '
'has been replaced by "account_threepid_delegate". '
"Please consult the configuration manual at docs/usage/configuration/config_documentation.md for "
"details and update your config file."
"is no longer supported. Please remove it from the config file."
)

self.local_threepid_handling_disabled_due_to_email_config = False
if (
self.threepid_behaviour_email == ThreepidBehaviour.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.local_threepid_handling_disabled_due_to_email_config = True

self.threepid_behaviour_email = ThreepidBehaviour.OFF
# If we have email config settings, assume that we can verify ownership of
# email addresses.
self.can_verify_email = email_config != {}

# 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.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
if self.can_verify_email:
missing = []
if not self.email_notif_from:
missing.append("email.notif_from")
Expand Down Expand Up @@ -356,18 +336,3 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
"Config option email.invite_client_location must be a http or https URL",
path=("email", "invite_client_location"),
)


class ThreepidBehaviour(Enum):
"""
Enum to define the behaviour of Synapse with regards to when it contacts an identity
server for 3pid registration and password resets
REMOTE = use an external server to send tokens
LOCAL = send tokens ourselves
OFF = disable registration via 3pid and password resets
"""

REMOTE = "remote"
LOCAL = "local"
OFF = "off"
11 changes: 10 additions & 1 deletion synapse/config/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
from synapse.types import JsonDict, RoomAlias, UserID
from synapse.util.stringutils import random_string_with_symbols, strtobool

NO_EMAIL_DELEGATE_ERROR = """\
Delegation of email verification to an identity server is no longer supported. To
continue to allow users to add email addresses to their accounts, and use them for
password resets, configure Synapse with an SMTP server via the `email` setting, and
remove `account_threepid_delegates.email`.
"""


class RegistrationConfig(Config):
section = "registration"
Expand Down Expand Up @@ -51,7 +58,9 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
self.bcrypt_rounds = config.get("bcrypt_rounds", 12)

account_threepid_delegates = config.get("account_threepid_delegates") or {}
self.account_threepid_delegate_email = account_threepid_delegates.get("email")
if "email" in account_threepid_delegates:
raise ConfigError(NO_EMAIL_DELEGATE_ERROR)
# self.account_threepid_delegate_email = account_threepid_delegates.get("email")
self.account_threepid_delegate_msisdn = account_threepid_delegates.get("msisdn")
self.default_identity_server = config.get("default_identity_server")
self.allow_guest_access = config.get("allow_guest_access", False)
Expand Down
56 changes: 1 addition & 55 deletions synapse/handlers/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
SynapseError,
)
from synapse.api.ratelimiting import Ratelimiter
from synapse.config.emailconfig import ThreepidBehaviour
from synapse.http import RequestTimedOutError
from synapse.http.client import SimpleHttpClient
from synapse.http.site import SynapseRequest
Expand Down Expand Up @@ -434,48 +433,6 @@ async def send_threepid_validation(

return session_id

async def requestEmailToken(
self,
id_server: str,
email: str,
client_secret: str,
send_attempt: int,
next_link: Optional[str] = None,
) -> JsonDict:
"""
Request an external server send an email on our behalf for the purposes of threepid
validation.
Args:
id_server: The identity server to proxy to
email: The email to send the message to
client_secret: The unique client_secret sends by the user
send_attempt: Which attempt this is
next_link: A link to redirect the user to once they submit the token
Returns:
The json response body from the server
"""
params = {
"email": email,
"client_secret": client_secret,
"send_attempt": send_attempt,
}
if next_link:
params["next_link"] = next_link

try:
data = await self.http_client.post_json_get_json(
id_server + "/_matrix/identity/api/v1/validate/email/requestToken",
params,
)
return data
except HttpResponseException as e:
logger.info("Proxied requestToken failed: %r", e)
raise e.to_synapse_error()
except RequestTimedOutError:
raise SynapseError(500, "Timed out contacting identity server")

async def requestMsisdnToken(
self,
id_server: str,
Expand Down Expand Up @@ -549,18 +506,7 @@ async def validate_threepid_session(
validation_session = None

# Try to validate as email
if self.hs.config.email.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
# Remote emails will only be used if a valid identity server is provided.
assert (
self.hs.config.registration.account_threepid_delegate_email is not None
)

# Ask our delegated email identity server
validation_session = await self.threepid_from_creds(
self.hs.config.registration.account_threepid_delegate_email,
threepid_creds,
)
elif self.hs.config.email.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
if self.hs.config.email.can_verify_email:
# Get a validated session matching these details
validation_session = await self.store.get_threepid_validation_session(
"email", client_secret, sid=sid, validated=True
Expand Down
21 changes: 3 additions & 18 deletions synapse/handlers/ui_auth/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from synapse.api.constants import LoginType
from synapse.api.errors import Codes, LoginError, SynapseError
from synapse.config.emailconfig import ThreepidBehaviour
from synapse.util import json_decoder

if TYPE_CHECKING:
Expand Down Expand Up @@ -153,7 +152,7 @@ async def _check_threepid(self, medium: str, authdict: dict) -> dict:

logger.info("Getting validated threepid. threepidcreds: %r", (threepid_creds,))

# msisdns are currently always ThreepidBehaviour.REMOTE
# msisdns are currently always verified via the IS
if medium == "msisdn":
if not self.hs.config.registration.account_threepid_delegate_msisdn:
raise SynapseError(
Expand All @@ -164,18 +163,7 @@ async def _check_threepid(self, medium: str, authdict: dict) -> dict:
threepid_creds,
)
elif medium == "email":
if (
self.hs.config.email.threepid_behaviour_email
== ThreepidBehaviour.REMOTE
):
assert self.hs.config.registration.account_threepid_delegate_email
threepid = await identity_handler.threepid_from_creds(
self.hs.config.registration.account_threepid_delegate_email,
threepid_creds,
)
elif (
self.hs.config.email.threepid_behaviour_email == ThreepidBehaviour.LOCAL
):
if self.hs.config.email.can_verify_email:
threepid = None
row = await self.store.get_threepid_validation_session(
medium,
Expand Down Expand Up @@ -227,10 +215,7 @@ def __init__(self, hs: "HomeServer"):
_BaseThreepidAuthChecker.__init__(self, hs)

def is_enabled(self) -> bool:
return self.hs.config.email.threepid_behaviour_email in (
ThreepidBehaviour.REMOTE,
ThreepidBehaviour.LOCAL,
)
return self.hs.config.email.can_verify_email

async def check_auth(self, authdict: dict, clientip: str) -> Any:
return await self._check_threepid("email", authdict)
Expand Down
Loading

0 comments on commit fa71bb1

Please sign in to comment.