Beispiel #1
0
 async def get_user(tok):
     if token != tok:
         return None
     return TokenLookupResult(
         user_id=USER_ID,
         is_guest=False,
         token_id=1234,
         device_id="DEVICE",
     )
Beispiel #2
0
    def test_get_user_by_req_user_missing_token(self):
        user_info = TokenLookupResult(user_id=self.test_user, token_id=5)
        self.store.get_user_by_access_token = simple_async_mock(user_info)

        request = Mock(args={})
        request.requestHeaders.getRawHeaders = mock_getRawHeaders()
        f = self.get_failure(self.auth.get_user_by_req(request),
                             MissingClientTokenError).value
        self.assertEqual(f.code, 401)
        self.assertEqual(f.errcode, "M_MISSING_TOKEN")
Beispiel #3
0
 def get_user(tok):
     if token != tok:
         return defer.succeed(None)
     return defer.succeed(
         TokenLookupResult(
             user_id=USER_ID,
             is_guest=False,
             token_id=1234,
             device_id="DEVICE",
         ))
Beispiel #4
0
    def test_get_user_by_req_user_valid_token(self):
        user_info = TokenLookupResult(
            user_id=self.test_user, token_id=5, device_id="device"
        )
        self.store.get_user_by_access_token = simple_async_mock(user_info)

        request = Mock(args={})
        request.args[b"access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = mock_getRawHeaders()
        requester = self.get_success(self.auth.get_user_by_req(request))
        self.assertEquals(requester.user.to_string(), self.test_user)
Beispiel #5
0
    def test_get_user_by_req_user_missing_token(self):
        user_info = TokenLookupResult(user_id=self.test_user, token_id=5)
        self.store.get_user_by_access_token = Mock(
            return_value=defer.succeed(user_info))

        request = Mock(args={})
        request.requestHeaders.getRawHeaders = mock_getRawHeaders()
        d = defer.ensureDeferred(self.auth.get_user_by_req(request))
        f = self.failureResultOf(d, MissingClientTokenError).value
        self.assertEqual(f.code, 401)
        self.assertEqual(f.errcode, "M_MISSING_TOKEN")
Beispiel #6
0
    def test_get_user_by_req_user_valid_token(self):
        user_info = TokenLookupResult(user_id=self.test_user,
                                      token_id=5,
                                      device_id="device")
        self.store.get_user_by_access_token = Mock(
            return_value=defer.succeed(user_info))

        request = Mock(args={})
        request.args[b"access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = mock_getRawHeaders()
        requester = yield defer.ensureDeferred(
            self.auth.get_user_by_req(request))
        self.assertEquals(requester.user.to_string(), self.test_user)
Beispiel #7
0
 def test_get_user_by_req__puppeted_token__not_tracking_puppeted_mau(self):
     self.store.get_user_by_access_token = simple_async_mock(
         TokenLookupResult(
             user_id="@baldrick:matrix.org",
             device_id="device",
             token_owner="@admin:matrix.org",
         ))
     self.store.insert_client_ip = simple_async_mock(None)
     request = Mock(args={})
     request.getClientIP.return_value = "127.0.0.1"
     request.args[b"access_token"] = [self.test_token]
     request.requestHeaders.getRawHeaders = mock_getRawHeaders()
     self.get_success(self.auth.get_user_by_req(request))
     self.store.insert_client_ip.assert_called_once()
Beispiel #8
0
    def test_get_user_from_macaroon(self):
        self.store.get_user_by_access_token = simple_async_mock(
            TokenLookupResult(user_id="@baldrick:matrix.org",
                              device_id="device"))

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server.server_name,
            identifier="key",
            key=self.hs.config.key.macaroon_secret_key,
        )
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id, ))
        user_info = self.get_success(
            self.auth.get_user_by_access_token(macaroon.serialize()))
        self.assertEqual(user_id, user_info.user_id)

        # TODO: device_id should come from the macaroon, but currently comes
        # from the db.
        self.assertEqual(user_info.device_id, "device")
Beispiel #9
0
    async def get_user_by_access_token(
        self,
        token: str,
        rights: str = "access",
        allow_expired: bool = False,
    ) -> TokenLookupResult:
        """Validate access token and get user_id from it

        Args:
            token: The access token to get the user by
            rights: The operation being performed; the access token must
                allow this
            allow_expired: If False, raises an InvalidClientTokenError
                if the token is expired

        Raises:
            InvalidClientTokenError if a user by that token exists, but the token is
                expired
            InvalidClientCredentialsError if no user by that token exists or the token
                is invalid
        """

        if rights == "access":
            # first look in the database
            r = await self.store.get_user_by_access_token(token)
            if r:
                valid_until_ms = r.valid_until_ms
                if (not allow_expired and valid_until_ms is not None
                        and valid_until_ms < self.clock.time_msec()):
                    # there was a valid access token, but it has expired.
                    # soft-logout the user.
                    raise InvalidClientTokenError(
                        msg="Access token has expired", soft_logout=True)

                return r

        # otherwise it needs to be a valid macaroon
        try:
            user_id, guest = self._parse_and_validate_macaroon(token, rights)

            if rights == "access":
                if not guest:
                    # non-guest access tokens must be in the database
                    logger.warning("Unrecognised access token - not in store.")
                    raise InvalidClientTokenError()

                # Guest access tokens are not stored in the database (there can
                # only be one access token per guest, anyway).
                #
                # In order to prevent guest access tokens being used as regular
                # user access tokens (and hence getting around the invalidation
                # process), we look up the user id and check that it is indeed
                # a guest user.
                #
                # It would of course be much easier to store guest access
                # tokens in the database as well, but that would break existing
                # guest tokens.
                stored_user = await self.store.get_user_by_id(user_id)
                if not stored_user:
                    raise InvalidClientTokenError("Unknown user_id %s" %
                                                  user_id)
                if not stored_user["is_guest"]:
                    raise InvalidClientTokenError(
                        "Guest access token used for regular user")

                ret = TokenLookupResult(
                    user_id=user_id,
                    is_guest=True,
                    # all guests get the same device id
                    device_id=GUEST_DEVICE_ID,
                )
            elif rights == "delete_pusher":
                # We don't store these tokens in the database

                ret = TokenLookupResult(user_id=user_id, is_guest=False)
            else:
                raise RuntimeError("Unknown rights setting %s", rights)
            return ret
        except (
                _InvalidMacaroonException,
                pymacaroons.exceptions.MacaroonException,
                TypeError,
                ValueError,
        ) as e:
            logger.warning("Invalid macaroon in auth: %s %s", type(e), e)
            raise InvalidClientTokenError("Invalid macaroon passed.")
Beispiel #10
0
    async def get_user_by_access_token(
        self,
        token: str,
        allow_expired: bool = False,
    ) -> TokenLookupResult:
        """Validate access token and get user_id from it

        Args:
            token: The access token to get the user by
            allow_expired: If False, raises an InvalidClientTokenError
                if the token is expired

        Raises:
            InvalidClientTokenError if a user by that token exists, but the token is
                expired
            InvalidClientCredentialsError if no user by that token exists or the token
                is invalid
        """

        # First look in the database to see if the access token is present
        # as an opaque token.
        r = await self.store.get_user_by_access_token(token)
        if r:
            valid_until_ms = r.valid_until_ms
            if (not allow_expired and valid_until_ms is not None
                    and valid_until_ms < self.clock.time_msec()):
                # there was a valid access token, but it has expired.
                # soft-logout the user.
                raise InvalidClientTokenError(msg="Access token has expired",
                                              soft_logout=True)

            return r

        # If the token isn't found in the database, then it could still be a
        # macaroon for a guest, so we check that here.
        try:
            user_id = self._macaroon_generator.verify_guest_token(token)

            # Guest access tokens are not stored in the database (there can
            # only be one access token per guest, anyway).
            #
            # In order to prevent guest access tokens being used as regular
            # user access tokens (and hence getting around the invalidation
            # process), we look up the user id and check that it is indeed
            # a guest user.
            #
            # It would of course be much easier to store guest access
            # tokens in the database as well, but that would break existing
            # guest tokens.
            stored_user = await self.store.get_user_by_id(user_id)
            if not stored_user:
                raise InvalidClientTokenError("Unknown user_id %s" % user_id)
            if not stored_user["is_guest"]:
                raise InvalidClientTokenError(
                    "Guest access token used for regular user")

            return TokenLookupResult(
                user_id=user_id,
                is_guest=True,
                # all guests get the same device id
                device_id=GUEST_DEVICE_ID,
            )
        except (
                pymacaroons.exceptions.MacaroonException,
                TypeError,
                ValueError,
        ) as e:
            logger.warning(
                "Invalid access token in auth: %s %s.",
                type(e),
                e,
            )
            raise InvalidClientTokenError("Invalid access token passed.")