def render_GET(self, request):
        err, args = get_args(request, ('sid', 'client_secret'))
        if err:
            return err

        sid = args['sid']
        clientSecret = args['client_secret']

        valSessionStore = ThreePidValSessionStore(self.sydent)

        noMatchError = {'errcode': 'M_NO_VALID_SESSION',
                        'error': "No valid session was found matching that sid and client secret"}

        try:
            s = valSessionStore.getValidatedSession(sid, clientSecret)
        except IncorrectClientSecretException:
            return noMatchError
        except SessionExpiredException:
            return {'errcode': 'M_SESSION_EXPIRED',
                    'error': "This validation session has expired: call requestToken again"}
        except InvalidSessionIdException:
            return noMatchError
        except SessionNotValidatedException:
            return {'errcode': 'M_SESSION_NOT_VALIDATED',
                    'error': "This validation session has not yet been completed"}

        return { 'medium': s.medium, 'address': s.address, 'validated_at': s.mtime }
    def render_POST(self, request):
        send_cors(request)
        err, args = get_args(request, ('sid', 'client_secret', 'mxid'))
        if err:
            return err

        sid = args['sid']
        mxid = args['mxid']
        clientSecret = args['client_secret']

        # Return the same error for not found / bad client secret otherwise people can get information about
        # sessions without knowing the secret
        noMatchError = {'errcode': 'M_NO_VALID_SESSION',
                        'error': "No valid session was found matching that sid and client secret"}

        try:
            valSessionStore = ThreePidValSessionStore(self.sydent)
            s = valSessionStore.getValidatedSession(sid, clientSecret)
        except IncorrectClientSecretException:
            return noMatchError
        except SessionExpiredException:
            return {'errcode': 'M_SESSION_EXPIRED',
                    'error': "This validation session has expired: call requestToken again"}
        except InvalidSessionIdException:
            return noMatchError
        except SessionNotValidatedException:
            return {'errcode': 'M_SESSION_NOT_VALIDATED',
                    'error': "This validation session has not yet been completed"}

        res = self.sydent.threepidBinder.addBinding(s.medium, s.address, mxid)
        return res
Beispiel #3
0
    def render_GET(self, request):
        authIfV2(self.sydent, request)

        args = get_args(request, ('sid', 'client_secret'))

        sid = args['sid']
        clientSecret = args['client_secret']

        if not is_valid_client_secret(clientSecret):
            request.setResponseCode(400)
            return {
                'errcode': 'M_INVALID_PARAM',
                'error': 'Invalid client_secret provided'
            }

        valSessionStore = ThreePidValSessionStore(self.sydent)

        noMatchError = {
            'errcode':
            'M_NO_VALID_SESSION',
            'error':
            "No valid session was found matching that sid and client secret"
        }

        try:
            s = valSessionStore.getValidatedSession(sid, clientSecret)
        except (IncorrectClientSecretException, InvalidSessionIdException):
            request.setResponseCode(404)
            return noMatchError
        except SessionExpiredException:
            request.setResponseCode(400)
            return {
                'errcode':
                'M_SESSION_EXPIRED',
                'error':
                "This validation session has expired: call requestToken again"
            }
        except SessionNotValidatedException:
            request.setResponseCode(400)
            return {
                'errcode': 'M_SESSION_NOT_VALIDATED',
                'error': "This validation session has not yet been completed"
            }

        return {
            'medium': s.medium,
            'address': s.address,
            'validated_at': s.mtime
        }
Beispiel #4
0
    def render_POST(self, request):
        send_cors(request)

        account = authIfV2(self.sydent, request)

        args = get_args(request, ('sid', 'client_secret', 'mxid'))

        sid = args['sid']
        mxid = args['mxid']
        clientSecret = args['client_secret']

        # Return the same error for not found / bad client secret otherwise people can get information about
        # sessions without knowing the secret
        noMatchError = {
            'errcode':
            'M_NO_VALID_SESSION',
            'error':
            "No valid session was found matching that sid and client secret"
        }

        if account:
            # This is a v2 API so only allow binding to the logged in user id
            if account.userId != mxid:
                raise MatrixRestError(
                    403, 'M_UNAUTHORIZED',
                    "This user is prohibited from binding to the mxid")

        try:
            valSessionStore = ThreePidValSessionStore(self.sydent)
            s = valSessionStore.getValidatedSession(sid, clientSecret)
        except IncorrectClientSecretException:
            return noMatchError
        except SessionExpiredException:
            return {
                'errcode':
                'M_SESSION_EXPIRED',
                'error':
                "This validation session has expired: call requestToken again"
            }
        except InvalidSessionIdException:
            return noMatchError
        except SessionNotValidatedException:
            return {
                'errcode': 'M_SESSION_NOT_VALIDATED',
                'error': "This validation session has not yet been completed"
            }

        res = self.sydent.threepidBinder.addBinding(s.medium, s.address, mxid)
        return res
Beispiel #5
0
    def addBinding(self, valSessionId, clientSecret, mxid):
        valSessionStore = ThreePidValSessionStore(self.sydent)
        localAssocStore = LocalAssociationStore(self.sydent)

        s = valSessionStore.getValidatedSession(valSessionId, clientSecret)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        assoc = ThreepidAssociation(s.medium, s.address, mxid, createdAt, createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        assocSigner = AssociationSigner(self.sydent)
        sgassoc = assocSigner.signedThreePidAssociation(assoc)

        return sgassoc
Beispiel #6
0
    def render_POST(self, request):
        send_cors(request)
        err, args = get_args(request, ('sid', 'client_secret', 'mxid'))
        if err:
            return err

        sid = args['sid']
        mxid = args['mxid']
        clientSecret = args['client_secret']

        # Return the same error for not found / bad client secret otherwise people can get information about
        # sessions without knowing the secret
        noMatchError = {
            'errcode':
            'M_NO_VALID_SESSION',
            'error':
            "No valid session was found matching that sid and client secret"
        }

        try:
            valSessionStore = ThreePidValSessionStore(self.sydent)
            s = valSessionStore.getValidatedSession(sid, clientSecret)
        except IncorrectClientSecretException:
            return noMatchError
        except SessionExpiredException:
            return {
                'errcode':
                'M_SESSION_EXPIRED',
                'error':
                "This validation session has expired: call requestToken again"
            }
        except InvalidSessionIdException:
            return noMatchError
        except SessionNotValidatedException:
            return {
                'errcode': 'M_SESSION_NOT_VALIDATED',
                'error': "This validation session has not yet been completed"
            }

        res = self.sydent.threepidBinder.addBinding(s.medium, s.address, mxid)
        return res
Beispiel #7
0
    def addBinding(self, valSessionId, clientSecret, mxid):
        valSessionStore = ThreePidValSessionStore(self.sydent)
        localAssocStore = LocalAssociationStore(self.sydent)

        s = valSessionStore.getValidatedSession(valSessionId, clientSecret)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        assoc = ThreepidAssociation(s.medium, s.address, mxid, createdAt,
                                    createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(s.medium, s.address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(
                token["signed"], self.sydent.server_name,
                self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(s.medium, s.address)

        assocSigner = AssociationSigner(self.sydent)
        sgassoc = assocSigner.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
    def render_GET(self, request):
        # err = require_args(request, ('sid', 'client_secret'))
        err = require_args(request, ('sid',))
        if err:
            return err

        sid = request.args['sid'][0]
        #clientSecret = request.args['client_secret'][0]

        if 'client_secret' in request.args:
            clientSecret = request.args['client_secret'][0]
        elif 'clientSecret' in request.args:
            clientSecret = request.args['clientSecret'][0]
        else:
            request.setResponseCode(400)
            return {'errcode': 'M_MISSING_PARAM', 'error':'No client_secret'}

        valSessionStore = ThreePidValSessionStore(self.sydent)

        noMatchError = {'errcode': 'M_NO_VALID_SESSION',
                        'error': "No valid session was found matching that sid and client secret"}

        try:
            s = valSessionStore.getValidatedSession(sid, clientSecret)
        except IncorrectClientSecretException:
            return noMatchError
        except SessionExpiredException:
            return {'errcode': 'M_SESSION_EXPIRED',
                    'error': "This validation session has expired: call requestToken again"}
        except InvalidSessionIdException:
            return noMatchError
        except SessionNotValidatedException:
            return {'errcode': 'M_SESSION_NOT_VALIDATED',
                    'error': "This validation session has not yet been completed"}

        return { 'medium': s.medium, 'address': s.address, 'validated_at': s.mtime }
Beispiel #9
0
    def addBinding(self, valSessionId, clientSecret, mxid):
        valSessionStore = ThreePidValSessionStore(self.sydent)
        localAssocStore = LocalAssociationStore(self.sydent)

        s = valSessionStore.getValidatedSession(valSessionId, clientSecret)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        assoc = ThreepidAssociation(s.medium, s.address, mxid, createdAt, createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(s.medium, s.address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(token["signed"], self.sydent.server_name, self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(s.medium, s.address)

        assocSigner = AssociationSigner(self.sydent)
        sgassoc = assocSigner.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
    def _async_render_POST(self, request):
        try:
            try:
                body = json.load(request.content)
            except ValueError:
                request.setResponseCode(400)
                request.write(json.dumps({'errcode': 'M_BAD_JSON', 'error': 'Malformed JSON'}))
                request.finish()
                return

            missing = [k for k in ("threepid", "mxid") if k not in body]
            if len(missing) > 0:
                request.setResponseCode(400)
                msg = "Missing parameters: "+(",".join(missing))
                request.write(json.dumps({'errcode': 'M_MISSING_PARAMS', 'error': msg}))
                request.finish()
                return

            threepid = body['threepid']
            mxid = body['mxid']

            if 'medium' not in threepid or 'address' not in threepid:
                request.setResponseCode(400)
                request.write(json.dumps({'errcode': 'M_MISSING_PARAMS', 'error': 'Threepid lacks medium / address'}))
                request.finish()
                return

            # We now check for authentication in two different ways, depending
            # on the contents of the request. If the user has supplied "sid"
            # (the Session ID returned by Sydent during the original binding)
            # and "client_secret" fields, they are trying to provie that they
            # were the original author of the bind. We then check that what
            # they supply matches and if it does, allow the unbind.
            # 
            # However if these fields are not supplied, we instead check
            # whether the request originated from a homeserver, and if so the
            # same homeserver that originally created the bind. We do this by
            # checking the signature of the request. If it all matches up, we
            # allow the unbind.
            #
            # Only one method of authentication is required.
            if 'sid' in body and 'client_secret' in body:
                sid = body['sid']
                client_secret = body['client_secret']

                valSessionStore = ThreePidValSessionStore(self.sydent)

                noMatchError = {'errcode': 'M_NO_VALID_SESSION',
                                'error': "No valid session was found matching that sid and client secret"}

                try:
                    s = valSessionStore.getValidatedSession(sid, client_secret)
                except IncorrectClientSecretException:
                    request.setResponseCode(401)
                    request.write(json.dumps(noMatchError))
                    request.finish()
                    return
                except InvalidSessionIdException:
                    request.setResponseCode(401)
                    request.write(json.dumps(noMatchError))
                    request.finish()
                    return
                except SessionNotValidatedException:
                    request.setResponseCode(403)
                    request.write(json.dumps({
                        'errcode': 'M_SESSION_NOT_VALIDATED',
                        'error': "This validation session has not yet been completed"
                    }))
                    return
                
                if s.medium != threepid['medium'] or s.address != threepid['address']:
                    request.setResponseCode(403)
                    request.write(json.dumps({
                        'errcode': 'M_FORBIDDEN',
                        'error': 'Provided session information does not match medium/address combo',
                    }))
                    request.finish()
                    return
            else:
                try:
                    origin_server_name = yield self.sydent.sig_verifier.authenticate_request(request, body)
                except SignatureVerifyException as ex:
                    request.setResponseCode(401)
                    request.write(json.dumps({'errcode': 'M_FORBIDDEN', 'error': ex.message}))
                    request.finish()
                    return
                except NoAuthenticationError as ex:
                    request.setResponseCode(401)
                    request.write(json.dumps({'errcode': 'M_FORBIDDEN', 'error': ex.message}))
                    request.finish()
                    return
                except:
                    logger.exception("Exception whilst authenticating unbind request")
                    request.setResponseCode(500)
                    request.write(json.dumps({'errcode': 'M_UNKNOWN', 'error': 'Internal Server Error'}))
                    request.finish()
                    return

                if not mxid.endswith(':' + origin_server_name):
                    request.setResponseCode(403)
                    request.write(json.dumps({'errcode': 'M_FORBIDDEN', 'error': 'Origin server name does not match mxid'}))
                    request.finish()
                    return

            try:
                res = self.sydent.threepidBinder.removeBinding(threepid, mxid)
            except ValueError:
                # User could have provided correct 3PID/sid/client_secret
                # details but not the correct mxid, which would cause the
                # binding removal to fail
                request.setResponseCode(400)
                request.write(json.dumps({'errcode': 'M_UNKNOWN', 'error': "Association between provided mxid and 3pid not found"}))
                request.finish()
                return

            request.write(json.dumps({}))
            request.finish()
        except Exception as ex:
            logger.exception("Exception whilst handling unbind")
            request.setResponseCode(500)
            request.write(json.dumps({'errcode': 'M_UNKNOWN', 'error': ex.message}))
            request.finish()
    async def _async_render_POST(self, request: Request) -> None:
        try:
            try:
                # TODO: we should really validate that this gives us a dict, and
                #   not some other json value like str, list, int etc
                # json.loads doesn't allow bytes in Python 3.5
                body: JsonDict = json_decoder.decode(
                    request.content.read().decode("UTF-8"))
            except ValueError:
                request.setResponseCode(HTTPStatus.BAD_REQUEST)
                request.write(
                    dict_to_json_bytes({
                        "errcode": "M_BAD_JSON",
                        "error": "Malformed JSON"
                    }))
                request.finish()
                return

            missing = [k for k in ("threepid", "mxid") if k not in body]
            if len(missing) > 0:
                request.setResponseCode(HTTPStatus.BAD_REQUEST)
                msg = "Missing parameters: " + (",".join(missing))
                request.write(
                    dict_to_json_bytes({
                        "errcode": "M_MISSING_PARAMS",
                        "error": msg
                    }))
                request.finish()
                return

            threepid = body["threepid"]
            mxid = body["mxid"]

            if "medium" not in threepid or "address" not in threepid:
                request.setResponseCode(HTTPStatus.BAD_REQUEST)
                request.write(
                    dict_to_json_bytes({
                        "errcode":
                        "M_MISSING_PARAMS",
                        "error":
                        "Threepid lacks medium / address",
                    }))
                request.finish()
                return

            # We now check for authentication in two different ways, depending
            # on the contents of the request. If the user has supplied "sid"
            # (the Session ID returned by Sydent during the original binding)
            # and "client_secret" fields, they are trying to prove that they
            # were the original author of the bind. We then check that what
            # they supply matches and if it does, allow the unbind.
            #
            # However if these fields are not supplied, we instead check
            # whether the request originated from a homeserver, and if so the
            # same homeserver that originally created the bind. We do this by
            # checking the signature of the request. If it all matches up, we
            # allow the unbind.
            #
            # Only one method of authentication is required.
            if "sid" in body and "client_secret" in body:
                sid = body["sid"]
                client_secret = body["client_secret"]

                if not is_valid_client_secret(client_secret):
                    request.setResponseCode(HTTPStatus.BAD_REQUEST)
                    request.write(
                        dict_to_json_bytes({
                            "errcode":
                            "M_INVALID_PARAM",
                            "error":
                            "Invalid client_secret provided",
                        }))
                    request.finish()
                    return

                valSessionStore = ThreePidValSessionStore(self.sydent)

                try:
                    s = valSessionStore.getValidatedSession(sid, client_secret)
                except (IncorrectClientSecretException,
                        InvalidSessionIdException):
                    request.setResponseCode(HTTPStatus.UNAUTHORIZED)
                    request.write(
                        dict_to_json_bytes({
                            "errcode":
                            "M_NO_VALID_SESSION",
                            "error":
                            "No valid session was found matching that sid and client secret",
                        }))
                    request.finish()
                    return
                except SessionNotValidatedException:
                    request.setResponseCode(HTTPStatus.FORBIDDEN)
                    request.write(
                        dict_to_json_bytes({
                            "errcode":
                            "M_SESSION_NOT_VALIDATED",
                            "error":
                            "This validation session has not yet been completed",
                        }))
                    return

                if s.medium != threepid["medium"] or s.address != threepid[
                        "address"]:
                    request.setResponseCode(HTTPStatus.FORBIDDEN)
                    request.write(
                        dict_to_json_bytes({
                            "errcode":
                            "M_FORBIDDEN",
                            "error":
                            "Provided session information does not match medium/address combo",
                        }))
                    request.finish()
                    return
            else:
                try:
                    origin_server_name = (
                        await self.sydent.sig_verifier.authenticate_request(
                            request, body))
                except SignatureVerifyException as ex:
                    request.setResponseCode(HTTPStatus.UNAUTHORIZED)
                    request.write(
                        dict_to_json_bytes({
                            "errcode": "M_FORBIDDEN",
                            "error": str(ex)
                        }))
                    request.finish()
                    return
                except NoAuthenticationError as ex:
                    request.setResponseCode(HTTPStatus.UNAUTHORIZED)
                    request.write(
                        dict_to_json_bytes({
                            "errcode": "M_FORBIDDEN",
                            "error": str(ex)
                        }))
                    request.finish()
                    return
                except InvalidServerName as ex:
                    request.setResponseCode(HTTPStatus.BAD_REQUEST)
                    request.write(
                        dict_to_json_bytes({
                            "errcode": "M_INVALID_PARAM",
                            "error": str(ex)
                        }))
                    request.finish()
                    return
                except (DNSLookupError, ConnectError, ResponseFailed) as e:
                    msg = (f"Unable to contact the Matrix homeserver to "
                           f"authenticate request ({type(e).__name__})")
                    logger.warning(msg)
                    request.setResponseCode(HTTPStatus.INTERNAL_SERVER_ERROR)
                    request.write(
                        dict_to_json_bytes({
                            "errcode": "M_UNKNOWN",
                            "error": msg,
                        }))
                    request.finish()
                    return
                except Exception:
                    logger.exception(
                        "Exception whilst authenticating unbind request")
                    request.setResponseCode(HTTPStatus.INTERNAL_SERVER_ERROR)
                    request.write(
                        dict_to_json_bytes({
                            "errcode": "M_UNKNOWN",
                            "error": "Internal Server Error"
                        }))
                    request.finish()
                    return

                if not mxid.endswith(":" + origin_server_name):
                    request.setResponseCode(HTTPStatus.FORBIDDEN)
                    request.write(
                        dict_to_json_bytes({
                            "errcode":
                            "M_FORBIDDEN",
                            "error":
                            "Origin server name does not match mxid",
                        }))
                    request.finish()
                    return

            self.sydent.threepidBinder.removeBinding(threepid, mxid)

            request.write(dict_to_json_bytes({}))
            request.finish()
        except Exception as ex:
            logger.exception("Exception whilst handling unbind")
            request.setResponseCode(HTTPStatus.INTERNAL_SERVER_ERROR)
            request.write(
                dict_to_json_bytes({
                    "errcode": "M_UNKNOWN",
                    "error": str(ex)
                }))
            request.finish()
    def _async_render_POST(self, request):
        try:
            try:
                body = json.load(request.content)
            except ValueError:
                request.setResponseCode(400)
                request.write(
                    json.dumps({
                        'errcode': 'M_BAD_JSON',
                        'error': 'Malformed JSON'
                    }))
                request.finish()
                return

            missing = [k for k in ("threepid", "mxid") if k not in body]
            if len(missing) > 0:
                request.setResponseCode(400)
                msg = "Missing parameters: " + (",".join(missing))
                request.write(
                    json.dumps({
                        'errcode': 'M_MISSING_PARAMS',
                        'error': msg
                    }))
                request.finish()
                return

            threepid = body['threepid']
            mxid = body['mxid']

            if 'medium' not in threepid or 'address' not in threepid:
                request.setResponseCode(400)
                request.write(
                    json.dumps({
                        'errcode': 'M_MISSING_PARAMS',
                        'error': 'Threepid lacks medium / address'
                    }))
                request.finish()
                return

            # We now check for authentication in two different ways, depending
            # on the contents of the request. If the user has supplied "sid"
            # (the Session ID returned by Sydent during the original binding)
            # and "client_secret" fields, they are trying to provie that they
            # were the original author of the bind. We then check that what
            # they supply matches and if it does, allow the unbind.
            #
            # However if these fields are not supplied, we instead check
            # whether the request originated from a homeserver, and if so the
            # same homeserver that originally created the bind. We do this by
            # checking the signature of the request. If it all matches up, we
            # allow the unbind.
            #
            # Only one method of authentication is required.
            if 'sid' in body and 'client_secret' in body:
                sid = body['sid']
                client_secret = body['client_secret']

                valSessionStore = ThreePidValSessionStore(self.sydent)

                noMatchError = {
                    'errcode':
                    'M_NO_VALID_SESSION',
                    'error':
                    "No valid session was found matching that sid and client secret"
                }

                try:
                    s = valSessionStore.getValidatedSession(sid, client_secret)
                except IncorrectClientSecretException:
                    request.setResponseCode(401)
                    request.write(json.dumps(noMatchError))
                    request.finish()
                    return
                except InvalidSessionIdException:
                    request.setResponseCode(401)
                    request.write(json.dumps(noMatchError))
                    request.finish()
                    return
                except SessionNotValidatedException:
                    request.setResponseCode(403)
                    request.write(
                        json.dumps({
                            'errcode':
                            'M_SESSION_NOT_VALIDATED',
                            'error':
                            "This validation session has not yet been completed"
                        }))
                    return

                if s.medium != threepid['medium'] or s.address != threepid[
                        'address']:
                    request.setResponseCode(403)
                    request.write(
                        json.dumps({
                            'errcode':
                            'M_FORBIDDEN',
                            'error':
                            'Provided session information does not match medium/address combo',
                        }))
                    request.finish()
                    return
            else:
                try:
                    origin_server_name = yield self.sydent.sig_verifier.authenticate_request(
                        request, body)
                except SignatureVerifyException as ex:
                    request.setResponseCode(401)
                    request.write(
                        json.dumps({
                            'errcode': 'M_FORBIDDEN',
                            'error': ex.message
                        }))
                    request.finish()
                    return
                except NoAuthenticationError as ex:
                    request.setResponseCode(401)
                    request.write(
                        json.dumps({
                            'errcode': 'M_FORBIDDEN',
                            'error': ex.message
                        }))
                    request.finish()
                    return
                except:
                    logger.exception(
                        "Exception whilst authenticating unbind request")
                    request.setResponseCode(500)
                    request.write(
                        json.dumps({
                            'errcode': 'M_UNKNOWN',
                            'error': 'Internal Server Error'
                        }))
                    request.finish()
                    return

                if not mxid.endswith(':' + origin_server_name):
                    request.setResponseCode(403)
                    request.write(
                        json.dumps({
                            'errcode':
                            'M_FORBIDDEN',
                            'error':
                            'Origin server name does not match mxid'
                        }))
                    request.finish()
                    return

            try:
                res = self.sydent.threepidBinder.removeBinding(threepid, mxid)
            except ValueError:
                # User could have provided correct 3PID/sid/client_secret
                # details but not the correct mxid, which would cause the
                # binding removal to fail
                request.setResponseCode(400)
                request.write(
                    json.dumps({
                        'errcode':
                        'M_UNKNOWN',
                        'error':
                        "Association between provided mxid and 3pid not found"
                    }))
                request.finish()
                return

            request.write(json.dumps({}))
            request.finish()
        except Exception as ex:
            logger.exception("Exception whilst handling unbind")
            request.setResponseCode(500)
            request.write(
                json.dumps({
                    'errcode': 'M_UNKNOWN',
                    'error': ex.message
                }))
            request.finish()