1
0

Compare commits

...

31 Commits

Author SHA1 Message Date
Richard van der Hoff 45ad44b076 Fix typo
Co-Authored-By: anoadragon453 <1342360+anoadragon453@users.noreply.github.com>
2019-01-21 16:05:29 +00:00
Andrew Morgan 8b0a9b3ad7 Set default config value for tests 2019-01-17 13:23:16 +00:00
Andrew Morgan 53f8936b40 Simplify code slightly 2019-01-17 12:09:31 +00:00
Andrew Morgan 439d71a8d1 Fix missing hs property 2019-01-17 12:03:48 +00:00
Andrew Morgan a82b682b07 linting 2019-01-17 10:52:04 +00:00
Andrew Morgan 1128d9b9b2 Clarify this is not for use with a SOCKS proxy 2019-01-16 17:36:20 +00:00
Andrew Morgan 2c9ce72071 Add changelog file 2019-01-16 17:23:08 +00:00
Andrew Morgan 6a83652dee Allow for Synapse to run through a http proxy
Signed-off-by: Andrew Morgan <andrew@amorgan.xyz>
2019-01-16 17:17:50 +00:00
Amber Brown ea00f18135 Merge Synapse v0.34.1.1 2019-01-11 02:21:54 +11:00
Amber Brown c0dba73aa0 changelog, for debian 2019-01-11 02:20:29 +11:00
Amber Brown 5c792ee5c3 changelog 2019-01-11 01:59:10 +11:00
Amber Brown 6dc06c3775 version 2019-01-11 01:56:37 +11:00
Amber Brown 3933ce9f13 Merge pull request #4374 from matrix-org/rav/macaroon_key_fix_0.34.1
Fix spontaneous logout
2019-01-11 01:48:53 +11:00
Richard van der Hoff de80e979c9 changelog 2019-01-10 14:26:01 +00:00
Richard van der Hoff e0910d0145 Merge branch rav/macaroon_key_fix_0.34 into rav/macaroon_key_fix_0.34.1
Fixes #4371
2019-01-10 14:12:50 +00:00
Richard van der Hoff ba41aeed6a Revert "Fix macaroon_secret_key fallback logic"
This is already fixed in 0.34.1, by 59f93bb

This reverts commit efc522c55e.
2019-01-10 14:09:26 +00:00
Richard van der Hoff 4f24452ead changelog 2019-01-10 14:00:23 +00:00
Richard van der Hoff aa70d24125 Merge branch 'rav/macaroon_key_fix' into rav/macaroon_key_fix_0.34 2019-01-10 12:58:33 +00:00
Richard van der Hoff efc522c55e Fix macaroon_secret_key fallback logic 2019-01-10 12:57:27 +00:00
Richard van der Hoff 566947ff34 Skip macaroon check for access tokens in the db 2019-01-10 12:57:21 +00:00
Richard van der Hoff 353f2407b7 Fix fallback to signing key for macaroon-secret-key 2019-01-10 12:42:56 +00:00
Richard van der Hoff 95fca1c7e9 fix docker build to install optional deps 2019-01-09 16:37:51 +00:00
Richard van der Hoff 2394e832a8 debian: Remove Breaks: matrix-synapse-ldap3 2019-01-09 15:35:11 +00:00
Richard van der Hoff 998f5225c1 0.34.1 2019-01-09 14:53:54 +00:00
Erik Johnston 484867d35d Merge branch 'develop' into release-v0.34.1 2019-01-09 11:38:13 +00:00
Erik Johnston d1d81d0651 Merge pull request #4362 from matrix-org/erikj/better_errors
Use RequestSendFailed when fail to parse content type headers
2019-01-09 09:08:35 +00:00
Erik Johnston d91b99abe0 Newsfile 2019-01-08 14:24:05 +00:00
Erik Johnston d422570e9b Use RequestSendFailed when fail to parse content type headers 2019-01-08 14:22:18 +00:00
Erik Johnston c4530b97b2 Merge pull request #4361 from matrix-org/erikj/better_errors
Don't log stack traces for HTTP error responses
2019-01-08 14:19:00 +00:00
Erik Johnston 83c50bf752 Newsfile 2019-01-08 12:28:35 +00:00
Erik Johnston 1371d5b798 Don't log stack traces for HTTP error responses 2019-01-08 12:28:30 +00:00
13 changed files with 126 additions and 212 deletions
+23
View File
@@ -1,3 +1,26 @@
Synapse 0.34.1.1 (2019-01-11)
=============================
This release fixes CVE-2019-5885 and is recommended for all users of Synapse 0.34.1.
This release is compatible with Python 2.7 and 3.5+. Python 3.7 is fully supported.
Bugfixes
--------
- Fix spontaneous logout on upgrade
([\#4374](https://github.com/matrix-org/synapse/issues/4374))
Synapse 0.34.1 (2019-01-09)
===========================
Internal Changes
----------------
- Add better logging for unexpected errors while sending transactions ([\#4361](https://github.com/matrix-org/synapse/issues/4361), [\#4362](https://github.com/matrix-org/synapse/issues/4362))
Synapse 0.34.1rc1 (2019-01-08)
==============================
+1
View File
@@ -0,0 +1 @@
Add a simple HTTP proxy option for Synapse to send federation traffic through before reaching other servers.
+17 -2
View File
@@ -1,9 +1,24 @@
matrix-synapse-py3 (0.34.0.1) UNRELEASED; urgency=medium
matrix-synapse-py3 (0.34.1.1) stable; urgency=high
* New synapse release 0.34.1.1
-- Synapse Packaging team <packages@matrix.org> Thu, 10 Jan 2019 15:04:52 +0000
matrix-synapse-py3 (0.34.1+1) stable; urgency=medium
* Remove 'Breaks: matrix-synapse-ldap3'. (matrix-synapse-py3 includes
the matrix-synapse-ldap3 python files, which makes the
matrix-synapse-ldap3 debian package redundant but not broken.
-- Synapse Packaging team <packages@matrix.org> Wed, 09 Jan 2019 15:30:00 +0000
matrix-synapse-py3 (0.34.1) stable; urgency=medium
* New synapse release 0.34.1.
* Update Conflicts specifications to allow installation alongside our
matrix-synapse transitional package.
-- Synapse Packaging team <packages@matrix.org> Wed, 02 Jan 2019 17:48:40 +0000
-- Synapse Packaging team <packages@matrix.org> Wed, 09 Jan 2019 14:52:24 +0000
matrix-synapse-py3 (0.34.0) stable; urgency=medium
-1
View File
@@ -20,7 +20,6 @@ Package: matrix-synapse-py3
Architecture: amd64
Provides: matrix-synapse
Breaks:
matrix-synapse-ldap3,
matrix-synapse (<< 0.34.0-0matrix2),
matrix-synapse (>= 0.34.0-1),
Pre-Depends: dpkg (>= 1.16.1)
+1 -3
View File
@@ -33,9 +33,7 @@ RUN pip install --prefix="/install" --no-warn-script-location \
COPY . /synapse
RUN pip install --prefix="/install" --no-warn-script-location \
lxml \
psycopg2 \
/synapse
/synapse[all]
###
### Stage 1: runtime
+1 -1
View File
@@ -27,4 +27,4 @@ try:
except ImportError:
pass
__version__ = "0.34.1rc1"
__version__ = "0.34.1.1"
+28 -39
View File
@@ -300,20 +300,28 @@ class Auth(object):
Raises:
AuthError if no user by that token exists or the token is invalid.
"""
if rights == "access":
# first look in the database
r = yield self._look_up_user_by_access_token(token)
if r:
defer.returnValue(r)
# otherwise it needs to be a valid macaroon
try:
user_id, guest = self._parse_and_validate_macaroon(token, rights)
except _InvalidMacaroonException:
# doesn't look like a macaroon: treat it as an opaque token which
# must be in the database.
# TODO: it would be nice to get rid of this, but apparently some
# people use access tokens which aren't macaroons
r = yield self._look_up_user_by_access_token(token)
defer.returnValue(r)
try:
user = UserID.from_string(user_id)
if guest:
if rights == "access":
if not guest:
# non-guest access tokens must be in the database
logger.warning("Unrecognised access token - not in store.")
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS,
"Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN,
)
# Guest access tokens are not stored in the database (there can
# only be one access token per guest, anyway).
#
@@ -354,31 +362,15 @@ class Auth(object):
"device_id": None,
}
else:
# This codepath exists for several reasons:
# * so that we can actually return a token ID, which is used
# in some parts of the schema (where we probably ought to
# use device IDs instead)
# * the only way we currently have to invalidate an
# access_token is by removing it from the database, so we
# have to check here that it is still in the db
# * some attributes (notably device_id) aren't stored in the
# macaroon. They probably should be.
# TODO: build the dictionary from the macaroon once the
# above are fixed
ret = yield self._look_up_user_by_access_token(token)
if ret["user"] != user:
logger.error(
"Macaroon user (%s) != DB user (%s)",
user,
ret["user"]
)
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS,
"User mismatch in macaroon",
errcode=Codes.UNKNOWN_TOKEN
)
raise RuntimeError("Unknown rights setting %s", rights)
defer.returnValue(ret)
except (pymacaroons.exceptions.MacaroonException, TypeError, ValueError):
except (
_InvalidMacaroonException,
pymacaroons.exceptions.MacaroonException,
TypeError,
ValueError,
) as e:
logger.warning("Invalid macaroon in auth: %s %s", type(e), e)
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Invalid macaroon passed.",
errcode=Codes.UNKNOWN_TOKEN
@@ -508,11 +500,8 @@ class Auth(object):
def _look_up_user_by_access_token(self, token):
ret = yield self.store.get_user_by_access_token(token)
if not ret:
logger.warn("Unrecognised access token - not in store.")
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN
)
defer.returnValue(None)
# we use ret.get() below because *lots* of unit tests stub out
# get_user_by_access_token in a way where it only returns a couple of
# the fields.
+2 -2
View File
@@ -57,8 +57,8 @@ class KeyConfig(Config):
# Unfortunately, there are people out there that don't have this
# set. Lets just be "nice" and derive one from their secret key.
logger.warn("Config is missing missing macaroon_secret_key")
seed = self.signing_key[0].seed
self.macaroon_secret_key = hashlib.sha256(seed)
seed = bytes(self.signing_key[0])
self.macaroon_secret_key = hashlib.sha256(seed).digest()
self.expire_access_token = config.get("expire_access_token", False)
+16
View File
@@ -107,12 +107,23 @@ class ServerConfig(Config):
federation_domain_whitelist = config.get(
"federation_domain_whitelist", None
)
# turn the whitelist into a hash for speed of lookup
if federation_domain_whitelist is not None:
self.federation_domain_whitelist = {}
for domain in federation_domain_whitelist:
self.federation_domain_whitelist[domain] = True
# Optional proxy address for federation traffic
self.federation_request_gateway_addr = config.get(
"federation_request_gateway_addr", None
)
if self.federation_request_gateway_addr is not None:
# Ensure proxy address is correctly formatted
if len(self.federation_request_gateway_addr.split(':')) != 2:
self.federation_request_gateway_addr = None
if self.public_baseurl is not None:
if self.public_baseurl[-1] != '/':
self.public_baseurl += '/'
@@ -289,6 +300,11 @@ class ServerConfig(Config):
# - nyc.example.com
# - syd.example.com
# Send outbound federation requests through a seperate traffic gateway.
# Not intended to be used with a SOCKS proxy, but rather a relay for
# HTTP traffic.
# federation_request_gateway_addr: localhost:1234
# List of ports that Synapse should listen on, their purpose and their
# configuration.
listeners:
+6 -1
View File
@@ -522,8 +522,13 @@ class TransactionQueue(object):
)
except FederationDeniedError as e:
logger.info(e)
except HttpResponseException as e:
logger.warning(
"TX [%s] Received %d response to transaction: %s",
destination, e.code, e,
)
except RequestSendFailed as e:
logger.warning("(TX [%s] Failed to send transaction: %s", destination, e)
logger.warning("TX [%s] Failed to send transaction: %s", destination, e)
for p, _ in pending_pdus:
logger.info("Failed to send event %s to %s", p.event_id,
+29 -9
View File
@@ -56,7 +56,6 @@ outgoing_requests_counter = Counter("synapse_http_matrixfederationclient_request
incoming_responses_counter = Counter("synapse_http_matrixfederationclient_responses",
"", ["method", "code"])
MAX_LONG_RETRIES = 10
MAX_SHORT_RETRIES = 3
@@ -66,6 +65,19 @@ else:
MAXINT = sys.maxint
class ProxyMatrixFederationEndpointFactory(object):
def __init__(self, hs):
self.reactor = hs.get_reactor()
self.tls_client_options_factory = hs.tls_client_options_factory
self.gateway_addr = hs.config.federation_request_gateway_addr
def endpointForURI(self, uri):
return matrix_federation_endpoint(
self.reactor, self.gateway_addr, timeout=10,
tls_client_options_factory=None
)
class MatrixFederationEndpointFactory(object):
def __init__(self, hs):
self.reactor = hs.get_reactor()
@@ -186,14 +198,22 @@ class MatrixFederationHttpClient(object):
self.hs = hs
self.signing_key = hs.config.signing_key[0]
self.server_name = hs.hostname
self.gateway_addr = hs.config.federation_request_gateway_addr
reactor = hs.get_reactor()
pool = HTTPConnectionPool(reactor)
pool.retryAutomatically = False
pool.maxPersistentPerHost = 5
pool.cachedConnectionTimeout = 2 * 60
self.agent = Agent.usingEndpointFactory(
reactor, MatrixFederationEndpointFactory(hs), pool=pool
)
if self.gateway_addr:
self.agent = Agent.usingEndpointFactory(
reactor, ProxyMatrixFederationEndpointFactory(hs), pool=pool
)
else:
self.agent = Agent.usingEndpointFactory(
reactor, MatrixFederationEndpointFactory(hs), pool=pool
)
self.clock = hs.get_clock()
self._store = hs.get_datastore()
self.version_string_bytes = hs.version_string.encode('ascii')
@@ -823,21 +843,21 @@ def check_content_type_is_json(headers):
headers (twisted.web.http_headers.Headers): headers to check
Raises:
RuntimeError if the
RequestSendFailed: if the Content-Type header is missing or isn't JSON
"""
c_type = headers.getRawHeaders(b"Content-Type")
if c_type is None:
raise RuntimeError(
raise RequestSendFailed(RuntimeError(
"No Content-Type header"
)
), can_retry=False)
c_type = c_type[0].decode('ascii') # only the first header
val, options = cgi.parse_header(c_type)
if val != "application/json":
raise RuntimeError(
raise RequestSendFailed(RuntimeError(
"Content-Type not application/json: was '%s'" % c_type
)
), can_retry=False)
def encode_query_args(args):
+1 -154
View File
@@ -194,8 +194,6 @@ class AuthTestCase(unittest.TestCase):
@defer.inlineCallbacks
def test_get_user_from_macaroon(self):
# TODO(danielwh): Remove this mock when we remove the
# get_user_by_access_token fallback.
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org", "device_id": "device"}
)
@@ -220,6 +218,7 @@ class AuthTestCase(unittest.TestCase):
@defer.inlineCallbacks
def test_get_guest_user_from_macaroon(self):
self.store.get_user_by_id = Mock(return_value={"is_guest": True})
self.store.get_user_by_access_token = Mock(return_value=None)
user_id = "@baldrick:matrix.org"
macaroon = pymacaroons.Macaroon(
@@ -240,158 +239,6 @@ class AuthTestCase(unittest.TestCase):
self.assertTrue(is_guest)
self.store.get_user_by_id.assert_called_with(user_id)
@defer.inlineCallbacks
def test_get_user_from_macaroon_user_db_mismatch(self):
self.store.get_user_by_access_token = Mock(
return_value={"name": "@percy:matrix.org"}
)
user = "@baldrick:matrix.org"
macaroon = pymacaroons.Macaroon(
location=self.hs.config.server_name,
identifier="key",
key=self.hs.config.macaroon_secret_key,
)
macaroon.add_first_party_caveat("gen = 1")
macaroon.add_first_party_caveat("type = access")
macaroon.add_first_party_caveat("user_id = %s" % (user,))
with self.assertRaises(AuthError) as cm:
yield self.auth.get_user_by_access_token(macaroon.serialize())
self.assertEqual(401, cm.exception.code)
self.assertIn("User mismatch", cm.exception.msg)
@defer.inlineCallbacks
def test_get_user_from_macaroon_missing_caveat(self):
# TODO(danielwh): Remove this mock when we remove the
# get_user_by_access_token fallback.
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
macaroon = pymacaroons.Macaroon(
location=self.hs.config.server_name,
identifier="key",
key=self.hs.config.macaroon_secret_key,
)
macaroon.add_first_party_caveat("gen = 1")
macaroon.add_first_party_caveat("type = access")
with self.assertRaises(AuthError) as cm:
yield self.auth.get_user_by_access_token(macaroon.serialize())
self.assertEqual(401, cm.exception.code)
self.assertIn("No user caveat", cm.exception.msg)
@defer.inlineCallbacks
def test_get_user_from_macaroon_wrong_key(self):
# TODO(danielwh): Remove this mock when we remove the
# get_user_by_access_token fallback.
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
user = "@baldrick:matrix.org"
macaroon = pymacaroons.Macaroon(
location=self.hs.config.server_name,
identifier="key",
key=self.hs.config.macaroon_secret_key + "wrong",
)
macaroon.add_first_party_caveat("gen = 1")
macaroon.add_first_party_caveat("type = access")
macaroon.add_first_party_caveat("user_id = %s" % (user,))
with self.assertRaises(AuthError) as cm:
yield self.auth.get_user_by_access_token(macaroon.serialize())
self.assertEqual(401, cm.exception.code)
self.assertIn("Invalid macaroon", cm.exception.msg)
@defer.inlineCallbacks
def test_get_user_from_macaroon_unknown_caveat(self):
# TODO(danielwh): Remove this mock when we remove the
# get_user_by_access_token fallback.
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
user = "@baldrick:matrix.org"
macaroon = pymacaroons.Macaroon(
location=self.hs.config.server_name,
identifier="key",
key=self.hs.config.macaroon_secret_key,
)
macaroon.add_first_party_caveat("gen = 1")
macaroon.add_first_party_caveat("type = access")
macaroon.add_first_party_caveat("user_id = %s" % (user,))
macaroon.add_first_party_caveat("cunning > fox")
with self.assertRaises(AuthError) as cm:
yield self.auth.get_user_by_access_token(macaroon.serialize())
self.assertEqual(401, cm.exception.code)
self.assertIn("Invalid macaroon", cm.exception.msg)
@defer.inlineCallbacks
def test_get_user_from_macaroon_expired(self):
# TODO(danielwh): Remove this mock when we remove the
# get_user_by_access_token fallback.
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
user = "@baldrick:matrix.org"
macaroon = pymacaroons.Macaroon(
location=self.hs.config.server_name,
identifier="key",
key=self.hs.config.macaroon_secret_key,
)
macaroon.add_first_party_caveat("gen = 1")
macaroon.add_first_party_caveat("type = access")
macaroon.add_first_party_caveat("user_id = %s" % (user,))
macaroon.add_first_party_caveat("time < -2000") # ms
self.hs.clock.now = 5000 # seconds
self.hs.config.expire_access_token = True
# yield self.auth.get_user_by_access_token(macaroon.serialize())
# TODO(daniel): Turn on the check that we validate expiration, when we
# validate expiration (and remove the above line, which will start
# throwing).
with self.assertRaises(AuthError) as cm:
yield self.auth.get_user_by_access_token(macaroon.serialize())
self.assertEqual(401, cm.exception.code)
self.assertIn("Invalid macaroon", cm.exception.msg)
@defer.inlineCallbacks
def test_get_user_from_macaroon_with_valid_duration(self):
# TODO(danielwh): Remove this mock when we remove the
# get_user_by_access_token fallback.
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
self.store.get_user_by_access_token = Mock(
return_value={"name": "@baldrick:matrix.org"}
)
user_id = "@baldrick:matrix.org"
macaroon = pymacaroons.Macaroon(
location=self.hs.config.server_name,
identifier="key",
key=self.hs.config.macaroon_secret_key,
)
macaroon.add_first_party_caveat("gen = 1")
macaroon.add_first_party_caveat("type = access")
macaroon.add_first_party_caveat("user_id = %s" % (user_id,))
macaroon.add_first_party_caveat("time < 900000000") # ms
self.hs.clock.now = 5000 # seconds
self.hs.config.expire_access_token = True
user_info = yield self.auth.get_user_by_access_token(macaroon.serialize())
user = user_info["user"]
self.assertEqual(UserID.from_string(user_id), user)
@defer.inlineCallbacks
def test_cannot_use_regular_token_as_guest(self):
USER_ID = "@percy:matrix.org"
+1
View File
@@ -115,6 +115,7 @@ def default_config(name):
config.email_enable_notifs = False
config.block_non_admin_invites = False
config.federation_domain_whitelist = None
config.federation_request_gateway_addr = None
config.federation_rc_reject_limit = 10
config.federation_rc_sleep_limit = 10
config.federation_rc_sleep_delay = 100