Example #1
0
class AuthTestCase(unittest.TestCase):

    @defer.inlineCallbacks
    def setUp(self):
        self.state_handler = Mock()
        self.store = Mock()

        self.hs = yield setup_test_homeserver(handlers=None)
        self.hs.get_datastore = Mock(return_value=self.store)
        self.auth = Auth(self.hs)

        self.test_user = "******"
        self.test_token = "_test_token_"

    @defer.inlineCallbacks
    def test_get_user_by_req_user_valid_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        user_info = {
            "name": self.test_user,
            "token_id": "ditto",
            "device_id": "device",
        }
        self.store.get_user_by_access_token = Mock(return_value=user_info)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        requester = yield self.auth.get_user_by_req(request)
        self.assertEquals(requester.user.to_string(), self.test_user)

    def test_get_user_by_req_user_bad_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    def test_get_user_by_req_user_missing_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        user_info = {
            "name": self.test_user,
            "token_id": "ditto",
        }
        self.store.get_user_by_access_token = Mock(return_value=user_info)

        request = Mock(args={})
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    @defer.inlineCallbacks
    def test_get_user_by_req_appservice_valid_token(self):
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        requester = yield self.auth.get_user_by_req(request)
        self.assertEquals(requester.user.to_string(), self.test_user)

    def test_get_user_by_req_appservice_bad_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    def test_get_user_by_req_appservice_missing_token(self):
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    @defer.inlineCallbacks
    def test_get_user_by_req_appservice_valid_token_valid_user_id(self):
        masquerading_user_id = "@doppelganger:matrix.org"
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        app_service.is_interested_in_user = Mock(return_value=True)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.args["user_id"] = [masquerading_user_id]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        requester = yield self.auth.get_user_by_req(request)
        self.assertEquals(requester.user.to_string(), masquerading_user_id)

    def test_get_user_by_req_appservice_valid_token_bad_user_id(self):
        masquerading_user_id = "@doppelganger:matrix.org"
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        app_service.is_interested_in_user = Mock(return_value=False)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.args["user_id"] = [masquerading_user_id]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={
                "name": "@baldrick:matrix.org",
                "device_id": "device",
            }
        )

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.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 = yield self.auth.get_user_from_macaroon(macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)

        # TODO: device_id should come from the macaroon, but currently comes
        # from the db.
        self.assertEqual(user_info["device_id"], "device")

    @defer.inlineCallbacks
    def test_get_guest_user_from_macaroon(self):
        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.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,))
        macaroon.add_first_party_caveat("guest = true")
        serialized = macaroon.serialize()

        user_info = yield self.auth.get_user_from_macaroon(serialized)
        user = user_info["user"]
        is_guest = user_info["is_guest"]
        self.assertEqual(UserID.from_string(user_id), user)
        self.assertTrue(is_guest)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_user_db_mismatch(self):
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@percy:matrix.org"}
        )

        user = "******"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.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,))
        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("User mismatch", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_missing_caveat(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")

        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("No user caveat", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_wrong_key(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        user = "******"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key + "wrong")
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user,))

        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_unknown_caveat(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        user = "******"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.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,))
        macaroon.add_first_party_caveat("cunning > fox")

        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_expired(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        user = "******"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.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,))
        macaroon.add_first_party_caveat("time < -2000")  # ms

        self.hs.clock.now = 5000  # seconds
        self.hs.config.expire_access_token = True
        # yield self.auth.get_user_from_macaroon(macaroon.serialize())
        # TODO(daniel): Turn on the check that we validate expiration, when we
        # validate expiration (and remove the above line, which will start
        # throwing).
        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_with_valid_duration(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.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,))
        macaroon.add_first_party_caveat("time < 900000000")  # ms

        self.hs.clock.now = 5000  # seconds
        self.hs.config.expire_access_token = True

        user_info = yield self.auth.get_user_from_macaroon(macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)
Example #2
0
class AuthTestCase(unittest.TestCase):
    @defer.inlineCallbacks
    def setUp(self):
        self.state_handler = Mock()
        self.store = Mock()

        self.hs = yield setup_test_homeserver(handlers=None)
        self.hs.get_datastore = Mock(return_value=self.store)
        self.auth = Auth(self.hs)

        self.test_user = "******"
        self.test_token = "_test_token_"

    @defer.inlineCallbacks
    def test_get_user_by_req_user_valid_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        user_info = {
            "name": self.test_user,
            "token_id": "ditto",
        }
        self.store.get_user_by_access_token = Mock(return_value=user_info)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        requester = yield self.auth.get_user_by_req(request)
        self.assertEquals(requester.user.to_string(), self.test_user)

    def test_get_user_by_req_user_bad_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    def test_get_user_by_req_user_missing_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        user_info = {
            "name": self.test_user,
            "token_id": "ditto",
        }
        self.store.get_user_by_access_token = Mock(return_value=user_info)

        request = Mock(args={})
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    @defer.inlineCallbacks
    def test_get_user_by_req_appservice_valid_token(self):
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        requester = yield self.auth.get_user_by_req(request)
        self.assertEquals(requester.user.to_string(), self.test_user)

    def test_get_user_by_req_appservice_bad_token(self):
        self.store.get_app_service_by_token = Mock(return_value=None)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    def test_get_user_by_req_appservice_missing_token(self):
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    @defer.inlineCallbacks
    def test_get_user_by_req_appservice_valid_token_valid_user_id(self):
        masquerading_user_id = "@doppelganger:matrix.org"
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        app_service.is_interested_in_user = Mock(return_value=True)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.args["user_id"] = [masquerading_user_id]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        requester = yield self.auth.get_user_by_req(request)
        self.assertEquals(requester.user.to_string(), masquerading_user_id)

    def test_get_user_by_req_appservice_valid_token_bad_user_id(self):
        masquerading_user_id = "@doppelganger:matrix.org"
        app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
        app_service.is_interested_in_user = Mock(return_value=False)
        self.store.get_app_service_by_token = Mock(return_value=app_service)
        self.store.get_user_by_access_token = Mock(return_value=None)

        request = Mock(args={})
        request.args["access_token"] = [self.test_token]
        request.args["user_id"] = [masquerading_user_id]
        request.requestHeaders.getRawHeaders = Mock(return_value=[""])
        d = self.auth.get_user_by_req(request)
        self.failureResultOf(d, AuthError)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.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 = yield self.auth.get_user_from_macaroon(
            macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)

    @defer.inlineCallbacks
    def test_get_guest_user_from_macaroon(self):
        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.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, ))
        macaroon.add_first_party_caveat("guest = true")
        serialized = macaroon.serialize()

        user_info = yield self.auth.get_user_from_macaroon(serialized)
        user = user_info["user"]
        is_guest = user_info["is_guest"]
        self.assertEqual(UserID.from_string(user_id), user)
        self.assertTrue(is_guest)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_user_db_mismatch(self):
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@percy:matrix.org"})

        user = "******"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.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, ))
        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("User mismatch", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_missing_caveat(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")

        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("No user caveat", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_wrong_key(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        user = "******"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key + "wrong")
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user, ))

        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_unknown_caveat(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        user = "******"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.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, ))
        macaroon.add_first_party_caveat("cunning > fox")

        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)

    @defer.inlineCallbacks
    def test_get_user_from_macaroon_expired(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        user = "******"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.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, ))
        macaroon.add_first_party_caveat("time < 1")  # ms

        self.hs.clock.now = 5000  # seconds
        self.hs.config.expire_access_token = True
        # yield self.auth.get_user_from_macaroon(macaroon.serialize())
        # TODO(daniel): Turn on the check that we validate expiration, when we
        # validate expiration (and remove the above line, which will start
        # throwing).
        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)