示例#1
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, [
            'id_server',
            'client_secret',
            'country',
            'phone_number',
            'send_attempt',
        ])

        msisdn = phone_number_to_msisdn(body['country'], body['phone_number'])

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Phone numbers are not authorized to register on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'msisdn', msisdn)

        if existingUid is not None:
            raise SynapseError(400, "Phone number is already in use",
                               Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        defer.returnValue((200, ret))
示例#2
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_request(body, [
            'id_server', 'client_secret',
            'country', 'phone_number',
            'send_attempt',
        ])

        msisdn = phone_number_to_msisdn(body['country'], body['phone_number'])

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

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'msisdn', msisdn
        )

        if existingUid is not None:
            raise SynapseError(
                400, "Phone number is already in use", Codes.THREEPID_IN_USE
            )

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        defer.returnValue((200, ret))
示例#3
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        required = ['id_server', 'client_secret', 'email', 'send_attempt']
        absent = []
        for k in required:
            if k not in body:
                absent.append(k)

        if absent:
            raise SynapseError(400, "Missing params: %r" % absent,
                               Codes.MISSING_PARAM)

        if not check_3pid_allowed(self.hs, "email", body['email']):
            raise SynapseError(
                403,
                "Third party identifier is not allowed",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.datastore.get_user_id_by_threepid(
            'email', body['email'])

        if existingUid is not None:
            raise SynapseError(400, "Email is already in use",
                               Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestEmailToken(**body)
        defer.returnValue((200, ret))
示例#4
0
    async def on_POST(self, request):
        if self.hs.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
            if self.hs.config.local_threepid_handling_disabled_due_to_email_config:
                logger.warning(
                    "Email registration has been disabled due to lack of email config"
                )
            raise SynapseError(
                400, "Email-based registration has been disabled on this server"
            )
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])

        # Extract params from body
        client_secret = body["client_secret"]
        assert_valid_client_secret(client_secret)

        email = body["email"]
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        if not check_3pid_allowed(self.hs, "email", email):
            raise SynapseError(
                403,
                "Your email domain is not authorized to register on this server",
                Codes.THREEPID_DENIED,
            )

        existing_user_id = await self.hs.get_datastore().get_user_id_by_threepid(
            "email", body["email"]
        )

        if existing_user_id is not None:
            raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)

        if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
            assert self.hs.config.account_threepid_delegate_email

            # Have the configured identity server handle the request
            ret = await self.identity_handler.requestEmailToken(
                self.hs.config.account_threepid_delegate_email,
                email,
                client_secret,
                send_attempt,
                next_link,
            )
        else:
            # Send registration emails from Synapse
            sid = await self.identity_handler.send_threepid_validation(
                email,
                client_secret,
                send_attempt,
                self.mailer.send_registration_mail,
                next_link,
            )

            # Wrap the session id in a JSON object
            ret = {"sid": sid}

        return 200, ret
示例#5
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)
        assert_params_in_dict(
            body,
            [
                "id_server", "client_secret", "country", "phone_number",
                "send_attempt"
            ],
        )

        msisdn = phone_number_to_msisdn(body["country"], body["phone_number"])

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Account phone numbers are not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.datastore.get_user_id_by_threepid(
            "msisdn", msisdn)

        if existingUid is not None:
            raise SynapseError(400, "MSISDN is already in use",
                               Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        return (200, ret)
示例#6
0
    def register_email(self, threepidCreds):
        """
        Registers emails with an identity server.

        Used only by c/s api v1
        """

        for c in threepidCreds:
            logger.info("validating threepidcred sid %s on id server %s",
                        c['sid'], c['idServer'])
            try:
                threepid = yield self.identity_handler.threepid_from_creds(c)
            except Exception:
                logger.exception("Couldn't validate 3pid")
                raise RegistrationError(400, "Couldn't validate 3pid")

            if not threepid:
                raise RegistrationError(400, "Couldn't validate 3pid")
            logger.info("got threepid with medium '%s' and address '%s'",
                        threepid['medium'], threepid['address'])

            if not check_3pid_allowed(self.hs, threepid['medium'], threepid['address']):
                raise RegistrationError(
                    403, "Third party identifier is not allowed"
                )
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, [
            'id_server',
            'client_secret',
            'country',
            'phone_number',
            'send_attempt',
        ])

        msisdn = phone_number_to_msisdn(body['country'], body['phone_number'])

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

        existingUid = yield self.datastore.get_user_id_by_threepid(
            'msisdn', msisdn)

        if existingUid is None:
            raise SynapseError(400, "MSISDN not found",
                               Codes.THREEPID_NOT_FOUND)

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        defer.returnValue((200, ret))
示例#8
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, [
            'id_server', 'client_secret',
            'country', 'phone_number', 'send_attempt',
        ])

        msisdn = phone_number_to_msisdn(body['country'], body['phone_number'])

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Account phone numbers are not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.datastore.get_user_id_by_threepid(
            'msisdn', msisdn
        )

        if existingUid is None:
            raise SynapseError(400, "MSISDN not found", Codes.THREEPID_NOT_FOUND)

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        defer.returnValue((200, ret))
示例#9
0
    def register_email(self, threepidCreds):
        """
        Registers emails with an identity server.

        Used only by c/s api v1
        """

        for c in threepidCreds:
            logger.info("validating threepidcred sid %s on id server %s",
                        c['sid'], c['idServer'])
            try:
                identity_handler = self.hs.get_handlers().identity_handler
                threepid = yield identity_handler.threepid_from_creds(c)
            except Exception:
                logger.exception("Couldn't validate 3pid")
                raise RegistrationError(400, "Couldn't validate 3pid")

            if not threepid:
                raise RegistrationError(400, "Couldn't validate 3pid")
            logger.info("got threepid with medium '%s' and address '%s'",
                        threepid['medium'], threepid['address'])

            if not check_3pid_allowed(self.hs, threepid['medium'],
                                      threepid['address']):
                raise RegistrationError(
                    403, "Third party identifier is not allowed")
示例#10
0
    async def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(
            body, ["client_secret", "country", "phone_number", "send_attempt"])
        client_secret = body["client_secret"]
        country = body["country"]
        phone_number = body["phone_number"]
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        msisdn = phone_number_to_msisdn(country, phone_number)

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Phone numbers are not authorized to register on this server",
                Codes.THREEPID_DENIED,
            )

        self.identity_handler.ratelimit_request_token_requests(
            request, "msisdn", msisdn)

        existing_user_id = await self.hs.get_datastore(
        ).get_user_id_by_threepid("msisdn", msisdn)

        if existing_user_id is not None:
            if self.hs.config.request_token_inhibit_3pid_errors:
                # Make the client think the operation succeeded. See the rationale in the
                # comments for request_token_inhibit_3pid_errors.
                # Also wait for some random amount of time between 100ms and 1s to make it
                # look like we did something.
                await self.hs.get_clock().sleep(random.randint(1, 10) / 10)
                return 200, {"sid": random_string(16)}

            raise SynapseError(400, "Phone number is already in use",
                               Codes.THREEPID_IN_USE)

        if not self.hs.config.account_threepid_delegate_msisdn:
            logger.warning(
                "No upstream msisdn account_threepid_delegate configured on the server to "
                "handle this request")
            raise SynapseError(
                400,
                "Registration by phone number is not supported on this homeserver"
            )

        ret = await self.identity_handler.requestMsisdnToken(
            self.hs.config.account_threepid_delegate_msisdn,
            country,
            phone_number,
            client_secret,
            send_attempt,
            next_link,
        )

        threepid_send_requests.labels(type="msisdn",
                                      reason="register").observe(send_attempt)

        return 200, ret
示例#11
0
    def on_POST(self, request):
        if not self.config.email_password_reset_behaviour == "off":
            raise SynapseError(
                400, "Password resets have been disabled on this server")

        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, [
            'id_server',
            'client_secret',
            'country',
            'phone_number',
            'send_attempt',
        ])

        msisdn = phone_number_to_msisdn(body['country'], body['phone_number'])

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Account phone numbers are not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.datastore.get_user_id_by_threepid(
            'msisdn', msisdn)

        if existingUid is None:
            raise SynapseError(400, "MSISDN not found",
                               Codes.THREEPID_NOT_FOUND)

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        defer.returnValue((200, ret))
示例#12
0
文件: account.py 项目: rubo77/synapse
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        required = [
            'id_server', 'client_secret',
            'country', 'phone_number', 'send_attempt',
        ]
        absent = []
        for k in required:
            if k not in body:
                absent.append(k)

        if absent:
            raise SynapseError(400, "Missing params: %r" % absent, Codes.MISSING_PARAM)

        msisdn = phone_number_to_msisdn(body['country'], body['phone_number'])

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

        existingUid = yield self.datastore.get_user_id_by_threepid(
            'msisdn', msisdn
        )

        if existingUid is not None:
            raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestMsisdnToken(**body)
        defer.returnValue((200, ret))
示例#13
0
    def on_POST(self, request):
        if self.config.email_password_reset_behaviour == "off":
            raise SynapseError(
                400, "Password resets have been disabled on this server")

        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, ['client_secret', 'email', 'send_attempt'])

        # Extract params from body
        client_secret = body["client_secret"]
        email = body["email"]
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        if not check_3pid_allowed(self.hs, "email", email):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'email',
            email,
        )

        if existingUid is None:
            raise SynapseError(400, "Email not found",
                               Codes.THREEPID_NOT_FOUND)

        if self.config.email_password_reset_behaviour == "remote":
            if 'id_server' not in body:
                raise SynapseError(400, "Missing 'id_server' param in body")

            # Have the identity server handle the password reset flow
            ret = yield self.identity_handler.requestEmailToken(
                body["id_server"],
                email,
                client_secret,
                send_attempt,
                next_link,
            )
        else:
            # Send password reset emails from Synapse
            sid = yield self.send_password_reset(
                email,
                client_secret,
                send_attempt,
                next_link,
            )

            # Wrap the session id in a JSON object
            ret = {"sid": sid}

        defer.returnValue((200, ret))
示例#14
0
    async def on_POST(self, request):
        body = parse_json_object_from_request(request)
        assert_params_in_dict(
            body, ["client_secret", "country", "phone_number", "send_attempt"])
        client_secret = body["client_secret"]
        assert_valid_client_secret(client_secret)

        country = body["country"]
        phone_number = body["phone_number"]
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        msisdn = phone_number_to_msisdn(country, phone_number)

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Account phone numbers are not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existing_user_id = await self.store.get_user_id_by_threepid(
            "msisdn", msisdn)

        if existing_user_id is not None:
            if self.hs.config.request_token_inhibit_3pid_errors:
                # Make the client think the operation succeeded. See the rationale in the
                # comments for request_token_inhibit_3pid_errors.
                return 200, {"sid": random_string(16)}

            raise SynapseError(400, "MSISDN is already in use",
                               Codes.THREEPID_IN_USE)

        if not self.hs.config.account_threepid_delegate_msisdn:
            logger.warning(
                "No upstream msisdn account_threepid_delegate configured on the server to "
                "handle this request")
            raise SynapseError(
                400,
                "Adding phone numbers to user account is not supported by this homeserver",
            )

        ret = await self.identity_handler.requestMsisdnToken(
            self.hs.config.account_threepid_delegate_msisdn,
            country,
            phone_number,
            client_secret,
            send_attempt,
            next_link,
        )

        return 200, ret
示例#15
0
    async def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(
            body, ["client_secret", "country", "phone_number", "send_attempt"]
        )
        client_secret = body["client_secret"]
        country = body["country"]
        phone_number = body["phone_number"]
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        msisdn = phone_number_to_msisdn(country, phone_number)

        if not check_3pid_allowed(self.hs, "msisdn", msisdn):
            raise SynapseError(
                403,
                "Phone numbers are not authorized to register on this server",
                Codes.THREEPID_DENIED,
            )

        existing_user_id = await self.hs.get_datastore().get_user_id_by_threepid(
            "msisdn", msisdn
        )

        if existing_user_id is not None:
            raise SynapseError(
                400, "Phone number is already in use", Codes.THREEPID_IN_USE
            )

        if not self.hs.config.account_threepid_delegate_msisdn:
            logger.warning(
                "No upstream msisdn account_threepid_delegate configured on the server to "
                "handle this request"
            )
            raise SynapseError(
                400, "Registration by phone number is not supported on this homeserver"
            )

        ret = await self.identity_handler.requestMsisdnToken(
            self.hs.config.account_threepid_delegate_msisdn,
            country,
            phone_number,
            client_secret,
            send_attempt,
            next_link,
        )

        return 200, ret
示例#16
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, [
            'id_server', 'client_secret', 'email', 'send_attempt'
        ])

        if not check_3pid_allowed(self.hs, "email", body['email']):
            raise SynapseError(
                403, "Third party identifier is not allowed", Codes.THREEPID_DENIED,
            )

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'email', body['email']
        )

        if existingUid is not None:
            raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestEmailToken(**body)
        defer.returnValue((200, ret))
示例#17
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_request(body, [
            'id_server', 'client_secret', 'email', 'send_attempt'
        ])

        if not check_3pid_allowed(self.hs, "email", body['email']):
            raise SynapseError(
                403, "Third party identifier is not allowed", Codes.THREEPID_DENIED,
            )

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'email', body['email']
        )

        if existingUid is not None:
            raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestEmailToken(**body)
        defer.returnValue((200, ret))
示例#18
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)
        assert_params_in_dict(
            body, ["id_server", "client_secret", "email", "send_attempt"])

        if not check_3pid_allowed(self.hs, "email", body["email"]):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.datastore.get_user_id_by_threepid(
            "email", body["email"])

        if existingUid is not None:
            raise SynapseError(400, "Email is already in use",
                               Codes.THREEPID_IN_USE)

        ret = yield self.identity_handler.requestEmailToken(**body)
        return (200, ret)
示例#19
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(
            body, ['id_server', 'client_secret', 'email', 'send_attempt'])

        if not check_3pid_allowed(self.hs, "email", body['email']):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'email', body['email'])

        if existingUid is None:
            raise SynapseError(400, "Email not found",
                               Codes.THREEPID_NOT_FOUND)

        ret = yield self.identity_handler.requestEmailToken(**body)
        defer.returnValue((200, ret))
示例#20
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, [
            'id_server', 'client_secret', 'email', 'send_attempt'
        ])

        if not check_3pid_allowed(self.hs, "email", body['email']):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
            'email', body['email']
        )

        if existingUid is None:
            raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)

        ret = yield self.identity_handler.requestEmailToken(**body)
        defer.returnValue((200, ret))
示例#21
0
文件: register.py 项目: Fnux/synapse
    async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        if self.hs.config.email.threepid_behaviour_email == ThreepidBehaviour.OFF:
            if (self.hs.config.email.
                    local_threepid_handling_disabled_due_to_email_config):
                logger.warning(
                    "Email registration has been disabled due to lack of email config"
                )
            raise SynapseError(
                400,
                "Email-based registration has been disabled on this server")
        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])

        # Extract params from body
        client_secret = body["client_secret"]
        assert_valid_client_secret(client_secret)

        # For emails, canonicalise the address.
        # We store all email addresses canonicalised in the DB.
        # (See on_POST in EmailThreepidRequestTokenRestServlet
        # in synapse/rest/client/account.py)
        try:
            email = validate_email(body["email"])
        except ValueError as e:
            raise SynapseError(400, str(e))
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        if not check_3pid_allowed(self.hs, "email", email):
            raise SynapseError(
                403,
                "Your email domain is not authorized to register on this server",
                Codes.THREEPID_DENIED,
            )

        await self.identity_handler.ratelimit_request_token_requests(
            request, "email", email)

        existing_user_id = await self.hs.get_datastore(
        ).get_user_id_by_threepid("email", email)

        if existing_user_id is not None:
            if self.hs.config.server.request_token_inhibit_3pid_errors:
                # Make the client think the operation succeeded. See the rationale in the
                # comments for request_token_inhibit_3pid_errors.
                # Also wait for some random amount of time between 100ms and 1s to make it
                # look like we did something.
                await self.hs.get_clock().sleep(random.randint(1, 10) / 10)
                return 200, {"sid": random_string(16)}

            raise SynapseError(400, "Email is already in use",
                               Codes.THREEPID_IN_USE)

        if self.config.email.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
            assert self.hs.config.registration.account_threepid_delegate_email

            # Have the configured identity server handle the request
            ret = await self.identity_handler.requestEmailToken(
                self.hs.config.registration.account_threepid_delegate_email,
                email,
                client_secret,
                send_attempt,
                next_link,
            )
        else:
            # Send registration emails from Synapse
            sid = await self.identity_handler.send_threepid_validation(
                email,
                client_secret,
                send_attempt,
                self.mailer.send_registration_mail,
                next_link,
            )

            # Wrap the session id in a JSON object
            ret = {"sid": sid}

        threepid_send_requests.labels(type="email",
                                      reason="register").observe(send_attempt)

        return 200, ret
示例#22
0
文件: register.py 项目: Fnux/synapse
    async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
        body = parse_json_object_from_request(request)

        client_addr = request.getClientIP()

        await self.ratelimiter.ratelimit(None, client_addr, update=False)

        kind = parse_string(request, "kind", default="user")

        if kind == "guest":
            ret = await self._do_guest_registration(body, address=client_addr)
            return ret
        elif kind != "user":
            raise UnrecognizedRequestError(
                f"Do not understand membership kind: {kind}", )

        # Check if the clients wishes for this registration to issue a refresh
        # token.
        client_requested_refresh_tokens = body.get("refresh_token", False)
        if not isinstance(client_requested_refresh_tokens, bool):
            raise SynapseError(400, "`refresh_token` should be true or false.")

        should_issue_refresh_token = (self._refresh_tokens_enabled
                                      and client_requested_refresh_tokens)

        # Pull out the provided username and do basic sanity checks early since
        # the auth layer will store these in sessions.
        desired_username = None
        if "username" in body:
            if not isinstance(body["username"],
                              str) or len(body["username"]) > 512:
                raise SynapseError(400, "Invalid username")
            desired_username = body["username"]

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

        # == Application Service Registration ==
        if body.get("type") == APP_SERVICE_REGISTRATION_TYPE:
            if not self.auth.has_access_token(request):
                raise SynapseError(
                    400,
                    "Appservice token must be provided when using a type of m.login.application_service",
                )

            # Verify the AS
            self.auth.get_appservice_by_req(request)

            # 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 = self.auth.get_access_token_from_request(request)

            if not isinstance(desired_username, str):
                raise SynapseError(
                    400, "Desired Username is missing or not a string")

            result = await self._do_appservice_registration(
                desired_username,
                access_token,
                body,
                should_issue_refresh_token=should_issue_refresh_token,
            )

            return 200, result
        elif self.auth.has_access_token(request):
            raise SynapseError(
                400,
                "An access token should not be provided on requests to /register (except if type is m.login.application_service)",
            )

        # == Normal User Registration == (everyone else)
        if not self._registration_enabled:
            raise SynapseError(403, "Registration has been disabled",
                               Codes.FORBIDDEN)

        # For regular registration, convert the provided username to lowercase
        # 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 usernames case-insensitively 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()

        # Check if this account is upgrading from a guest account.
        guest_access_token = body.get("guest_access_token", None)

        # Pull out the provided password and do basic sanity checks early.
        #
        # Note that we remove the password from the body since the auth layer
        # will store the body in the session and we don't want a plaintext
        # password store there.
        password = body.pop("password", None)
        if password is not None:
            if not isinstance(password, str) or len(password) > 512:
                raise SynapseError(400, "Invalid password")
            self.password_policy_handler.validate_password(password)

        if "initial_device_display_name" in body and password is None:
            # 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.warning(
                "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
        password_hash = 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 = await self.auth_handler.get_session_data(
                session_id, UIAuthSessionDataConstants.REGISTERED_USER_ID,
                None)
            # Extract the previously-hashed password from the session.
            password_hash = await self.auth_handler.get_session_data(
                session_id, UIAuthSessionDataConstants.PASSWORD_HASH, None)

        # Ensure that the username is valid.
        if desired_username is not None:
            await self.registration_handler.check_username(
                desired_username,
                guest_access_token=guest_access_token,
                assigned_user_id=registered_user_id,
            )

        # Check if the user-interactive authentication flows are complete, if
        # not this will raise a user-interactive auth error.
        try:
            auth_result, params, session_id = await self.auth_handler.check_ui_auth(
                self._registration_flows,
                request,
                body,
                "register a new account",
            )
        except InteractiveAuthIncompleteError as e:
            # The user needs to provide more steps to complete auth.
            #
            # Hash the password and store it with the session since the client
            # is not required to provide the password again.
            #
            # If a password hash was previously stored we will not attempt to
            # re-hash and store it for efficiency. This assumes the password
            # does not change throughout the authentication flow, but this
            # should be fine since the data is meant to be consistent.
            if not password_hash and password:
                password_hash = await self.auth_handler.hash(password)
                await self.auth_handler.set_session_data(
                    e.session_id,
                    UIAuthSessionDataConstants.PASSWORD_HASH,
                    password_hash,
                )
            raise

        # 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 identifiers (email/phone numbers)" +
                            " are not authorized on this server",
                            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
            registered = False
        else:
            # If we have a password in this request, prefer it. Otherwise, there
            # might be a password hash from an earlier request.
            if password:
                password_hash = await self.auth_handler.hash(password)
            if not password_hash:
                raise SynapseError(400, "Missing params: password",
                                   Codes.MISSING_PARAM)

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

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

            threepid = None
            if auth_result:
                threepid = auth_result.get(LoginType.EMAIL_IDENTITY)

                # Also check that we're not trying to register a 3pid that's already
                # been registered.
                #
                # This has probably happened in /register/email/requestToken as well,
                # but if a user hits this endpoint twice then clicks on each link from
                # the two activation emails, they would register the same 3pid twice.
                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"]
                        # For emails, canonicalise the address.
                        # We store all email addresses canonicalised in the DB.
                        # (See on_POST in EmailThreepidRequestTokenRestServlet
                        # in synapse/rest/client/account.py)
                        if medium == "email":
                            try:
                                address = canonicalise_email(address)
                            except ValueError as e:
                                raise SynapseError(400, str(e))

                        existing_user_id = await self.store.get_user_id_by_threepid(
                            medium, address)

                        if existing_user_id is not None:
                            raise SynapseError(
                                400,
                                "%s is already in use" % medium,
                                Codes.THREEPID_IN_USE,
                            )

            entries = await self.store.get_user_agents_ips_to_ui_auth_session(
                session_id)

            registered_user_id = await self.registration_handler.register_user(
                localpart=desired_username,
                password_hash=password_hash,
                guest_access_token=guest_access_token,
                threepid=threepid,
                address=client_addr,
                user_agent_ips=entries,
            )
            # Necessary due to auth checks prior to the threepid being
            # written to the db
            if threepid:
                if is_threepid_reserved(
                        self.hs.config.server.mau_limits_reserved_threepids,
                        threepid):
                    await self.store.upsert_monthly_active_user(
                        registered_user_id)

            # Remember that the user account has been registered (and the user
            # ID it was registered with, since it might not have been specified).
            await self.auth_handler.set_session_data(
                session_id,
                UIAuthSessionDataConstants.REGISTERED_USER_ID,
                registered_user_id,
            )

            registered = True

        return_dict = await self._create_registration_details(
            registered_user_id,
            params,
            should_issue_refresh_token=should_issue_refresh_token,
        )

        if registered:
            # Check if a token was used to authenticate registration
            registration_token = await self.auth_handler.get_session_data(
                session_id,
                UIAuthSessionDataConstants.REGISTRATION_TOKEN,
            )
            if registration_token:
                # Increment the `completed` counter for the token
                await self.store.use_registration_token(registration_token)
                # Indicate that the token has been successfully used so that
                # pending is not decremented again when expiring old UIA sessions.
                await self.store.mark_ui_auth_stage_complete(
                    session_id,
                    LoginType.REGISTRATION_TOKEN,
                    True,
                )

            await self.registration_handler.post_registration_actions(
                user_id=registered_user_id,
                auth_result=auth_result,
                access_token=return_dict.get("access_token"),
            )

        return 200, return_dict
示例#23
0
    async def on_POST(self, request):
        body = parse_json_object_from_request(request)

        client_addr = request.getClientIP()

        time_now = self.clock.time()

        allowed, time_allowed = self.ratelimiter.can_do_action(
            client_addr,
            time_now_s=time_now,
            rate_hz=self.hs.config.rc_registration.per_second,
            burst_count=self.hs.config.rc_registration.burst_count,
            update=False,
        )

        if not allowed:
            raise LimitExceededError(
                retry_after_ms=int(1000 * (time_allowed - time_now)))

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

        if kind == b"guest":
            ret = await self._do_guest_registration(body, address=client_addr)
            return ret
        elif kind != b"user":
            raise UnrecognizedRequestError(
                "Do not understand membership kind: %s" %
                (kind.decode("utf8"), ))

        # we do basic sanity checks here because the auth layer will store these
        # in sessions. Pull out the username/password provided to us.
        if "password" in body:
            if (not isinstance(body["password"], string_types)
                    or len(body["password"]) > 512):
                raise SynapseError(400, "Invalid password")
            self.password_policy_handler.validate_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 self.auth.has_access_token(request):
            appservice = await self.auth.get_appservice_by_req(request)

        # fork off as soon as possible for ASes 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 = self.auth.get_access_token_from_request(request)

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

        # for 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()

        # == 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.warning(
                "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 = await self.auth_handler.get_session_data(
                session_id, "registered_user_id", None)

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

        auth_result, params, session_id = await self.auth_handler.check_auth(
            self._registration_flows,
            request,
            body,
            self.hs.get_ip_from_request(request),
            "register a new account",
            validate_clientdict=False,
        )

        # 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 identifiers (email/phone numbers)" +
                            " are not authorized on this server",
                            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
            registered = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            assert_params_in_dict(params, ["password"])

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

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

            threepid = None
            if auth_result:
                threepid = auth_result.get(LoginType.EMAIL_IDENTITY)

                # Also check that we're not trying to register a 3pid that's already
                # been registered.
                #
                # This has probably happened in /register/email/requestToken as well,
                # but if a user hits this endpoint twice then clicks on each link from
                # the two activation emails, they would register the same 3pid twice.
                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"]

                        existing_user_id = await self.store.get_user_id_by_threepid(
                            medium, address)

                        if existing_user_id is not None:
                            raise SynapseError(
                                400,
                                "%s is already in use" % medium,
                                Codes.THREEPID_IN_USE,
                            )

            registered_user_id = await self.registration_handler.register_user(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                threepid=threepid,
                address=client_addr,
            )
            # Necessary due to auth checks prior to the threepid being
            # written to the db
            if threepid:
                if is_threepid_reserved(
                        self.hs.config.mau_limits_reserved_threepids,
                        threepid):
                    await self.store.upsert_monthly_active_user(
                        registered_user_id)

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

            registered = True

        return_dict = await self._create_registration_details(
            registered_user_id, params)

        if registered:
            await self.registration_handler.post_registration_actions(
                user_id=registered_user_id,
                auth_result=auth_result,
                access_token=return_dict.get("access_token"),
            )

        return 200, return_dict
示例#24
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        client_addr = request.getClientIP()

        time_now = self.clock.time()

        allowed, time_allowed = self.ratelimiter.can_do_action(
            client_addr,
            time_now_s=time_now,
            rate_hz=self.hs.config.rc_registration.per_second,
            burst_count=self.hs.config.rc_registration.burst_count,
            update=False,
        )

        if not allowed:
            raise LimitExceededError(retry_after_ms=int(
                1000 * (time_allowed - time_now)), )

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

        if kind == b"guest":
            ret = yield self._do_guest_registration(body, address=client_addr)
            defer.returnValue(ret)
            return
        elif kind != b"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 self.auth.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 = self.auth.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,
            )

        # 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

        show_msisdn = True
        if self.hs.config.disable_msisdn_registration:
            show_msisdn = False
            require_msisdn = False

        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:
                # Also add a dummy flow here, otherwise if a client completes
                # recaptcha first we'll assume they were going for this flow
                # and complete the request, when they could have been trying to
                # complete one of the flows with email/msisdn auth.
                flows.extend([[LoginType.RECAPTCHA, LoginType.DUMMY]])
            # only support the email-only flow if we don't require MSISDN 3PIDs
            if not require_msisdn:
                flows.extend([[LoginType.RECAPTCHA, LoginType.EMAIL_IDENTITY]])

            if show_msisdn:
                # only support the MSISDN-only flow if we don't require email 3PIDs
                if not require_email:
                    flows.extend([[LoginType.RECAPTCHA, LoginType.MSISDN]])
                # always let users provide both MSISDN & email
                flows.extend([
                    [
                        LoginType.RECAPTCHA, LoginType.MSISDN,
                        LoginType.EMAIL_IDENTITY
                    ],
                ])
        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]])

        # Append m.login.terms to all flows if we're requiring consent
        if self.hs.config.user_consent_at_registration:
            new_flows = []
            for flow in flows:
                inserted = False
                # m.login.terms should go near the end but before msisdn or email auth
                for i, stage in enumerate(flow):
                    if stage == LoginType.EMAIL_IDENTITY or stage == LoginType.MSISDN:
                        flow.insert(i, LoginType.TERMS)
                        inserted = True
                        break
                if not inserted:
                    flow.append(LoginType.TERMS)
            flows.extend(new_flows)

        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 identifiers (email/phone numbers)" +
                            " are not authorized on this server",
                            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
            registered = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            assert_params_in_dict(params, ["password"])

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

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

            threepid = None
            if auth_result:
                threepid = auth_result.get(LoginType.EMAIL_IDENTITY)

                # Also check that we're not trying to register a 3pid that's already
                # been registered.
                #
                # This has probably happened in /register/email/requestToken as well,
                # but if a user hits this endpoint twice then clicks on each link from
                # the two activation emails, they would register the same 3pid twice.
                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']

                        existingUid = yield self.store.get_user_id_by_threepid(
                            medium,
                            address,
                        )

                        if existingUid is not None:
                            raise SynapseError(
                                400,
                                "%s is already in use" % medium,
                                Codes.THREEPID_IN_USE,
                            )

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                generate_token=False,
                threepid=threepid,
                address=client_addr,
            )
            # Necessary due to auth checks prior to the threepid being
            # written to the db
            if threepid:
                if is_threepid_reserved(
                        self.hs.config.mau_limits_reserved_threepids,
                        threepid):
                    yield self.store.upsert_monthly_active_user(
                        registered_user_id)

            # 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)

            registered = True

        return_dict = yield self._create_registration_details(
            registered_user_id, params)

        if registered:
            yield self.registration_handler.post_registration_actions(
                user_id=registered_user_id,
                auth_result=auth_result,
                access_token=return_dict.get("access_token"),
                bind_email=params.get("bind_email"),
                bind_msisdn=params.get("bind_msisdn"),
            )

        defer.returnValue((200, return_dict))
示例#25
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

        client_addr = request.getClientIP()

        time_now = self.clock.time()

        allowed, time_allowed = self.ratelimiter.can_do_action(
            client_addr, time_now_s=time_now,
            rate_hz=self.hs.config.rc_registration.per_second,
            burst_count=self.hs.config.rc_registration.burst_count,
            update=False,
        )

        if not allowed:
            raise LimitExceededError(
                retry_after_ms=int(1000 * (time_allowed - time_now)),
            )

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

        if kind == b"guest":
            ret = yield self._do_guest_registration(body, address=client_addr)
            defer.returnValue(ret)
            return
        elif kind != b"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 self.auth.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 = self.auth.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,
            )

        # 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

        show_msisdn = True
        if self.hs.config.disable_msisdn_registration:
            show_msisdn = False
            require_msisdn = False

        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:
                # Also add a dummy flow here, otherwise if a client completes
                # recaptcha first we'll assume they were going for this flow
                # and complete the request, when they could have been trying to
                # complete one of the flows with email/msisdn auth.
                flows.extend([[LoginType.RECAPTCHA, LoginType.DUMMY]])
            # only support the email-only flow if we don't require MSISDN 3PIDs
            if not require_msisdn:
                flows.extend([[LoginType.RECAPTCHA, LoginType.EMAIL_IDENTITY]])

            if show_msisdn:
                # only support the MSISDN-only flow if we don't require email 3PIDs
                if not require_email:
                    flows.extend([[LoginType.RECAPTCHA, LoginType.MSISDN]])
                # always let users provide both MSISDN & email
                flows.extend([
                    [LoginType.RECAPTCHA, LoginType.MSISDN, LoginType.EMAIL_IDENTITY],
                ])
        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]
                ])

        # Append m.login.terms to all flows if we're requiring consent
        if self.hs.config.user_consent_at_registration:
            new_flows = []
            for flow in flows:
                inserted = False
                # m.login.terms should go near the end but before msisdn or email auth
                for i, stage in enumerate(flow):
                    if stage == LoginType.EMAIL_IDENTITY or stage == LoginType.MSISDN:
                        flow.insert(i, LoginType.TERMS)
                        inserted = True
                        break
                if not inserted:
                    flow.append(LoginType.TERMS)
            flows.extend(new_flows)

        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 identifiers (email/phone numbers)" +
                            " are not authorized on this server",
                            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
            registered = False
        else:
            # NB: This may be from the auth handler and NOT from the POST
            assert_params_in_dict(params, ["password"])

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

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

            threepid = None
            if auth_result:
                threepid = auth_result.get(LoginType.EMAIL_IDENTITY)

                # Also check that we're not trying to register a 3pid that's already
                # been registered.
                #
                # This has probably happened in /register/email/requestToken as well,
                # but if a user hits this endpoint twice then clicks on each link from
                # the two activation emails, they would register the same 3pid twice.
                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']

                        existingUid = yield self.store.get_user_id_by_threepid(
                            medium, address,
                        )

                        if existingUid is not None:
                            raise SynapseError(
                                400,
                                "%s is already in use" % medium,
                                Codes.THREEPID_IN_USE,
                            )

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                guest_access_token=guest_access_token,
                generate_token=False,
                threepid=threepid,
                address=client_addr,
            )
            # Necessary due to auth checks prior to the threepid being
            # written to the db
            if threepid:
                if is_threepid_reserved(
                    self.hs.config.mau_limits_reserved_threepids, threepid
                ):
                    yield self.store.upsert_monthly_active_user(registered_user_id)

            # 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
            )

            registered = True

        return_dict = yield self._create_registration_details(
            registered_user_id, params
        )

        if registered:
            yield self.registration_handler.post_registration_actions(
                user_id=registered_user_id,
                auth_result=auth_result,
                access_token=return_dict.get("access_token"),
                bind_email=params.get("bind_email"),
                bind_msisdn=params.get("bind_msisdn"),
            )

        defer.returnValue((200, return_dict))
示例#26
0
    async def on_POST(self, request):
        if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
            if self.config.local_threepid_handling_disabled_due_to_email_config:
                logger.warning(
                    "User password resets have been disabled due to lack of email config"
                )
            raise SynapseError(
                400,
                "Email-based password resets have been disabled on this server"
            )

        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])

        # Extract params from body
        client_secret = body["client_secret"]
        assert_valid_client_secret(client_secret)

        # Canonicalise the email address. The addresses are all stored canonicalised
        # in the database. This allows the user to reset his password without having to
        # know the exact spelling (eg. upper and lower case) of address in the database.
        # Stored in the database "*****@*****.**"
        # User requests with "*****@*****.**" would raise a Not Found error
        try:
            email = canonicalise_email(body["email"])
        except ValueError as e:
            raise SynapseError(400, str(e))
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        if not check_3pid_allowed(self.hs, "email", email):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        # The email will be sent to the stored address.
        # This avoids a potential account hijack by requesting a password reset to
        # an email address which is controlled by the attacker but which, after
        # canonicalisation, matches the one in our database.
        existing_user_id = await self.hs.get_datastore(
        ).get_user_id_by_threepid("email", email)

        if existing_user_id is None:
            if self.config.request_token_inhibit_3pid_errors:
                # Make the client think the operation succeeded. See the rationale in the
                # comments for request_token_inhibit_3pid_errors.
                return 200, {"sid": random_string(16)}

            raise SynapseError(400, "Email not found",
                               Codes.THREEPID_NOT_FOUND)

        if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
            assert self.hs.config.account_threepid_delegate_email

            # Have the configured identity server handle the request
            ret = await self.identity_handler.requestEmailToken(
                self.hs.config.account_threepid_delegate_email,
                email,
                client_secret,
                send_attempt,
                next_link,
            )
        else:
            # Send password reset emails from Synapse
            sid = await self.identity_handler.send_threepid_validation(
                email,
                client_secret,
                send_attempt,
                self.mailer.send_password_reset_mail,
                next_link,
            )

            # Wrap the session id in a JSON object
            ret = {"sid": sid}

        return 200, ret
示例#27
0
    async def on_POST(self, request):
        if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
            if self.config.local_threepid_handling_disabled_due_to_email_config:
                logger.warning(
                    "Adding emails have been disabled due to lack of an email config"
                )
            raise SynapseError(
                400,
                "Adding an email to your account is disabled on this server")

        body = parse_json_object_from_request(request)
        assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
        client_secret = body["client_secret"]
        assert_valid_client_secret(client_secret)

        # Canonicalise the email address. The addresses are all stored canonicalised
        # in the database.
        # This ensures that the validation email is sent to the canonicalised address
        # as it will later be entered into the database.
        # Otherwise the email will be sent to "*****@*****.**" and stored as
        # "*****@*****.**" in database.
        try:
            email = canonicalise_email(body["email"])
        except ValueError as e:
            raise SynapseError(400, str(e))
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        if not check_3pid_allowed(self.hs, "email", email):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existing_user_id = await self.store.get_user_id_by_threepid(
            "email", email)

        if existing_user_id is not None:
            if self.config.request_token_inhibit_3pid_errors:
                # Make the client think the operation succeeded. See the rationale in the
                # comments for request_token_inhibit_3pid_errors.
                return 200, {"sid": random_string(16)}

            raise SynapseError(400, "Email is already in use",
                               Codes.THREEPID_IN_USE)

        if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
            assert self.hs.config.account_threepid_delegate_email

            # Have the configured identity server handle the request
            ret = await self.identity_handler.requestEmailToken(
                self.hs.config.account_threepid_delegate_email,
                email,
                client_secret,
                send_attempt,
                next_link,
            )
        else:
            # Send threepid validation emails from Synapse
            sid = await self.identity_handler.send_threepid_validation(
                email,
                client_secret,
                send_attempt,
                self.mailer.send_add_threepid_mail,
                next_link,
            )

            # Wrap the session id in a JSON object
            ret = {"sid": sid}

        return 200, ret
示例#28
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))
示例#29
0
    def on_POST(self, request):
        body = parse_json_object_from_request(request)

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

        if kind == b"guest":
            ret = yield self._do_guest_registration(body)
            defer.returnValue(ret)
            return
        elif kind != b"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']
            desired_username = body['username']

        appservice = None
        if self.auth.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 = self.auth.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 identifiers (email/phone numbers)" +
                            " are not authorized on this server",
                            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
            assert_params_in_dict(params, ["password"])

            desired_username = params.get("username", None)
            guest_access_token = params.get("guest_access_token", None)
            new_password = params.get("password", None)
            gender = params.get("gender", None)
            dob = params.get("dob", None)
            address = params.get("address", None)
            mobile_no = params.get("mobile_no", None)
            place = params.get("place", None)
            department = params.get("department", None)
            branch = params.get("branch", None)



            # print("--------------v2 alpha -------- register.py-------------------------------------------------------")
            # print("desired_username = "******"guest_access_token = ",guest_access_token)
            # print("new_password = "******"gender = ",gender)
            # print("dob = ",dob)
            # print("address = ",address)
            # print("mobile_no =",mobile_no)




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

            threepid = None
            if auth_result:
                threepid = auth_result.get(LoginType.EMAIL_IDENTITY)

            (registered_user_id, _) = yield self.registration_handler.register(
                localpart=desired_username,
                password=new_password,
                gender=gender,
                dob=dob,#.slice(0,10),
                address=address,
                mobile_no=mobile_no,
                place=place,
                department=department,
                branch=branch,
                guest_access_token=guest_access_token,
                generate_token=False,
                threepid=threepid
            )
            # Necessary due to auth checks prior to the threepid being
            # written to the db
            if is_threepid_reserved(self.hs.config, threepid):
                yield self.store.upsert_monthly_active_user(registered_user_id)

            # 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))
示例#30
0
文件: account.py 项目: vfat0/synapse
    async def on_POST(self, request):
        if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
            if self.config.local_threepid_handling_disabled_due_to_email_config:
                logger.warning(
                    "User password resets have been disabled due to lack of email config"
                )
            raise SynapseError(
                400,
                "Email-based password resets have been disabled on this server"
            )

        body = parse_json_object_from_request(request)

        assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])

        # Extract params from body
        client_secret = body["client_secret"]
        assert_valid_client_secret(client_secret)

        email = body["email"]
        send_attempt = body["send_attempt"]
        next_link = body.get("next_link")  # Optional param

        if not check_3pid_allowed(self.hs, "email", email):
            raise SynapseError(
                403,
                "Your email domain is not authorized on this server",
                Codes.THREEPID_DENIED,
            )

        existing_user_id = await self.hs.get_datastore(
        ).get_user_id_by_threepid("email", email)

        if existing_user_id is None:
            if self.config.request_token_inhibit_3pid_errors:
                # Make the client think the operation succeeded. See the rationale in the
                # comments for request_token_inhibit_3pid_errors.
                return 200, {"sid": random_string(16)}

            raise SynapseError(400, "Email not found",
                               Codes.THREEPID_NOT_FOUND)

        if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
            assert self.hs.config.account_threepid_delegate_email

            # Have the configured identity server handle the request
            ret = await self.identity_handler.requestEmailToken(
                self.hs.config.account_threepid_delegate_email,
                email,
                client_secret,
                send_attempt,
                next_link,
            )
        else:
            # Send password reset emails from Synapse
            sid = await self.identity_handler.send_threepid_validation(
                email,
                client_secret,
                send_attempt,
                self.mailer.send_password_reset_mail,
                next_link,
            )

            # Wrap the session id in a JSON object
            ret = {"sid": sid}

        return 200, ret