Exemple #1
0
    async def on_GET(self, request: Request) -> Tuple[int, JsonDict]:
        await self.ratelimiter.ratelimit(None,
                                         (request.getClientAddress().host, ))

        if not self.hs.config.registration.enable_registration:
            raise SynapseError(403,
                               "Registration has been disabled",
                               errcode=Codes.FORBIDDEN)

        token = parse_string(request, "token", required=True)
        valid = await self.store.registration_token_is_valid(token)

        return 200, {"valid": valid}
Exemple #2
0
    async def on_GET(self, request: Request) -> Tuple[int, JsonDict]:
        if not self.hs.config.registration.enable_registration:
            raise SynapseError(403,
                               "Registration has been disabled",
                               errcode=Codes.FORBIDDEN)

        if self.inhibit_user_in_use_error:
            return 200, {"available": True}

        ip = request.getClientAddress().host
        with self.ratelimiter.ratelimit(ip) as wait_deferred:
            await wait_deferred

            username = parse_string(request, "username", required=True)

            await self.registration_handler.check_username(username)

            return 200, {"available": True}
Exemple #3
0
    async def _get_appservice_user_id_and_device_id(
        self, request: Request
    ) -> Tuple[Optional[str], Optional[str], Optional[ApplicationService]]:
        """
        Given a request, reads the request parameters to determine:
        - whether it's an application service that's making this request
        - what user the application service should be treated as controlling
          (the user_id URI parameter allows an application service to masquerade
          any applicable user in its namespace)
        - what device the application service should be treated as controlling
          (the device_id[^1] URI parameter allows an application service to masquerade
          as any device that exists for the relevant user)

        [^1] Unstable and provided by MSC3202.
             Must use `org.matrix.msc3202.device_id` in place of `device_id` for now.

        Returns:
            3-tuple of
            (user ID?, device ID?, application service?)

        Postconditions:
        - If an application service is returned, so is a user ID
        - A user ID is never returned without an application service
        - A device ID is never returned without a user ID or an application service
        - The returned application service, if present, is permitted to control the
          returned user ID.
        - The returned device ID, if present, has been checked to be a valid device ID
          for the returned user ID.
        """
        DEVICE_ID_ARG_NAME = b"org.matrix.msc3202.device_id"

        app_service = self.store.get_app_service_by_token(
            self.get_access_token_from_request(request))
        if app_service is None:
            return None, None, None

        if app_service.ip_range_whitelist:
            ip_address = IPAddress(request.getClientAddress().host)
            if ip_address not in app_service.ip_range_whitelist:
                return None, None, None

        # This will always be set by the time Twisted calls us.
        assert request.args is not None

        if b"user_id" in request.args:
            effective_user_id = request.args[b"user_id"][0].decode("utf8")
            await self.validate_appservice_can_control_user_id(
                app_service, effective_user_id)
        else:
            effective_user_id = app_service.sender

        effective_device_id: Optional[str] = None

        if (self.hs.config.experimental.msc3202_device_masquerading_enabled
                and DEVICE_ID_ARG_NAME in request.args):
            effective_device_id = request.args[DEVICE_ID_ARG_NAME][0].decode(
                "utf8")
            # We only just set this so it can't be None!
            assert effective_device_id is not None
            device_opt = await self.store.get_device(effective_user_id,
                                                     effective_device_id)
            if device_opt is None:
                # For now, use 400 M_EXCLUSIVE if the device doesn't exist.
                # This is an open thread of discussion on MSC3202 as of 2021-12-09.
                raise AuthError(
                    400,
                    f"Application service trying to use a device that doesn't exist ('{effective_device_id}' for {effective_user_id})",
                    Codes.EXCLUSIVE,
                )

        return effective_user_id, effective_device_id, app_service
Exemple #4
0
    async def on_POST(self, request: Request, stagetype: str) -> None:

        session = parse_string(request, "session")
        if not session:
            raise SynapseError(400, "No session supplied")

        if stagetype == LoginType.RECAPTCHA:
            response = parse_string(request, "g-recaptcha-response")

            if not response:
                raise SynapseError(400, "No captcha response supplied")

            authdict = {"response": response, "session": session}

            try:
                await self.auth_handler.add_oob_auth(
                    LoginType.RECAPTCHA, authdict,
                    request.getClientAddress().host)
            except LoginError as e:
                # Authentication failed, let user try again
                html = self.recaptcha_template.render(
                    session=session,
                    myurl="%s/v3/auth/%s/fallback/web" %
                    (CLIENT_API_PREFIX, LoginType.RECAPTCHA),
                    sitekey=self.hs.config.captcha.recaptcha_public_key,
                    error=e.msg,
                )
            else:
                # No LoginError was raised, so authentication was successful
                html = self.success_template.render()

        elif stagetype == LoginType.TERMS:
            authdict = {"session": session}

            try:
                await self.auth_handler.add_oob_auth(
                    LoginType.TERMS, authdict,
                    request.getClientAddress().host)
            except LoginError as e:
                # Authentication failed, let user try again
                html = self.terms_template.render(
                    session=session,
                    terms_url="%s_matrix/consent?v=%s" % (
                        self.hs.config.server.public_baseurl,
                        self.hs.config.consent.user_consent_version,
                    ),
                    myurl="%s/v3/auth/%s/fallback/web" %
                    (CLIENT_API_PREFIX, LoginType.TERMS),
                    error=e.msg,
                )
            else:
                # No LoginError was raised, so authentication was successful
                html = self.success_template.render()

        elif stagetype == LoginType.SSO:
            # The SSO fallback workflow should not post here,
            raise SynapseError(
                404, "Fallback SSO auth does not support POST requests.")

        elif stagetype == LoginType.REGISTRATION_TOKEN:
            token = parse_string(request, "token", required=True)
            authdict = {"session": session, "token": token}

            try:
                await self.auth_handler.add_oob_auth(
                    LoginType.REGISTRATION_TOKEN,
                    authdict,
                    request.getClientAddress().host,
                )
            except LoginError as e:
                html = self.registration_token_template.render(
                    session=session,
                    myurl=
                    f"{CLIENT_API_PREFIX}/r0/auth/{LoginType.REGISTRATION_TOKEN}/fallback/web",
                    error=e.msg,
                )
            else:
                html = self.success_template.render()

        else:
            raise SynapseError(404, "Unknown auth stage type")

        # Render the HTML and return.
        respond_with_html(request, 200, html)
        return None
Exemple #5
0
    async def register_sso_user(self, request: Request,
                                session_id: str) -> None:
        """Called once we have all the info we need to register a new user.

        Does so and serves an HTTP response

        Args:
            request: HTTP request
            session_id: ID of the username mapping session, extracted from a cookie
        """
        try:
            session = self.get_mapping_session(session_id)
        except SynapseError as e:
            self.render_error(request, "bad_session", e.msg, code=e.code)
            return

        logger.info(
            "[session %s] Registering localpart %s",
            session_id,
            session.chosen_localpart,
        )

        attributes = UserAttributes(
            localpart=session.chosen_localpart,
            emails=session.emails_to_use,
        )

        if session.use_display_name:
            attributes.display_name = session.display_name

        # the following will raise a 400 error if the username has been taken in the
        # meantime.
        user_id = await self._register_mapped_user(
            attributes,
            session.auth_provider_id,
            session.remote_user_id,
            get_request_user_agent(request),
            request.getClientAddress().host,
        )

        logger.info(
            "[session %s] Registered userid %s with attributes %s",
            session_id,
            user_id,
            attributes,
        )

        # delete the mapping session and the cookie
        del self._username_mapping_sessions[session_id]

        # delete the cookie
        request.addCookie(
            USERNAME_MAPPING_SESSION_COOKIE_NAME,
            b"",
            expires=b"Thu, 01 Jan 1970 00:00:00 GMT",
            path=b"/",
        )

        auth_result = {}
        if session.terms_accepted_version:
            # TODO: make this less awful.
            auth_result[LoginType.TERMS] = True

        await self._registration_handler.post_registration_actions(
            user_id, auth_result, access_token=None)

        await self._auth_handler.complete_sso_login(
            user_id,
            session.auth_provider_id,
            request,
            session.client_redirect_url,
            session.extra_login_attributes,
            new_user=True,
        )