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}
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}
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
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
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, )