Exemplo n.º 1
0
 def getClientIP(self):
     "If there's an X-Forwarded-For, treat that as the client IP."
     forwarded_for = self.getHeader('x-forwarded-for')
     if forwarded_for is not None:
         return forwarded_for
     else:
         return Request.getClientIP(self)
Exemplo n.º 2
0
 def getClientIP(self):
     "If there's an X-Forwarded-For, treat that as the client IP."
     forwarded_for = self.getHeader('x-forwarded-for')
     if forwarded_for is not None:
         return forwarded_for
     else:
         return Request.getClientIP(self)
Exemplo n.º 3
0
    async def _get_appservice_user_id(
        self, request: Request
    ) -> Tuple[Optional[str], Optional[ApplicationService]]:
        app_service = self.store.get_app_service_by_token(
            self.get_access_token_from_request(request))
        if app_service is None:
            return None, None

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

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

        if b"user_id" not in request.args:
            return app_service.sender, app_service

        user_id = request.args[b"user_id"][0].decode("utf8")
        await self.validate_appservice_can_control_user_id(
            app_service, user_id)

        if app_service.sender == user_id:
            return app_service.sender, app_service

        return user_id, app_service
Exemplo n.º 4
0
    async def _get_appservice_user_id(
        self, request: Request
    ) -> Tuple[Optional[str], Optional[ApplicationService]]:
        app_service = self.store.get_app_service_by_token(
            self.get_access_token_from_request(request))
        if app_service is None:
            return None, None

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

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

        if b"user_id" not in request.args:
            return app_service.sender, app_service

        user_id = request.args[b"user_id"][0].decode("utf8")
        if app_service.sender == user_id:
            return app_service.sender, app_service

        if not app_service.is_interested_in_user(user_id):
            raise AuthError(
                403, "Application service cannot masquerade as this user.")
        if not (await self.store.get_user_by_id(user_id)):
            raise AuthError(
                403, "Application service has not registered this user")
        return user_id, app_service
Exemplo n.º 5
0
    async def on_GET(self, request: Request) -> Tuple[int, JsonDict]:
        await self.ratelimiter.ratelimit(None, (request.getClientIP(), ))

        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}
Exemplo n.º 6
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)

        ip = request.getClientIP()
        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}
Exemplo n.º 7
0
    def getClientIP(self, **kwargs):
        """Override base getClientIP to be X-Real-IP aware.
        
        Arguments:
        
            honor_xrealip (bool)(optional) - (If present, overrides the default
                                              for honor_xrealip specified in the config file.)
                                             
                                             Whether or not to prefer the value of
                                             the X-Real-IP header if present.
        """
        if kwargs.has_key("honor_xrealip"):
            honor_xrealip = kwargs["honor_xrealip"]
        else:
            honor_xrealip = self.site.honor_xrealip

        if honor_xrealip and self.getHeader("X-Real-IP"):
            return self.getHeader("X-Real-IP")

        return Request.getClientIP(self)
Exemplo n.º 8
0
 def getClientIP(self, **kwargs):
     """Override base getClientIP to be X-Real-IP aware.
     
     Arguments:
     
         honor_xrealip (bool)(optional) - (If present, overrides the default
                                           for honor_xrealip specified in the config file.)
                                          
                                          Whether or not to prefer the value of
                                          the X-Real-IP header if present.
     """
     if kwargs.has_key("honor_xrealip"):
         honor_xrealip = kwargs["honor_xrealip"]
     else:
         honor_xrealip = self.site.honor_xrealip
     
     if honor_xrealip and self.getHeader("X-Real-IP"):
         return self.getHeader("X-Real-IP")
     
     return Request.getClientIP(self)
Exemplo n.º 9
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,
        )
	def getClientIP(self):
		"""Get the clients IP address. Evaluates allowed proxys (from localhost)"""
		ip = Request.getClientIP(self)
		if ip in ('::1', '127.0.0.1'):
			return self.requestHeaders.getRawHeaders('X-Forwarded-For', [ip])[-1]
		return ip
Exemplo n.º 11
0
 def getClientIP(self):
     if self.requestHeaders.hasHeader('x-forwarded-for'):
         return self.requestHeaders.getRawHeaders(b"x-forwarded-for")[0].split(b",")[0].strip()
     if self.requestHeaders.hasHeader('x-real-ip'):
         return self.requestHeaders.getRawHeaders(b"x-real-ip")[0].split(b",")[0].strip()
     return Request.getClientIP(self)
Exemplo n.º 12
0
 def getClientIP(self):
     if self.requestHeaders.hasHeader('x-forwarded-for'):
         return self.requestHeaders.getRawHeaders(b"x-forwarded-for")[0].split(b",")[0].strip()
     if self.requestHeaders.hasHeader('x-real-ip'):
         return self.requestHeaders.getRawHeaders(b"x-real-ip")[0].split(b",")[0].strip()
     return Request.getClientIP(self)
Exemplo n.º 13
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.getClientIP())
            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
Exemplo n.º 14
0
    async def get_user_by_req(
        self,
        request: Request,
        allow_guest: bool = False,
        rights: str = "access",
        allow_expired: bool = False,
    ) -> synapse.types.Requester:
        """Get a registered user's ID.

        Args:
            request: An HTTP request with an access_token query parameter.
            allow_guest: If False, will raise an AuthError if the user making the
                request is a guest.
            rights: The operation being performed; the access token must allow this
            allow_expired: If True, allow the request through even if the account
                is expired, or session token lifetime has ended. Note that
                /login will deliver access tokens regardless of expiration.

        Returns:
            Resolves to the requester
        Raises:
            InvalidClientCredentialsError if no user by that token exists or the token
                is invalid.
            AuthError if access is denied for the user in the access token
        """
        try:
            ip_addr = request.getClientIP()
            user_agent = get_request_user_agent(request)

            access_token = self.get_access_token_from_request(request)

            user_id, app_service = await self._get_appservice_user_id(request)
            if user_id:
                if ip_addr and self._track_appservice_user_ips:
                    await self.store.insert_client_ip(
                        user_id=user_id,
                        access_token=access_token,
                        ip=ip_addr,
                        user_agent=user_agent,
                        device_id="dummy-device",  # stubbed
                    )

                requester = synapse.types.create_requester(
                    user_id, app_service=app_service)

                request.requester = user_id
                opentracing.set_tag("authenticated_entity", user_id)
                opentracing.set_tag("user_id", user_id)
                opentracing.set_tag("appservice_id", app_service.id)

                return requester

            user_info = await self.get_user_by_access_token(
                access_token, rights, allow_expired=allow_expired)
            token_id = user_info.token_id
            is_guest = user_info.is_guest
            shadow_banned = user_info.shadow_banned

            # Deny the request if the user account has expired.
            if self._account_validity.enabled and not allow_expired:
                if await self.store.is_account_expired(user_info.user_id,
                                                       self.clock.time_msec()):
                    raise AuthError(403,
                                    "User account has expired",
                                    errcode=Codes.EXPIRED_ACCOUNT)

            device_id = user_info.device_id

            if access_token and ip_addr:
                await self.store.insert_client_ip(
                    user_id=user_info.token_owner,
                    access_token=access_token,
                    ip=ip_addr,
                    user_agent=user_agent,
                    device_id=device_id,
                )

            if is_guest and not allow_guest:
                raise AuthError(
                    403,
                    "Guest access not allowed",
                    errcode=Codes.GUEST_ACCESS_FORBIDDEN,
                )

            requester = synapse.types.create_requester(
                user_info.user_id,
                token_id,
                is_guest,
                shadow_banned,
                device_id,
                app_service=app_service,
                authenticated_entity=user_info.token_owner,
            )

            request.requester = requester
            opentracing.set_tag("authenticated_entity", user_info.token_owner)
            opentracing.set_tag("user_id", user_info.user_id)
            if device_id:
                opentracing.set_tag("device_id", device_id)

            return requester
        except KeyError:
            raise MissingClientTokenError()
Exemplo n.º 15
0
 def getClientIP(self):
     real_ip = self.getHeader("X-Real-IP")
     if real_ip:
         return real_ip
     else:
         Request.getClientIP(self)
Exemplo n.º 16
0
 def getClientIP(self):
     real_ip = self.getHeader("X-Real-IP")
     if real_ip:
         return real_ip
     else:
         Request.getClientIP(self)
Exemplo n.º 17
0
def fix_twisted_web_http_Request():
    """Add ipv6 support to Request.getClientIP()

       Specifically, IPv6 IP addresses need to be wrapped in [], and return
       address.IPv6Address when needed.

       See https://bugs.launchpad.net/ubuntu/+source/twisted/+bug/1604608
    """
    from netaddr import IPAddress
    from netaddr.core import AddrFormatError
    from twisted.internet import address
    from twisted.python.compat import (
        intToBytes,
        networkString,
    )
    import twisted.web.http
    from twisted.web.server import Request
    from twisted.web.test.requesthelper import DummyChannel

    def new_getClientIP(self):
        from twisted.internet import address
        # upstream doesn't check for address.IPv6Address
        if isinstance(self.client, address.IPv4Address):
            return self.client.host
        elif isinstance(self.client, address.IPv6Address):
            return self.client.host
        else:
            return None

    def new_getRequestHostname(self):
        # Unlike upstream, support/require IPv6 addresses to be
        # [ip:v6:add:ress]:port, with :port being optional.
        # IPv6 IP addresses are wrapped in [], to disambigate port numbers.
        host = self.getHeader(b'host')
        if host:
            if host.startswith(b'[') and b']' in host:
                if host.find(b']') < host.rfind(b':'):
                    # The format is: [ip:add:ress]:port.
                    return host[:host.rfind(b':')]
                else:
                    # no :port after [...]
                    return host
            # No brackets, so it must be host:port or IPv4:port.
            return host.split(b':', 1)[0]
        host = self.getHost().host
        try:
            if isinstance(host, str):
                ip = IPAddress(host)
            else:
                ip = IPAddress(host.decode("idna"))
        except AddrFormatError:
            # If we could not convert the hostname to an IPAddress, assume that
            # it is a hostname.
            return networkString(host)
        if ip.version == 4:
            return networkString(host)
        else:
            return networkString('[' + host + ']')

    def new_setHost(self, host, port, ssl=0):
        try:
            ip = IPAddress(host.decode("idna"))
        except AddrFormatError:
            ip = None  # `host` is a host or domain name.
        self._forceSSL = ssl  # set first so isSecure will work
        if self.isSecure():
            default = 443
        else:
            default = 80
        if ip is None:
            hostHeader = host
        elif ip.version == 4:
            hostHeader = host
        else:
            hostHeader = b"[" + host + b"]"
        if port != default:
            hostHeader += b":" + intToBytes(port)
        self.requestHeaders.setRawHeaders(b"host", [hostHeader])
        if ip is None:
            # Pretend that a host or domain name is an IPv4 address.
            self.host = address.IPv4Address("TCP", host, port)
        elif ip.version == 4:
            self.host = address.IPv4Address("TCP", host, port)
        else:
            self.host = address.IPv6Address("TCP", host, port)

    request = Request(DummyChannel(), False)
    request.client = address.IPv6Address('TCP', 'fe80::1', '80')
    request.setHost(b"fe80::1", 1234)
    if request.getClientIP() is None:
        # Buggy code returns None for IPv6 addresses.
        twisted.web.http.Request.getClientIP = new_getClientIP
    if isinstance(request.host, address.IPv4Address):
        # Buggy code calls fe80::1 an IPv4Address.
        twisted.web.http.Request.setHost = new_setHost
    if request.getRequestHostname() == b'fe80':
        # The fe80::1 test address above was incorrectly interpreted as
        # address='fe80', port = ':1', because it does host.split(':', 1)[0].
        twisted.web.http.Request.getRequestHostname = new_getRequestHostname
Exemplo n.º 18
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.getClientIP())
            except LoginError as e:
                # Authentication failed, let user try again
                html = self.recaptcha_template.render(
                    session=session,
                    myurl="%s/r0/auth/%s/fallback/web" %
                    (CLIENT_API_PREFIX, LoginType.RECAPTCHA),
                    sitekey=self.hs.config.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.getClientIP())
            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.public_baseurl,
                        self.hs.config.user_consent_version,
                    ),
                    myurl="%s/r0/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.getClientIP())
            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