Propagate errors sensibly from proxied IS requests

When we're proxying Matrix endpoints, parse out Matrix error
responses and turn them into SynapseErrors so they can be
propagated sensibly upstream.
This commit is contained in:
David Baker 2017-04-21 11:32:48 +01:00
parent 247c736b9b
commit a90a0f5c8a
3 changed files with 42 additions and 6 deletions

View File

@ -35,7 +35,7 @@ class IdentityHandler(BaseHandler):
def __init__(self, hs): def __init__(self, hs):
super(IdentityHandler, self).__init__(hs) super(IdentityHandler, self).__init__(hs)
self.http_client = hs.get_simple_http_client() self.proxy_client = hs.get_matrix_proxy_client()
self.trusted_id_servers = set(hs.config.trusted_third_party_id_servers) self.trusted_id_servers = set(hs.config.trusted_third_party_id_servers)
self.trust_any_id_server_just_for_testing_do_not_use = ( self.trust_any_id_server_just_for_testing_do_not_use = (
@ -83,7 +83,7 @@ class IdentityHandler(BaseHandler):
data = {} data = {}
try: try:
data = yield self.http_client.get_json( data = yield self.proxy_client.get_json(
"https://%s%s" % ( "https://%s%s" % (
id_server, id_server,
"/_matrix/identity/api/v1/3pid/getValidated3pid" "/_matrix/identity/api/v1/3pid/getValidated3pid"
@ -118,7 +118,7 @@ class IdentityHandler(BaseHandler):
raise SynapseError(400, "No client_secret in creds") raise SynapseError(400, "No client_secret in creds")
try: try:
data = yield self.http_client.post_urlencoded_get_json( data = yield self.proxy_client.post_urlencoded_get_json(
"https://%s%s" % ( "https://%s%s" % (
id_server, "/_matrix/identity/api/v1/3pid/bind" id_server, "/_matrix/identity/api/v1/3pid/bind"
), ),
@ -151,7 +151,7 @@ class IdentityHandler(BaseHandler):
params.update(kwargs) params.update(kwargs)
try: try:
data = yield self.http_client.post_json_get_json( data = yield self.proxy_client.post_json_get_json(
"https://%s%s" % ( "https://%s%s" % (
id_server, id_server,
"/_matrix/identity/api/v1/validate/email/requestToken" "/_matrix/identity/api/v1/validate/email/requestToken"
@ -185,7 +185,7 @@ class IdentityHandler(BaseHandler):
params.update(kwargs) params.update(kwargs)
try: try:
data = yield self.http_client.post_json_get_json( data = yield self.proxy_client.post_json_get_json(
"https://%s%s" % ( "https://%s%s" % (
id_server, id_server,
"/_matrix/identity/api/v1/validate/msisdn/requestToken" "/_matrix/identity/api/v1/validate/msisdn/requestToken"

View File

@ -145,6 +145,9 @@ class SimpleHttpClient(object):
body = yield preserve_context_over_fn(readBody, response) body = yield preserve_context_over_fn(readBody, response)
if response.code / 100 != 2:
raise CodeMessageException(response.code, body)
defer.returnValue(json.loads(body)) defer.returnValue(json.loads(body))
@defer.inlineCallbacks @defer.inlineCallbacks
@ -306,6 +309,33 @@ class SimpleHttpClient(object):
defer.returnValue((length, headers, response.request.absoluteURI, response.code)) defer.returnValue((length, headers, response.request.absoluteURI, response.code))
class MatrixProxyClient(object):
"""
An HTTP client that proxies other Matrix endpoints, ie. if the remote endpoint
returns Matrix-style error response, this will raise the appropriate SynapseError
"""
def __init__(self, hs):
self.simpleHttpClient = SimpleHttpClient(hs)
@defer.inlineCallbacks
def post_json_get_json(self, uri, post_json):
try:
result = yield self.simpleHttpClient.post_json_get_json(uri, post_json)
defer.returnValue(result)
except CodeMessageException as cme:
ex = None
try:
errbody = json.loads(cme.msg)
errcode = errbody['errcode']
errtext = errbody['error']
ex = SynapseError(cme.code, errtext, errcode)
except:
pass
if ex is not None:
raise ex
raise cme
# XXX: FIXME: This is horribly copy-pasted from matrixfederationclient. # XXX: FIXME: This is horribly copy-pasted from matrixfederationclient.
# The two should be factored out. # The two should be factored out.

View File

@ -48,7 +48,9 @@ from synapse.handlers.typing import TypingHandler
from synapse.handlers.events import EventHandler, EventStreamHandler from synapse.handlers.events import EventHandler, EventStreamHandler
from synapse.handlers.initial_sync import InitialSyncHandler from synapse.handlers.initial_sync import InitialSyncHandler
from synapse.handlers.receipts import ReceiptsHandler from synapse.handlers.receipts import ReceiptsHandler
from synapse.http.client import SimpleHttpClient, InsecureInterceptableContextFactory from synapse.http.client import (
SimpleHttpClient, InsecureInterceptableContextFactory, MatrixProxyClient
)
from synapse.http.matrixfederationclient import MatrixFederationHttpClient from synapse.http.matrixfederationclient import MatrixFederationHttpClient
from synapse.notifier import Notifier from synapse.notifier import Notifier
from synapse.push.pusherpool import PusherPool from synapse.push.pusherpool import PusherPool
@ -127,6 +129,7 @@ class HomeServer(object):
'filtering', 'filtering',
'http_client_context_factory', 'http_client_context_factory',
'simple_http_client', 'simple_http_client',
'matrix_proxy_client',
'media_repository', 'media_repository',
'federation_transport_client', 'federation_transport_client',
'federation_sender', 'federation_sender',
@ -188,6 +191,9 @@ class HomeServer(object):
def build_simple_http_client(self): def build_simple_http_client(self):
return SimpleHttpClient(self) return SimpleHttpClient(self)
def build_matrix_proxy_client(self):
return MatrixProxyClient(self)
def build_v1auth(self): def build_v1auth(self):
orf = Auth(self) orf = Auth(self)
# Matrix spec makes no reference to what HTTP status code is returned, # Matrix spec makes no reference to what HTTP status code is returned,