Merge branch 'master' of github.com:matrix-org/synapse into develop

This commit is contained in:
Erik Johnston 2019-06-11 17:25:16 +01:00
commit 7e68691ce9
18 changed files with 394 additions and 50 deletions

View File

@ -1,3 +1,24 @@
Synapse 1.0.0 (2019-06-11)
==========================
Bugfixes
--------
- Fix bug where attempting to send transactions with large number of EDUs can fail. ([\#5418](https://github.com/matrix-org/synapse/issues/5418))
Improved Documentation
----------------------
- Expand the federation guide to include relevant content from the MSC1711 FAQ ([\#5419](https://github.com/matrix-org/synapse/issues/5419))
Internal Changes
----------------
- Move password reset links to /_matrix/client/unstable namespace. ([\#5424](https://github.com/matrix-org/synapse/issues/5424))
Synapse 1.0.0rc3 (2019-06-10) Synapse 1.0.0rc3 (2019-06-10)
============================= =============================

View File

@ -1,14 +1,14 @@
* [Installing Synapse](#installing-synapse) - [Installing Synapse](#installing-synapse)
* [Installing from source](#installing-from-source) - [Installing from source](#installing-from-source)
* [Platform-Specific Instructions](#platform-specific-instructions) - [Platform-Specific Instructions](#platform-specific-instructions)
* [Troubleshooting Installation](#troubleshooting-installation) - [Troubleshooting Installation](#troubleshooting-installation)
* [Prebuilt packages](#prebuilt-packages) - [Prebuilt packages](#prebuilt-packages)
* [Setting up Synapse](#setting-up-synapse) - [Setting up Synapse](#setting-up-synapse)
* [TLS certificates](#tls-certificates) - [TLS certificates](#tls-certificates)
* [Email](#email) - [Email](#email)
* [Registering a user](#registering-a-user) - [Registering a user](#registering-a-user)
* [Setting up a TURN server](#setting-up-a-turn-server) - [Setting up a TURN server](#setting-up-a-turn-server)
* [URL previews](#url-previews) - [URL previews](#url-previews)
# Installing Synapse # Installing Synapse
@ -395,8 +395,9 @@ To configure Synapse to expose an HTTPS port, you will need to edit
instance, if using certbot, use `fullchain.pem` as your certificate, not instance, if using certbot, use `fullchain.pem` as your certificate, not
`cert.pem`). `cert.pem`).
For those of you upgrading your TLS certificate for Synapse 1.0 compliance, For a more detailed guide to configuring your server for federation, see
please take a look at [our guide](docs/MSC1711_certificates_FAQ.md#configuring-certificates-for-compatibility-with-synapse-100). [federate.md](docs/federate.md)
## Email ## Email

View File

@ -1 +0,0 @@
Fix bug where attempting to send transactions with large number of EDUs can fail.

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
matrix-synapse-py3 (1.0.0) stable; urgency=medium
* New synapse release 1.0.0.
-- Synapse Packaging team <packages@matrix.org> Tue, 11 Jun 2019 17:09:53 +0100
matrix-synapse-py3 (0.99.5.2) stable; urgency=medium matrix-synapse-py3 (0.99.5.2) stable; urgency=medium
* New synapse release 0.99.5.2. * New synapse release 0.99.5.2.

View File

@ -1,5 +1,22 @@
# MSC1711 Certificates FAQ # MSC1711 Certificates FAQ
## Historical Note
This document was originally written to guide server admins through the upgrade
path towards Synapse 1.0. Specifically,
[MSC1711](https://github.com/matrix-org/matrix-doc/blob/master/proposals/1711-x509-for-federation.md)
required that all servers present valid TLS certificates on their federation
API. Admins were encouraged to achieve compliance from version 0.99.0 (released
in February 2019) ahead of version 1.0 (released June 2019) enforcing the
certificate checks.
Much of what follows is now outdated since most admins will have already
upgraded, however it may be of use to those with old installs returning to the
project.
If you are setting up a server from scratch you almost certainly should look at
the [installation guide](INSTALL.md) instead.
## Introduction
The goal of Synapse 0.99.0 is to act as a stepping stone to Synapse 1.0.0. It The goal of Synapse 0.99.0 is to act as a stepping stone to Synapse 1.0.0. It
supports the r0.1 release of the server to server specification, but is supports the r0.1 release of the server to server specification, but is
compatible with both the legacy Matrix federation behaviour (pre-r0.1) as well compatible with both the legacy Matrix federation behaviour (pre-r0.1) as well

View File

@ -14,9 +14,9 @@ up and will work provided you set the ``server_name`` to match your
machine's public DNS hostname, and provide Synapse with a TLS certificate machine's public DNS hostname, and provide Synapse with a TLS certificate
which is valid for your ``server_name``. which is valid for your ``server_name``.
Once you have completed the steps necessary to federate, you should be able to Once federation has been configured, you should be able to join a room over
join a room via federation. (A good place to start is ``#synapse:matrix.org`` - a federation. A good place to start is ``#synapse:matrix.org`` - a room for
room for Synapse admins.) Synapse admins.
## Delegation ## Delegation
@ -98,6 +98,77 @@ _matrix._tcp.<server_name>``. In our example, we would expect this:
Note that the target of a SRV record cannot be an alias (CNAME record): it has to point Note that the target of a SRV record cannot be an alias (CNAME record): it has to point
directly to the server hosting the synapse instance. directly to the server hosting the synapse instance.
### Delegation FAQ
#### When do I need a SRV record or .well-known URI?
If your homeserver listens on the default federation port (8448), and your
`server_name` points to the host that your homeserver runs on, you do not need an SRV
record or `.well-known/matrix/server` URI.
For instance, if you registered `example.com` and pointed its DNS A record at a
fresh server, you could install Synapse on that host,
giving it a `server_name` of `example.com`, and once [ACME](acme.md) support is enabled,
it would automatically generate a valid TLS certificate for you via Let's Encrypt
and no SRV record or .well-known URI would be needed.
This is the common case, although you can add an SRV record or
`.well-known/matrix/server` URI for completeness if you wish.
**However**, if your server does not listen on port 8448, or if your `server_name`
does not point to the host that your homeserver runs on, you will need to let
other servers know how to find it. The way to do this is via .well-known or an
SRV record.
#### I have created a .well-known URI. Do I still need an SRV record?
As of Synapse 0.99, Synapse will first check for the existence of a .well-known
URI and follow any delegation it suggests. It will only then check for the
existence of an SRV record.
That means that the SRV record will often be redundant. However, you should
remember that there may still be older versions of Synapse in the federation
which do not understand .well-known URIs, so if you removed your SRV record
you would no longer be able to federate with them.
It is therefore best to leave the SRV record in place for now. Synapse 0.34 and
earlier will follow the SRV record (and not care about the invalid
certificate). Synapse 0.99 and later will follow the .well-known URI, with the
correct certificate chain.
#### Can I manage my own certificates rather than having Synapse renew certificates itself?
Yes, you are welcome to manage your certificates yourself. Synapse will only
attempt to obtain certificates from Let's Encrypt if you configure it to do
so.The only requirement is that there is a valid TLS cert present for
federation end points.
#### Do you still recommend against using a reverse proxy on the federation port?
We no longer actively recommend against using a reverse proxy. Many admins will
find it easier to direct federation traffic to a reverse proxy and manage their
own TLS certificates, and this is a supported configuration.
See [reverse_proxy.rst](reverse_proxy.rst) for information on setting up a
reverse proxy.
#### Do I still need to give my TLS certificates to Synapse if I am using a reverse proxy?
Practically speaking, this is no longer necessary.
If you are using a reverse proxy for all of your TLS traffic, then you can set
`no_tls: True` in the Synapse config. In that case, the only reason Synapse
needs the certificate is to populate a legacy `tls_fingerprints` field in the
federation API. This is ignored by Synapse 0.99.0 and later, and the only time
pre-0.99 Synapses will check it is when attempting to fetch the server keys -
and generally this is delegated via `matrix.org`, which will be running a modern
version of Synapse.
#### Do I need the same certificate for the client and federation port?
No. There is nothing stopping you from using different certificates,
particularly if you are using a reverse proxy. However, Synapse will use the
same certificate on any ports where TLS is configured.
## Troubleshooting ## Troubleshooting
You can use the [federation tester]( You can use the [federation tester](

View File

@ -27,4 +27,4 @@ try:
except ImportError: except ImportError:
pass pass
__version__ = "1.0.0rc3" __version__ = "1.0.0"

View File

@ -176,7 +176,6 @@ class SynapseHomeServer(HomeServer):
resources.update({ resources.update({
"/_matrix/client/api/v1": client_resource, "/_matrix/client/api/v1": client_resource,
"/_synapse/password_reset": client_resource,
"/_matrix/client/r0": client_resource, "/_matrix/client/r0": client_resource,
"/_matrix/client/unstable": client_resource, "/_matrix/client/unstable": client_resource,
"/_matrix/client/v2_alpha": client_resource, "/_matrix/client/v2_alpha": client_resource,

View File

@ -117,7 +117,7 @@ class Mailer(object):
link = ( link = (
self.hs.config.public_baseurl + self.hs.config.public_baseurl +
"_synapse/password_reset/email/submit_token" "_matrix/client/unstable/password_reset/email/submit_token"
"?token=%s&client_secret=%s&sid=%s" % "?token=%s&client_secret=%s&sid=%s" %
(token, client_secret, sid) (token, client_secret, sid)
) )

View File

@ -80,7 +80,7 @@ REQUIREMENTS = [
] ]
CONDITIONAL_REQUIREMENTS = { CONDITIONAL_REQUIREMENTS = {
"email": ["Jinja2>=2.9", "bleach>=1.4.2"], "email": ["Jinja2>=2.9", "bleach>=1.4.3"],
"matrix-synapse-ldap3": ["matrix-synapse-ldap3>=0.1"], "matrix-synapse-ldap3": ["matrix-synapse-ldap3>=0.1"],
# we use execute_batch, which arrived in psycopg 2.7. # we use execute_batch, which arrived in psycopg 2.7.

View File

@ -1,6 +1,6 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p>Your password was successfully reset. You may now close this window.</p> <p>Your email has now been validated, please return to your client to reset your password. You may now close this window.</p>
</body> </body>
</html> </html>

View File

@ -15,7 +15,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import logging import logging
import re
from six.moves import http_client from six.moves import http_client
@ -231,9 +230,11 @@ class MsisdnPasswordRequestTokenRestServlet(RestServlet):
class PasswordResetSubmitTokenServlet(RestServlet): class PasswordResetSubmitTokenServlet(RestServlet):
"""Handles 3PID validation token submission""" """Handles 3PID validation token submission"""
PATTERNS = [ PATTERNS = client_patterns(
re.compile("^/_synapse/password_reset/(?P<medium>[^/]*)/submit_token/*$"), "/password_reset/(?P<medium>[^/]*)/submit_token/*$",
] releases=(),
unstable=True,
)
def __init__(self, hs): def __init__(self, hs):
""" """

View File

@ -24,15 +24,9 @@ from synapse.rest.client.v1 import login, room
from tests.unittest import HomeserverTestCase from tests.unittest import HomeserverTestCase
try:
from synapse.push.mailer import load_jinja2_templates
except Exception:
load_jinja2_templates = None
class EmailPusherTests(HomeserverTestCase): class EmailPusherTests(HomeserverTestCase):
skip = "No Jinja installed" if not load_jinja2_templates else None
servlets = [ servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource, synapse.rest.admin.register_servlets_for_client_rest_resource,
room.register_servlets, room.register_servlets,

View File

@ -23,15 +23,9 @@ from synapse.util.logcontext import make_deferred_yieldable
from tests.unittest import HomeserverTestCase from tests.unittest import HomeserverTestCase
try:
from synapse.push.mailer import load_jinja2_templates
except Exception:
load_jinja2_templates = None
class HTTPPusherTests(HomeserverTestCase): class HTTPPusherTests(HomeserverTestCase):
skip = "No Jinja installed" if not load_jinja2_templates else None
servlets = [ servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource, synapse.rest.admin.register_servlets_for_client_rest_resource,
room.register_servlets, room.register_servlets,

View File

@ -23,14 +23,8 @@ from synapse.rest.consent import consent_resource
from tests import unittest from tests import unittest
from tests.server import render from tests.server import render
try:
from synapse.push.mailer import load_jinja2_templates
except Exception:
load_jinja2_templates = None
class ConsentResourceTestCase(unittest.HomeserverTestCase): class ConsentResourceTestCase(unittest.HomeserverTestCase):
skip = "No Jinja installed" if not load_jinja2_templates else None
servlets = [ servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource, synapse.rest.admin.register_servlets_for_client_rest_resource,
room.register_servlets, room.register_servlets,

View File

@ -0,0 +1,241 @@
# -*- coding: utf-8 -*-
# Copyright 2015-2016 OpenMarket Ltd
# Copyright 2017-2018 New Vector Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import re
from email.parser import Parser
import pkg_resources
import synapse.rest.admin
from synapse.api.constants import LoginType
from synapse.rest.client.v1 import login
from synapse.rest.client.v2_alpha import account, register
from tests import unittest
class PasswordResetTestCase(unittest.HomeserverTestCase):
servlets = [
account.register_servlets,
synapse.rest.admin.register_servlets_for_client_rest_resource,
register.register_servlets,
login.register_servlets,
]
def make_homeserver(self, reactor, clock):
config = self.default_config()
# Email config.
self.email_attempts = []
def sendmail(smtphost, from_addr, to_addrs, msg, **kwargs):
self.email_attempts.append(msg)
return
config["email"] = {
"enable_notifs": False,
"template_dir": os.path.abspath(
pkg_resources.resource_filename("synapse", "res/templates")
),
"smtp_host": "127.0.0.1",
"smtp_port": 20,
"require_transport_security": False,
"smtp_user": None,
"smtp_pass": None,
"notif_from": "test@example.com",
}
config["public_baseurl"] = "https://example.com"
hs = self.setup_test_homeserver(config=config, sendmail=sendmail)
return hs
def prepare(self, reactor, clock, hs):
self.store = hs.get_datastore()
def test_basic_password_reset(self):
"""Test basic password reset flow
"""
old_password = "monkey"
new_password = "kangeroo"
user_id = self.register_user("kermit", old_password)
self.login("kermit", old_password)
email = "test@example.com"
# Add a threepid
self.get_success(
self.store.user_add_threepid(
user_id=user_id,
medium="email",
address=email,
validated_at=0,
added_at=0,
)
)
client_secret = "foobar"
session_id = self._request_token(email, client_secret)
self.assertEquals(len(self.email_attempts), 1)
link = self._get_link_from_email()
self._validate_token(link)
self._reset_password(new_password, session_id, client_secret)
# Assert we can log in with the new password
self.login("kermit", new_password)
# Assert we can't log in with the old password
self.attempt_wrong_password_login("kermit", old_password)
def test_cant_reset_password_without_clicking_link(self):
"""Test that we do actually need to click the link in the email
"""
old_password = "monkey"
new_password = "kangeroo"
user_id = self.register_user("kermit", old_password)
self.login("kermit", old_password)
email = "test@example.com"
# Add a threepid
self.get_success(
self.store.user_add_threepid(
user_id=user_id,
medium="email",
address=email,
validated_at=0,
added_at=0,
)
)
client_secret = "foobar"
session_id = self._request_token(email, client_secret)
self.assertEquals(len(self.email_attempts), 1)
# Attempt to reset password without clicking the link
self._reset_password(
new_password, session_id, client_secret, expected_code=401,
)
# Assert we can log in with the old password
self.login("kermit", old_password)
# Assert we can't log in with the new password
self.attempt_wrong_password_login("kermit", new_password)
def test_no_valid_token(self):
"""Test that we do actually need to request a token and can't just
make a session up.
"""
old_password = "monkey"
new_password = "kangeroo"
user_id = self.register_user("kermit", old_password)
self.login("kermit", old_password)
email = "test@example.com"
# Add a threepid
self.get_success(
self.store.user_add_threepid(
user_id=user_id,
medium="email",
address=email,
validated_at=0,
added_at=0,
)
)
client_secret = "foobar"
session_id = "weasle"
# Attempt to reset password without even requesting an email
self._reset_password(
new_password, session_id, client_secret, expected_code=401,
)
# Assert we can log in with the old password
self.login("kermit", old_password)
# Assert we can't log in with the new password
self.attempt_wrong_password_login("kermit", new_password)
def _request_token(self, email, client_secret):
request, channel = self.make_request(
"POST",
b"account/password/email/requestToken",
{"client_secret": client_secret, "email": email, "send_attempt": 1},
)
self.render(request)
self.assertEquals(200, channel.code, channel.result)
return channel.json_body["sid"]
def _validate_token(self, link):
# Remove the host
path = link.replace("https://example.com", "")
request, channel = self.make_request("GET", path, shorthand=False)
self.render(request)
self.assertEquals(200, channel.code, channel.result)
def _get_link_from_email(self):
assert self.email_attempts, "No emails have been sent"
raw_msg = self.email_attempts[-1].decode("UTF-8")
mail = Parser().parsestr(raw_msg)
text = None
for part in mail.walk():
if part.get_content_type() == "text/plain":
text = part.get_payload(decode=True).decode("UTF-8")
break
if not text:
self.fail("Could not find text portion of email to parse")
match = re.search(r"https://example.com\S+", text)
assert match, "Could not find link in email"
return match.group(0)
def _reset_password(
self, new_password, session_id, client_secret, expected_code=200
):
request, channel = self.make_request(
"POST",
b"account/password",
{
"new_password": new_password,
"auth": {
"type": LoginType.EMAIL_IDENTITY,
"threepid_creds": {
"client_secret": client_secret,
"sid": session_id,
},
},
},
)
self.render(request)
self.assertEquals(expected_code, channel.code, channel.result)

View File

@ -30,11 +30,6 @@ from synapse.rest.client.v2_alpha import account_validity, register, sync
from tests import unittest from tests import unittest
try:
from synapse.push.mailer import load_jinja2_templates
except ImportError:
load_jinja2_templates = None
class RegisterRestServletTestCase(unittest.HomeserverTestCase): class RegisterRestServletTestCase(unittest.HomeserverTestCase):
@ -307,7 +302,6 @@ class AccountValidityTestCase(unittest.HomeserverTestCase):
class AccountValidityRenewalByEmailTestCase(unittest.HomeserverTestCase): class AccountValidityRenewalByEmailTestCase(unittest.HomeserverTestCase):
skip = "No Jinja installed" if not load_jinja2_templates else None
servlets = [ servlets = [
register.register_servlets, register.register_servlets,
synapse.rest.admin.register_servlets_for_client_rest_resource, synapse.rest.admin.register_servlets_for_client_rest_resource,

View File

@ -441,3 +441,15 @@ class HomeserverTestCase(TestCase):
access_token = channel.json_body["access_token"] access_token = channel.json_body["access_token"]
return access_token return access_token
def attempt_wrong_password_login(self, username, password):
"""Attempts to login as the user with the given password, asserting
that the attempt *fails*.
"""
body = {"type": "m.login.password", "user": username, "password": password}
request, channel = self.make_request(
"POST", "/_matrix/client/r0/login", json.dumps(body).encode('utf8')
)
self.render(request)
self.assertEqual(channel.code, 403, channel.result)