Beispiel #1
0
    def on_POST(self, request):
        user_json = parse_json_object_from_request(request)

        access_token = get_access_token_from_request(request)
        app_service = yield self.store.get_app_service_by_token(access_token)
        if not app_service:
            raise SynapseError(403, "Invalid application service token.")

        logger.debug("creating user: %s", user_json)

        response = yield self._do_create(user_json)

        defer.returnValue((200, response))
Beispiel #2
0
    def on_POST(self, request):
        user_json = parse_json_object_from_request(request)

        access_token = get_access_token_from_request(request)
        app_service = yield self.store.get_app_service_by_token(
            access_token
        )
        if not app_service:
            raise SynapseError(403, "Invalid application service token.")

        logger.debug("creating user: %s", user_json)

        response = yield self._do_create(user_json)

        defer.returnValue((200, response))
Beispiel #3
0
def get_transaction_key(request):
    """A helper function which returns a transaction key that can be used
    with TransactionCache for idempotent requests.

    Idempotency is based on the returned key being the same for separate
    requests to the same endpoint. The key is formed from the HTTP request
    path and the access_token for the requesting user.

    Args:
        request (twisted.web.http.Request): The incoming request. Must
        contain an access_token.
    Returns:
        str: A transaction key
    """
    token = get_access_token_from_request(request)
    return request.path + "/" + token
Beispiel #4
0
def get_transaction_key(request):
    """A helper function which returns a transaction key that can be used
    with TransactionCache for idempotent requests.

    Idempotency is based on the returned key being the same for separate
    requests to the same endpoint. The key is formed from the HTTP request
    path and the access_token for the requesting user.

    Args:
        request (twisted.web.http.Request): The incoming request. Must
        contain an access_token.
    Returns:
        str: A transaction key
    """
    token = get_access_token_from_request(request)
    return request.path + "/" + token
Beispiel #5
0
    def _do_app_service(self, request, register_json, session):
        as_token = get_access_token_from_request(request)

        if "user" not in register_json:
            raise SynapseError(400, "Expected 'user' key.")

        user_localpart = register_json["user"].encode("utf-8")

        handler = self.handlers.registration_handler
        user_id = yield handler.appservice_register(user_localpart, as_token)
        token = yield self.auth_handler.issue_access_token(user_id)
        self._remove_session(session)
        defer.returnValue({
            "user_id": user_id,
            "access_token": token,
            "home_server": self.hs.hostname,
        })
Beispiel #6
0
    def on_POST(self, request):
        try:
            requester = yield self.auth.get_user_by_req(request)
        except AuthError:
            # this implies the access token has already been deleted.
            pass
        else:
            if requester.device_id is None:
                # the acccess token wasn't associated with a device.
                # Just delete the access token
                access_token = get_access_token_from_request(request)
                yield self._auth_handler.delete_access_token(access_token)
            else:
                yield self._device_handler.delete_device(
                    requester.user.to_string(), requester.device_id)

        defer.returnValue((200, {}))
Beispiel #7
0
    def _do_app_service(self, request, register_json, session):
        as_token = get_access_token_from_request(request)

        if "user" not in register_json:
            raise SynapseError(400, "Expected 'user' key.")

        user_localpart = register_json["user"].encode("utf-8")

        handler = self.handlers.registration_handler
        user_id = yield handler.appservice_register(
            user_localpart, as_token
        )
        token = yield self.auth_handler.issue_access_token(user_id)
        self._remove_session(session)
        defer.returnValue({
            "user_id": user_id,
            "access_token": token,
            "home_server": self.hs.hostname,
        })
Beispiel #8
0
    def on_POST(self, request):
        try:
            requester = yield self.auth.get_user_by_req(request)
        except AuthError:
            # this implies the access token has already been deleted.
            defer.returnValue((401, {
                "errcode": "M_UNKNOWN_TOKEN",
                "error": "Access Token unknown or expired"
            }))
        else:
            if requester.device_id is None:
                # the acccess token wasn't associated with a device.
                # Just delete the access token
                access_token = get_access_token_from_request(request)
                yield self._auth_handler.delete_access_token(access_token)
            else:
                yield self._device_handler.delete_device(
                    requester.user.to_string(), requester.device_id)

        defer.returnValue((200, {}))
Beispiel #9
0
    def on_POST(self, request):
        yield run_on_reactor()

        body = parse_json_object_from_request(request)

        kind = "user"
        if "kind" in request.args:
            kind = request.args["kind"][0]

        if kind == "guest":
            ret = yield self._do_guest_registration(body)
            defer.returnValue(ret)
            return
        elif kind != "user":
            raise UnrecognizedRequestError(
                "Do not understand membership kind: %s" % (kind, ))

        # we do basic sanity checks here because the auth layer will store these
        # in sessions. Pull out the username/password provided to us.
        desired_password = None
        if 'password' in body:
            if (not isinstance(body['password'], basestring)
                    or len(body['password']) > 512):
                raise SynapseError(400, "Invalid password")
            desired_password = body["password"]

        desired_username = None
        if 'username' in body:
            if (not isinstance(body['username'], basestring)
                    or len(body['username']) > 512):
                raise SynapseError(400, "Invalid username")
            desired_username = body['username']

        appservice = None
        if has_access_token(request):
            appservice = yield self.auth.get_appservice_by_req(request)

        # fork off as soon as possible for ASes and shared secret auth which
        # have completely different registration flows to normal users

        # == Application Service Registration ==
        if appservice:
            # Set the desired user according to the AS API (which uses the
            # 'user' key not 'username'). Since this is a new addition, we'll
            # fallback to 'username' if they gave one.
            desired_username = body.get("user", desired_username)
            access_token = get_access_token_from_request(request)

            if isinstance(desired_username, basestring):
                result = yield self._do_appservice_registration(
                    desired_username, access_token, body)
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # == Shared Secret Registration == (e.g. create new user scripts)
        if 'mac' in body:
            # FIXME: Should we really be determining if this is shared secret
            # auth based purely on the 'mac' key?
            result = yield self._do_shared_secret_registration(
                desired_username, desired_password, body)
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # == Normal User Registration == (everyone else)
        if not self.hs.config.enable_registration:
            raise SynapseError(403, "Registration has been disabled")

        guest_access_token = body.get("guest_access_token", None)

        if ('initial_device_display_name' in body and 'password' not in body):
            # ignore 'initial_device_display_name' if sent without
            # a password to work around a client bug where it sent
            # the 'initial_device_display_name' param alone, wiping out
            # the original registration params
            logger.warn(
                "Ignoring initial_device_display_name without password")
            del body['initial_device_display_name']

        session_id = self.auth_handler.get_session_id(body)
        registered_user_id = None
        if session_id:
            # if we get a registered user id out of here, it means we previously
            # registered a user for this session, so we could just return the
            # user here. We carry on and go through the auth checks though,
            # for paranoia.
            registered_user_id = self.auth_handler.get_session_data(
                session_id, "registered_user_id", None)

        if desired_username is not None:
            yield self.registration_handler.check_username(
                desired_username,
                guest_access_token=guest_access_token,
                assigned_user_id=registered_user_id,
            )

        # Only give msisdn flows if the x_show_msisdn flag is given:
        # this is a hack to work around the fact that clients were shipped
        # that use fallback registration if they see any flows that they don't
        # recognise, which means we break registration for these clients if we
        # advertise msisdn flows. Once usage of Riot iOS <=0.3.9 and Riot
        # Android <=0.6.9 have fallen below an acceptable threshold, this
        # parameter should go away and we should always advertise msisdn flows.
        show_msisdn = False
        if 'x_show_msisdn' in body and body['x_show_msisdn']:
            show_msisdn = True

        if self.hs.config.enable_registration_captcha:
            flows = [
                [LoginType.RECAPTCHA],
                [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA],
            ]
            if show_msisdn:
                flows.extend([
                    [LoginType.MSISDN, LoginType.RECAPTCHA],
                    [
                        LoginType.MSISDN, LoginType.EMAIL_IDENTITY,
                        LoginType.RECAPTCHA
                    ],
                ])
        else:
            flows = [
                [LoginType.DUMMY],
                [LoginType.EMAIL_IDENTITY],
            ]
            if show_msisdn:
                flows.extend([
                    [LoginType.MSISDN],
                    [LoginType.MSISDN, LoginType.EMAIL_IDENTITY],
                ])

        authed, auth_result, params, session_id = yield self.auth_handler.check_auth(
            flows, body, self.hs.get_ip_from_request(request))

        if not authed:
            defer.returnValue((401, auth_result))
            return

        if registered_user_id is not None:
            logger.info("Already registered user ID %r for this session",
                        registered_user_id)
            # don't re-register the threepids
            add_email = False
            add_msisdn = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            if 'password' not in params:
                raise SynapseError(400, "Missing password.",
                                   Codes.MISSING_PARAM)

            desired_username = params.get("username", None)
            new_password = params.get("password", None)
            guest_access_token = params.get("guest_access_token", None)

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                generate_token=False,
            )

            # remember that we've now registered that user account, and with
            #  what user ID (since the user may not have specified)
            self.auth_handler.set_session_data(session_id,
                                               "registered_user_id",
                                               registered_user_id)

            add_email = True
            add_msisdn = True

        return_dict = yield self._create_registration_details(
            registered_user_id, params)

        if add_email and auth_result and LoginType.EMAIL_IDENTITY in auth_result:
            threepid = auth_result[LoginType.EMAIL_IDENTITY]
            yield self._register_email_threepid(registered_user_id, threepid,
                                                return_dict["access_token"],
                                                params.get("bind_email"))

        if add_msisdn and auth_result and LoginType.MSISDN in auth_result:
            threepid = auth_result[LoginType.MSISDN]
            yield self._register_msisdn_threepid(registered_user_id, threepid,
                                                 return_dict["access_token"],
                                                 params.get("bind_msisdn"))

        defer.returnValue((200, return_dict))
Beispiel #10
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        kind = "user"
        if "kind" in request.args:
            kind = request.args["kind"][0]

        if kind == "guest":
            ret = yield self._do_guest_registration(body)
            defer.returnValue(ret)
            return
        elif kind != "user":
            raise UnrecognizedRequestError(
                "Do not understand membership kind: %s" % (kind, ))

        # we do basic sanity checks here because the auth layer will store these
        # in sessions. Pull out the username/password provided to us.
        desired_password = None
        if 'password' in body:
            if (not isinstance(body['password'], string_types)
                    or len(body['password']) > 512):
                raise SynapseError(400, "Invalid password")
            desired_password = body["password"]

        desired_username = None
        if 'username' in body:
            if (not isinstance(body['username'], string_types)
                    or len(body['username']) > 512):
                raise SynapseError(400, "Invalid username")
            desired_username = body['username']

        appservice = None
        if has_access_token(request):
            appservice = yield self.auth.get_appservice_by_req(request)

        # fork off as soon as possible for ASes and shared secret auth which
        # have completely different registration flows to normal users

        # == Application Service Registration ==
        if appservice:
            # Set the desired user according to the AS API (which uses the
            # 'user' key not 'username'). Since this is a new addition, we'll
            # fallback to 'username' if they gave one.
            desired_username = body.get("user", desired_username)

            # XXX we should check that desired_username is valid. Currently
            # we give appservices carte blanche for any insanity in mxids,
            # because the IRC bridges rely on being able to register stupid
            # IDs.

            access_token = get_access_token_from_request(request)

            if isinstance(desired_username, string_types):
                result = yield self._do_appservice_registration(
                    desired_username, access_token, body)
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # for either shared secret or regular registration, downcase the
        # provided username before attempting to register it. This should mean
        # that people who try to register with upper-case in their usernames
        # don't get a nasty surprise. (Note that we treat username
        # case-insenstively in login, so they are free to carry on imagining
        # that their username is CrAzYh4cKeR if that keeps them happy)
        if desired_username is not None:
            desired_username = desired_username.lower()

        # == Shared Secret Registration == (e.g. create new user scripts)
        if 'mac' in body:
            # FIXME: Should we really be determining if this is shared secret
            # auth based purely on the 'mac' key?
            result = yield self._do_shared_secret_registration(
                desired_username, desired_password, body)
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # == Normal User Registration == (everyone else)
        if not self.hs.config.enable_registration:
            raise SynapseError(403, "Registration has been disabled")

        guest_access_token = body.get("guest_access_token", None)

        if ('initial_device_display_name' in body and 'password' not in body):
            # ignore 'initial_device_display_name' if sent without
            # a password to work around a client bug where it sent
            # the 'initial_device_display_name' param alone, wiping out
            # the original registration params
            logger.warn(
                "Ignoring initial_device_display_name without password")
            del body['initial_device_display_name']

        session_id = self.auth_handler.get_session_id(body)
        registered_user_id = None
        if session_id:
            # if we get a registered user id out of here, it means we previously
            # registered a user for this session, so we could just return the
            # user here. We carry on and go through the auth checks though,
            # for paranoia.
            registered_user_id = self.auth_handler.get_session_data(
                session_id, "registered_user_id", None)

        if desired_username is not None:
            yield self.registration_handler.check_username(
                desired_username,
                guest_access_token=guest_access_token,
                assigned_user_id=registered_user_id,
            )

        # Only give msisdn flows if the x_show_msisdn flag is given:
        # this is a hack to work around the fact that clients were shipped
        # that use fallback registration if they see any flows that they don't
        # recognise, which means we break registration for these clients if we
        # advertise msisdn flows. Once usage of Riot iOS <=0.3.9 and Riot
        # Android <=0.6.9 have fallen below an acceptable threshold, this
        # parameter should go away and we should always advertise msisdn flows.
        show_msisdn = False
        if 'x_show_msisdn' in body and body['x_show_msisdn']:
            show_msisdn = True

        # FIXME: need a better error than "no auth flow found" for scenarios
        # where we required 3PID for registration but the user didn't give one
        require_email = 'email' in self.hs.config.registrations_require_3pid
        require_msisdn = 'msisdn' in self.hs.config.registrations_require_3pid

        flows = []
        if self.hs.config.enable_registration_captcha:
            # only support 3PIDless registration if no 3PIDs are required
            if not require_email and not require_msisdn:
                flows.extend([[LoginType.RECAPTCHA]])
            # only support the email-only flow if we don't require MSISDN 3PIDs
            if not require_msisdn:
                flows.extend([[LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA]])

            if show_msisdn:
                # only support the MSISDN-only flow if we don't require email 3PIDs
                if not require_email:
                    flows.extend([[LoginType.MSISDN, LoginType.RECAPTCHA]])
                # always let users provide both MSISDN & email
                flows.extend([
                    [
                        LoginType.MSISDN, LoginType.EMAIL_IDENTITY,
                        LoginType.RECAPTCHA
                    ],
                ])
        else:
            # only support 3PIDless registration if no 3PIDs are required
            if not require_email and not require_msisdn:
                flows.extend([[LoginType.DUMMY]])
            # only support the email-only flow if we don't require MSISDN 3PIDs
            if not require_msisdn:
                flows.extend([[LoginType.EMAIL_IDENTITY]])

            if show_msisdn:
                # only support the MSISDN-only flow if we don't require email 3PIDs
                if not require_email or require_msisdn:
                    flows.extend([[LoginType.MSISDN]])
                # always let users provide both MSISDN & email
                flows.extend([[LoginType.MSISDN, LoginType.EMAIL_IDENTITY]])

        auth_result, params, session_id = yield self.auth_handler.check_auth(
            flows, body, self.hs.get_ip_from_request(request))

        # Check that we're not trying to register a denied 3pid.
        #
        # the user-facing checks will probably already have happened in
        # /register/email/requestToken when we requested a 3pid, but that's not
        # guaranteed.

        if auth_result:
            for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]:
                if login_type in auth_result:
                    medium = auth_result[login_type]['medium']
                    address = auth_result[login_type]['address']

                    if not check_3pid_allowed(self.hs, medium, address):
                        raise SynapseError(
                            403,
                            "Third party identifier is not allowed",
                            Codes.THREEPID_DENIED,
                        )

        if registered_user_id is not None:
            logger.info("Already registered user ID %r for this session",
                        registered_user_id)
            # don't re-register the threepids
            add_email = False
            add_msisdn = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            if 'password' not in params:
                raise SynapseError(400, "Missing password.",
                                   Codes.MISSING_PARAM)

            desired_username = params.get("username", None)
            new_password = params.get("password", None)
            guest_access_token = params.get("guest_access_token", None)

            if desired_username is not None:
                desired_username = desired_username.lower()

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                generate_token=False,
            )

            # remember that we've now registered that user account, and with
            #  what user ID (since the user may not have specified)
            self.auth_handler.set_session_data(session_id,
                                               "registered_user_id",
                                               registered_user_id)

            add_email = True
            add_msisdn = True

        return_dict = yield self._create_registration_details(
            registered_user_id, params)

        if add_email and auth_result and LoginType.EMAIL_IDENTITY in auth_result:
            threepid = auth_result[LoginType.EMAIL_IDENTITY]
            yield self._register_email_threepid(registered_user_id, threepid,
                                                return_dict["access_token"],
                                                params.get("bind_email"))

        if add_msisdn and auth_result and LoginType.MSISDN in auth_result:
            threepid = auth_result[LoginType.MSISDN]
            yield self._register_msisdn_threepid(registered_user_id, threepid,
                                                 return_dict["access_token"],
                                                 params.get("bind_msisdn"))

        defer.returnValue((200, return_dict))
Beispiel #11
0
 def on_POST(self, request):
     access_token = get_access_token_from_request(request)
     yield self._auth_handler.delete_access_token(access_token)
     defer.returnValue((200, {}))
Beispiel #12
0
 def _get_key(self, request):
     token = get_access_token_from_request(request)
     path_without_txn_id = request.path.rsplit("/", 1)[0]
     return path_without_txn_id + "/" + token
Beispiel #13
0
    def on_POST(self, request):
        yield run_on_reactor()

        body = parse_json_object_from_request(request)

        kind = "user"
        if "kind" in request.args:
            kind = request.args["kind"][0]

        if kind == "guest":
            ret = yield self._do_guest_registration(body)
            defer.returnValue(ret)
            return
        elif kind != "user":
            raise UnrecognizedRequestError(
                "Do not understand membership kind: %s" % (kind,)
            )

        # we do basic sanity checks here because the auth layer will store these
        # in sessions. Pull out the username/password provided to us.
        desired_password = None
        if 'password' in body:
            if (not isinstance(body['password'], string_types) or
                    len(body['password']) > 512):
                raise SynapseError(400, "Invalid password")
            desired_password = body["password"]

        desired_username = None
        if 'username' in body:
            if (not isinstance(body['username'], string_types) or
                    len(body['username']) > 512):
                raise SynapseError(400, "Invalid username")
            desired_username = body['username']

        appservice = None
        if has_access_token(request):
            appservice = yield self.auth.get_appservice_by_req(request)

        # fork off as soon as possible for ASes and shared secret auth which
        # have completely different registration flows to normal users

        # == Application Service Registration ==
        if appservice:
            # Set the desired user according to the AS API (which uses the
            # 'user' key not 'username'). Since this is a new addition, we'll
            # fallback to 'username' if they gave one.
            desired_username = body.get("user", desired_username)

            # XXX we should check that desired_username is valid. Currently
            # we give appservices carte blanche for any insanity in mxids,
            # because the IRC bridges rely on being able to register stupid
            # IDs.

            access_token = get_access_token_from_request(request)

            if isinstance(desired_username, string_types):
                result = yield self._do_appservice_registration(
                    desired_username, access_token, body
                )
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # for either shared secret or regular registration, downcase the
        # provided username before attempting to register it. This should mean
        # that people who try to register with upper-case in their usernames
        # don't get a nasty surprise. (Note that we treat username
        # case-insenstively in login, so they are free to carry on imagining
        # that their username is CrAzYh4cKeR if that keeps them happy)
        if desired_username is not None:
            desired_username = desired_username.lower()

        # == Shared Secret Registration == (e.g. create new user scripts)
        if 'mac' in body:
            # FIXME: Should we really be determining if this is shared secret
            # auth based purely on the 'mac' key?
            result = yield self._do_shared_secret_registration(
                desired_username, desired_password, body
            )
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # == Normal User Registration == (everyone else)
        if not self.hs.config.enable_registration:
            raise SynapseError(403, "Registration has been disabled")

        guest_access_token = body.get("guest_access_token", None)

        if (
            'initial_device_display_name' in body and
            'password' not in body
        ):
            # ignore 'initial_device_display_name' if sent without
            # a password to work around a client bug where it sent
            # the 'initial_device_display_name' param alone, wiping out
            # the original registration params
            logger.warn("Ignoring initial_device_display_name without password")
            del body['initial_device_display_name']

        session_id = self.auth_handler.get_session_id(body)
        registered_user_id = None
        if session_id:
            # if we get a registered user id out of here, it means we previously
            # registered a user for this session, so we could just return the
            # user here. We carry on and go through the auth checks though,
            # for paranoia.
            registered_user_id = self.auth_handler.get_session_data(
                session_id, "registered_user_id", None
            )

        if desired_username is not None:
            yield self.registration_handler.check_username(
                desired_username,
                guest_access_token=guest_access_token,
                assigned_user_id=registered_user_id,
            )

        # Only give msisdn flows if the x_show_msisdn flag is given:
        # this is a hack to work around the fact that clients were shipped
        # that use fallback registration if they see any flows that they don't
        # recognise, which means we break registration for these clients if we
        # advertise msisdn flows. Once usage of Riot iOS <=0.3.9 and Riot
        # Android <=0.6.9 have fallen below an acceptable threshold, this
        # parameter should go away and we should always advertise msisdn flows.
        show_msisdn = False
        if 'x_show_msisdn' in body and body['x_show_msisdn']:
            show_msisdn = True

        # FIXME: need a better error than "no auth flow found" for scenarios
        # where we required 3PID for registration but the user didn't give one
        require_email = 'email' in self.hs.config.registrations_require_3pid
        require_msisdn = 'msisdn' in self.hs.config.registrations_require_3pid

        flows = []
        if self.hs.config.enable_registration_captcha:
            # only support 3PIDless registration if no 3PIDs are required
            if not require_email and not require_msisdn:
                flows.extend([[LoginType.RECAPTCHA]])
            # only support the email-only flow if we don't require MSISDN 3PIDs
            if not require_msisdn:
                flows.extend([[LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA]])

            if show_msisdn:
                # only support the MSISDN-only flow if we don't require email 3PIDs
                if not require_email:
                    flows.extend([[LoginType.MSISDN, LoginType.RECAPTCHA]])
                # always let users provide both MSISDN & email
                flows.extend([
                    [LoginType.MSISDN, LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA],
                ])
        else:
            # only support 3PIDless registration if no 3PIDs are required
            if not require_email and not require_msisdn:
                flows.extend([[LoginType.DUMMY]])
            # only support the email-only flow if we don't require MSISDN 3PIDs
            if not require_msisdn:
                flows.extend([[LoginType.EMAIL_IDENTITY]])

            if show_msisdn:
                # only support the MSISDN-only flow if we don't require email 3PIDs
                if not require_email or require_msisdn:
                    flows.extend([[LoginType.MSISDN]])
                # always let users provide both MSISDN & email
                flows.extend([
                    [LoginType.MSISDN, LoginType.EMAIL_IDENTITY]
                ])

        auth_result, params, session_id = yield self.auth_handler.check_auth(
            flows, body, self.hs.get_ip_from_request(request)
        )

        # Check that we're not trying to register a denied 3pid.
        #
        # the user-facing checks will probably already have happened in
        # /register/email/requestToken when we requested a 3pid, but that's not
        # guaranteed.

        if auth_result:
            for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]:
                if login_type in auth_result:
                    medium = auth_result[login_type]['medium']
                    address = auth_result[login_type]['address']

                    if not check_3pid_allowed(self.hs, medium, address):
                        raise SynapseError(
                            403, "Third party identifier is not allowed",
                            Codes.THREEPID_DENIED,
                        )

        if registered_user_id is not None:
            logger.info(
                "Already registered user ID %r for this session",
                registered_user_id
            )
            # don't re-register the threepids
            add_email = False
            add_msisdn = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            if 'password' not in params:
                raise SynapseError(400, "Missing password.",
                                   Codes.MISSING_PARAM)

            desired_username = params.get("username", None)
            new_password = params.get("password", None)
            guest_access_token = params.get("guest_access_token", None)

            if desired_username is not None:
                desired_username = desired_username.lower()

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                generate_token=False,
            )

            # remember that we've now registered that user account, and with
            #  what user ID (since the user may not have specified)
            self.auth_handler.set_session_data(
                session_id, "registered_user_id", registered_user_id
            )

            add_email = True
            add_msisdn = True

        return_dict = yield self._create_registration_details(
            registered_user_id, params
        )

        if add_email and auth_result and LoginType.EMAIL_IDENTITY in auth_result:
            threepid = auth_result[LoginType.EMAIL_IDENTITY]
            yield self._register_email_threepid(
                registered_user_id, threepid, return_dict["access_token"],
                params.get("bind_email")
            )

        if add_msisdn and auth_result and LoginType.MSISDN in auth_result:
            threepid = auth_result[LoginType.MSISDN]
            yield self._register_msisdn_threepid(
                registered_user_id, threepid, return_dict["access_token"],
                params.get("bind_msisdn")
            )

        defer.returnValue((200, return_dict))
Beispiel #14
0
 def _get_key(self, request):
     token = get_access_token_from_request(request)
     path_without_txn_id = request.path.rsplit("/", 1)[0]
     return path_without_txn_id + "/" + token
Beispiel #15
0
    def on_POST(self, request):
        yield run_on_reactor()

        kind = "user"
        if "kind" in request.args:
            kind = request.args["kind"][0]

        if kind == "guest":
            ret = yield self._do_guest_registration()
            defer.returnValue(ret)
            return
        elif kind != "user":
            raise UnrecognizedRequestError(
                "Do not understand membership kind: %s" % (kind,)
            )

        body = parse_json_object_from_request(request)

        # we do basic sanity checks here because the auth layer will store these
        # in sessions. Pull out the username/password provided to us.
        desired_password = None
        if 'password' in body:
            if (not isinstance(body['password'], basestring) or
                    len(body['password']) > 512):
                raise SynapseError(400, "Invalid password")
            desired_password = body["password"]

        desired_username = None
        if 'username' in body:
            if (not isinstance(body['username'], basestring) or
                    len(body['username']) > 512):
                raise SynapseError(400, "Invalid username")
            desired_username = body['username']

        appservice = None
        if has_access_token(request):
            appservice = yield self.auth.get_appservice_by_req(request)

        # fork off as soon as possible for ASes and shared secret auth which
        # have completely different registration flows to normal users

        # == Application Service Registration ==
        if appservice:
            # Set the desired user according to the AS API (which uses the
            # 'user' key not 'username'). Since this is a new addition, we'll
            # fallback to 'username' if they gave one.
            desired_username = body.get("user", desired_username)
            access_token = get_access_token_from_request(request)

            if isinstance(desired_username, basestring):
                result = yield self._do_appservice_registration(
                    desired_username, access_token, body
                )
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # == Shared Secret Registration == (e.g. create new user scripts)
        if 'mac' in body:
            # FIXME: Should we really be determining if this is shared secret
            # auth based purely on the 'mac' key?
            result = yield self._do_shared_secret_registration(
                desired_username, desired_password, body
            )
            defer.returnValue((200, result))  # we throw for non 200 responses
            return

        # == Normal User Registration == (everyone else)
        if not self.hs.config.enable_registration:
            raise SynapseError(403, "Registration has been disabled")

        guest_access_token = body.get("guest_access_token", None)

        session_id = self.auth_handler.get_session_id(body)
        registered_user_id = None
        if session_id:
            # if we get a registered user id out of here, it means we previously
            # registered a user for this session, so we could just return the
            # user here. We carry on and go through the auth checks though,
            # for paranoia.
            registered_user_id = self.auth_handler.get_session_data(
                session_id, "registered_user_id", None
            )

        if desired_username is not None:
            yield self.registration_handler.check_username(
                desired_username,
                guest_access_token=guest_access_token,
                assigned_user_id=registered_user_id,
            )

        if self.hs.config.enable_registration_captcha:
            flows = [
                [LoginType.RECAPTCHA],
                [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA]
            ]
        else:
            flows = [
                [LoginType.DUMMY],
                [LoginType.EMAIL_IDENTITY]
            ]

        authed, auth_result, params, session_id = yield self.auth_handler.check_auth(
            flows, body, self.hs.get_ip_from_request(request)
        )

        if not authed:
            defer.returnValue((401, auth_result))
            return

        if registered_user_id is not None:
            logger.info(
                "Already registered user ID %r for this session",
                registered_user_id
            )
            # don't re-register the email address
            add_email = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            if 'password' not in params:
                raise SynapseError(400, "Missing password.",
                                   Codes.MISSING_PARAM)

            desired_username = params.get("username", None)
            new_password = params.get("password", None)
            guest_access_token = params.get("guest_access_token", None)

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                generate_token=False,
            )

            # remember that we've now registered that user account, and with
            #  what user ID (since the user may not have specified)
            self.auth_handler.set_session_data(
                session_id, "registered_user_id", registered_user_id
            )

            add_email = True

        return_dict = yield self._create_registration_details(
            registered_user_id, params
        )

        if add_email and auth_result and LoginType.EMAIL_IDENTITY in auth_result:
            threepid = auth_result[LoginType.EMAIL_IDENTITY]
            yield self._register_email_threepid(
                registered_user_id, threepid, return_dict["access_token"],
                params.get("bind_email")
            )

        defer.returnValue((200, return_dict))