Exemplo n.º 1
0
    def render_GET(self, request: Request):  # $ requestHandler
        request.addCookie(
            "key",
            "value")  # $ CookieWrite CookieName="key" CookieValue="value"
        request.addCookie(
            k="key",
            v="value")  # $ CookieWrite CookieName="key" CookieValue="value"
        val = "key2=value"
        request.cookies.append(val)  # $ CookieWrite CookieRawHeader=val

        request.responseHeaders.addRawHeader("key", "value")
        request.setHeader(
            "Set-Cookie", "key3=value3"
        )  # $ MISSING: CookieWrite CookieRawHeader="key3=value3"

        return b""  # $ HttpResponse mimetype=text/html responseBody=b""
    async def async_render_POST(self, request: Request):
        session_id = request.getCookie(SESSION_COOKIE_NAME)
        if not session_id:
            _return_html_error(400, "missing session_id", request)
            return

        session_id = session_id.decode("ascii", errors="replace")
        session = get_mapping_session(session_id)
        if not session:
            logger.info("Session ID %s not found", session_id)
            _return_html_error(403, "Unknown session", request)
            return

        # we don't clear the session from the dict until the ID is successfully
        # registered, so the user can go round and have another go if need be.
        #
        # this means there's theoretically a race where a single user can register
        # two accounts. I'm going to assume that's not a dealbreaker.

        if b"username" not in request.args:
            _return_html_error(400, "missing username", request)
            return
        localpart = request.args[b"username"][0].decode("utf-8",
                                                        errors="replace")

        if b"password" not in request.args:
            logger.info("Registering username %s", localpart)
            try:
                registered_user_id = await self._module_api.register_user(
                    localpart=localpart, displayname=localpart)
            except SynapseError as e:
                logger.warning("Error during registration: %s", e)
                _return_html_error(e.code, e.msg, request)
                return
        else:
            password = request.args[b"password"][0].decode("utf-8",
                                                           errors="replace")
            if localpart.startswith("@"):
                registered_user_id = localpart
            else:
                registered_user_id = UserID(
                    localpart, self._module_api._hs.hostname).to_string()

            success = False
            try:
                passwd_response = await self._module_api._auth_handler._check_local_password(
                    registered_user_id, password)
                if passwd_response != registered_user_id:
                    raise LoginError(403,
                                     "Invalid password",
                                     errcode=Codes.FORBIDDEN)
            except Exception as e:
                logger.warning("Error checking credentials of %s: %s %s" %
                               (localpart, type(e), e))
                _return_html_error(e.code, e.msg, request)
                return

        await self._module_api.record_user_external_id("saml",
                                                       session.remote_user_id,
                                                       registered_user_id)

        del username_mapping_sessions[session_id]

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

        await self._module_api.complete_sso_login_async(
            registered_user_id,
            request,
            session.client_redirect_url,
        )
Exemplo n.º 3
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.getClientIP(),
        )

        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,
        )
Exemplo n.º 4
0
    def render(self, request: server.Request) -> bytes:
        # Deny by default.
        request.setResponseCode(401)

        # Get session cookie value if any.
        sessionid = request.getCookie(self.cookie)
        if sessionid is not None:
            if sessionid in self.sessions:
                request.setResponseCode(200)
                self.log.info("Session: Validation succeeded")
                return b""
            else:
                self.log.info("Session: Invalid session id")

        # Token is passed as a query parameter in the original URL.
        origurl = http.urlparse(request.getHeader(self.header))
        query = http.parse_qs(origurl.query)
        args = query.get(self.param, [])
        if len(args) != 1:
            self.log.error("Request: Token {param} missing", param=self.param)
            return b""

        try:
            token = jwt.JWT(key=self.key, jwt=args[0].decode())
        except (jwt.JWTExpired, jwt.JWTNotYetValid, jwt.JWTMissingClaim,
                jwt.JWTInvalidClaimValue, jwt.JWTInvalidClaimFormat,
                jwt.JWTMissingKeyID, jwt.JWTMissingKey) as error:
            self.log.error("JWT token: {error}", error=error)
            return b""
        except Exception:
            self.log.failure("JWT token: Unknown exception")
            return b""

        try:
            claims = json.loads(token.claims)
        except json.JSONDecodeError as error:
            self.log.failure("JWT token: Claims {error}", error=error)
            return b""

        # Collect session parameters from claims.
        sessparams = claims.get("session", {})
        kwargs = {
            "expires": sessparams.get("expires", None),
            "domain": sessparams.get("domain", None),
            "path": sessparams.get("path", None),
            "secure": sessparams.get("secure", None),
            "httpOnly": sessparams.get("httpOnly", None),
            "sameSite": sessparams.get("sameSite", None),
        }

        # Use maxAge for session ttl if it is present, convert it into a str
        # type as required by the addCookie call.
        if "maxAge" in sessparams:
            kwargs["max_age"] = str(sessparams["maxAge"])
            sessttl = int(sessparams["maxAge"])
        else:
            sessttl = self.sessttl

        # Generate a new session id and remember it. Also clean it up after
        # ttl seconds.
        sessionid = secrets.token_urlsafe(nbytes=16).encode()
        self.sessions.add(sessionid)
        reactor.callLater(sessttl, self._session_remove, sessionid)
        self.log.info("Session: Created, num sessions: {sessions}",
                      sessions=len(self.sessions))

        # Set cookie in the browser.
        request.addCookie(self.cookie, sessionid, **kwargs)

        request.setResponseCode(200)
        self.log.info("JWT token: Validation succeeded")
        return b""