Esempio n. 1
0
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.authenticator = iMock(IAuthenticator)

        def authenticate_tenant(tenant_id):
            return succeed(('auth-token', 'catalog'))

        self.authenticator.authenticate_tenant.side_effect = authenticate_tenant
        self.auth_function = self.authenticator.authenticate_tenant

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, self.authenticator, 10)
Esempio n. 2
0
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.result = ('auth-token', 'catalog')
        self.resps = {1: self.result}

        class FakeAuthenticator(object):
            def authenticate_tenant(fself, tenant_id, log=None):
                r = self.resps[tenant_id]
                if isinstance(r, Deferred):
                    return r
                return fail(r) if isinstance(r, Exception) else succeed(r)

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, FakeAuthenticator(), 10)
Esempio n. 3
0
def makeService(config):
    """
    Set up the otter-api service.
    """
    set_config_data(dict(config))

    if not config_value('mock'):
        seed_endpoints = [
            clientFromString(reactor, str(host))
            for host in config_value('cassandra.seed_hosts')
        ]

        cassandra_cluster = LoggingCQLClient(
            RoundRobinCassandraCluster(seed_endpoints,
                                       config_value('cassandra.keyspace')),
            log.bind(system='otter.silverberg'))

        set_store(CassScalingGroupCollection(cassandra_cluster))

    bobby_url = config_value('bobby_url')
    if bobby_url is not None:
        set_bobby(BobbyClient(bobby_url))

    cache_ttl = config_value('identity.cache_ttl')

    if cache_ttl is None:
        # FIXME: Pick an arbitrary cache ttl value based on absolutely no
        # science.
        cache_ttl = 300

    authenticator = CachingAuthenticator(
        reactor,
        ImpersonatingAuthenticator(config_value('identity.username'),
                                   config_value('identity.password'),
                                   config_value('identity.url'),
                                   config_value('identity.admin_url')),
        cache_ttl)

    supervisor = Supervisor(authenticator.authenticate_tenant, coiterate)

    set_supervisor(supervisor)

    s = MultiService()

    site = Site(root)
    site.displayTracebacks = False

    api_service = service(str(config_value('port')), site)
    api_service.setServiceParent(s)

    if config_value('scheduler') and not config_value('mock'):
        scheduler_service = SchedulerService(
            int(config_value('scheduler.batchsize')),
            int(config_value('scheduler.interval')), cassandra_cluster)
        scheduler_service.setServiceParent(s)

    return s
Esempio n. 4
0
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.authenticator = iMock(IAuthenticator)

        def authenticate_tenant(tenant_id, log=None):
            return succeed(('auth-token', 'catalog'))

        self.authenticator.authenticate_tenant.side_effect = authenticate_tenant
        self.auth_function = self.authenticator.authenticate_tenant

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, self.authenticator, 10)
Esempio n. 5
0
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.result = ('auth-token', 'catalog')
        self.resps = {1: self.result}

        class FakeAuthenticator(object):
            def authenticate_tenant(fself, tenant_id, log=None):
                r = self.resps[tenant_id]
                if isinstance(r, Deferred):
                    return r
                return fail(r) if isinstance(r, Exception) else succeed(r)

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, FakeAuthenticator(), 10)
Esempio n. 6
0
class CachingAuthenticatorTests(TestCase):
    """
    Test the in memory cache of authentication tokens.
    """
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.authenticator = iMock(IAuthenticator)

        def authenticate_tenant(tenant_id, log=None):
            return succeed(('auth-token', 'catalog'))

        self.authenticator.authenticate_tenant.side_effect = authenticate_tenant
        self.auth_function = self.authenticator.authenticate_tenant

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, self.authenticator, 10)

    def test_verifyObject(self):
        """
        CachingAuthenticator provides the IAuthenticator interface.
        """
        verifyObject(IAuthenticator, self.ca)

    def test_calls_auth_function_with_empty_cache(self):
        """
        authenticate_tenant with no items in the cache returns the result
        of the auth_function passed to the authenticator.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1, mock.Mock()))
        self.assertEqual(result, ('auth-token', 'catalog'))
        self.auth_function.assert_called_once_with(
            1, log=matches(IsInstance(mock.Mock)))

    def test_returns_token_from_cache(self):
        """
        authenticate_tenant returns tokens from the cache without calling
        auth_function again for subsequent calls.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))

        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))

        self.auth_function.assert_called_once_with(
            1, log=matches(IsInstance(default_log.__class__)))

    def test_cache_expires(self):
        """
        authenticate_tenant will call auth_function again after the ttl has
        lapsed.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))

        self.auth_function.assert_called_once_with(
            1, log=matches(IsInstance(default_log.__class__)))

        self.clock.advance(20)

        self.auth_function.side_effect = lambda _, log: succeed(('auth-token2', 'catalog2'))

        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token2', 'catalog2'))

        self.auth_function.assert_has_calls([
            mock.call(1, log=matches(IsInstance(default_log.__class__))),
            mock.call(1, log=matches(IsInstance(default_log.__class__)))])

    def test_serialize_auth_requests(self):
        """
        authenticate_tenant will serialize requests to authenticate the same
        tenant to prevent multiple outstanding auth requests when no
        value is cached.
        """
        auth_d = Deferred()
        self.auth_function.side_effect = lambda _, log: auth_d

        d1 = self.ca.authenticate_tenant(1)
        d2 = self.ca.authenticate_tenant(1)

        self.assertNotIdentical(d1, d2)

        self.auth_function.assert_called_once_with(
            1, log=matches(IsInstance(default_log.__class__)))

        auth_d.callback(('auth-token2', 'catalog2'))

        r1 = self.successResultOf(d1)
        r2 = self.successResultOf(d2)

        self.assertEqual(r1, r2)
        self.assertEqual(r1, ('auth-token2', 'catalog2'))

    def test_cached_value_per_tenant(self):
        """
        authenticate_tenant calls auth_function for each distinct tenant_id
        not found in the cache.
        """
        r1 = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(r1, ('auth-token', 'catalog'))

        self.auth_function.side_effect = (
            lambda _, log: succeed(('auth-token2', 'catalog2')))

        r2 = self.successResultOf(self.ca.authenticate_tenant(2))

        self.assertEqual(r2, ('auth-token2', 'catalog2'))

    def test_auth_failure_propagated_to_waiters(self):
        """
        authenticate_tenant propagates auth failures to all waiters
        """
        auth_d = Deferred()
        self.auth_function.side_effect = lambda _, log: auth_d

        d1 = self.ca.authenticate_tenant(1)
        d2 = self.ca.authenticate_tenant(1)

        self.assertNotIdentical(d1, d2)

        auth_d.errback(APIError(500, '500'))

        self.failureResultOf(d1)

        f2 = self.failureResultOf(d2)
        self.assertTrue(f2.check(APIError))

    def test_auth_failure_propagated_to_caller(self):
        """
        authenticate_tenant propagates auth failures to the caller.
        """
        self.auth_function.side_effect = lambda _, log: fail(APIError(500, '500'))

        d = self.ca.authenticate_tenant(1)
        failure = self.failureResultOf(d)
        self.assertTrue(failure.check(APIError))
Esempio n. 7
0
class CachingAuthenticatorTests(SynchronousTestCase):
    """
    Test the in memory cache of authentication tokens.
    """
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.result = ('auth-token', 'catalog')
        self.resps = {1: self.result}

        class FakeAuthenticator(object):
            def authenticate_tenant(fself, tenant_id, log=None):
                r = self.resps[tenant_id]
                if isinstance(r, Deferred):
                    return r
                return fail(r) if isinstance(r, Exception) else succeed(r)

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, FakeAuthenticator(), 10)

    def test_verifyObject(self):
        """
        CachingAuthenticator provides the IAuthenticator interface.
        """
        verifyObject(IAuthenticator, self.ca)

    def test_calls_auth_function_with_empty_cache(self):
        """
        authenticate_tenant with no items in the cache returns the result
        of the auth_function passed to the authenticator.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1, mock.Mock()))
        self.assertEqual(result, self.result)

    def test_returns_token_from_cache(self):
        """
        authenticate_tenant returns tokens from the cache without calling
        auth_function again for subsequent calls.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, self.result)

        # Remove result and it still succeeds since it is from cache
        del self.resps[1]
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, self.result)

    def test_cache_expires(self):
        """
        authenticate_tenant will call auth_function again after the ttl has
        lapsed.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, self.result)

        self.clock.advance(20)

        self.resps[1] = ('auth-token2', 'catalog2')

        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token2', 'catalog2'))

    def test_serialize_auth_requests(self):
        """
        authenticate_tenant will serialize requests to authenticate the same
        tenant to prevent multiple outstanding auth requests when no
        value is cached.
        """
        auth_d = Deferred()
        self.resps[1] = auth_d

        d1 = self.ca.authenticate_tenant(1)
        d2 = self.ca.authenticate_tenant(1)

        self.assertIs(auth_d, d1)
        self.assertNotIdentical(d1, d2)

        del self.resps[1]
        auth_d.callback(('auth-token2', 'catalog2'))

        r1 = self.successResultOf(d1)
        r2 = self.successResultOf(d2)

        self.assertEqual(r1, r2)
        self.assertEqual(r1, ('auth-token2', 'catalog2'))

    def test_cached_value_per_tenant(self):
        """
        authenticate_tenant calls auth_function for each distinct tenant_id
        not found in the cache.
        """
        r1 = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(r1, self.result)

        del self.resps[1]
        self.resps[2] = ('auth-token2', 'catalog2')

        r2 = self.successResultOf(self.ca.authenticate_tenant(2))

        self.assertEqual(r2, ('auth-token2', 'catalog2'))

    def test_auth_failure_propagated_to_waiters(self):
        """
        authenticate_tenant propagates auth failures to all waiters
        """
        auth_d = Deferred()
        self.resps[1] = auth_d

        d1 = self.ca.authenticate_tenant(1)
        del self.resps[1]
        d2 = self.ca.authenticate_tenant(1)

        self.assertNotIdentical(d1, d2)

        auth_d.errback(APIError(500, '500'))

        self.failureResultOf(d1, APIError)

        self.failureResultOf(d2, APIError)

    def test_auth_failure_propagated_to_caller(self):
        """
        authenticate_tenant propagates auth failures to the caller.
        """
        self.resps[1] = APIError(500, '500')

        d = self.ca.authenticate_tenant(1)
        self.failureResultOf(d, APIError)

    def test_invalidate(self):
        """
        The invalidate method causes the next authenticate_tenant call to
        re-authenticate.
        """
        d = self.ca.authenticate_tenant(1)
        self.assertEqual(self.successResultOf(d), self.result)
        self.ca.invalidate(1)
        self.resps[1] = 'r2'
        d = self.ca.authenticate_tenant(1)
        self.assertEqual(self.successResultOf(d), 'r2')
Esempio n. 8
0
class CachingAuthenticatorTests(TestCase):
    """
    Test the in memory cache of authentication tokens.
    """
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.authenticator = iMock(IAuthenticator)

        def authenticate_tenant(tenant_id):
            return succeed(('auth-token', 'catalog'))

        self.authenticator.authenticate_tenant.side_effect = authenticate_tenant
        self.auth_function = self.authenticator.authenticate_tenant

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, self.authenticator, 10)

    def test_verifyObject(self):
        """
        CachingAuthenticator provides the IAuthenticator interface.
        """
        verifyObject(IAuthenticator, self.ca)

    def test_calls_auth_function_with_empty_cache(self):
        """
        authenticate_tenant with no items in the cache returns the result
        of the auth_function passed to the authenticator.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))
        self.auth_function.assert_called_once_with(1)

    def test_returns_token_from_cache(self):
        """
        authenticate_tenant returns tokens from the cache without calling
        auth_function again for subsequent calls.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))

        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))

        self.auth_function.assert_called_once_with(1)

    def test_cache_expires(self):
        """
        authenticate_tenant will call auth_function again after the ttl has
        lapsed.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token', 'catalog'))

        self.auth_function.assert_called_once_with(1)

        self.clock.advance(20)

        self.auth_function.side_effect = lambda _: succeed(
            ('auth-token2', 'catalog2'))

        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token2', 'catalog2'))

        self.auth_function.assert_has_calls([mock.call(1), mock.call(1)])

    def test_serialize_auth_requests(self):
        """
        authenticate_tenant will serialize requests to authenticate the same
        tenant to prevent multiple outstanding auth requests when no
        value is cached.
        """
        auth_d = Deferred()
        self.auth_function.side_effect = lambda _: auth_d

        d1 = self.ca.authenticate_tenant(1)
        d2 = self.ca.authenticate_tenant(1)

        self.assertNotIdentical(d1, d2)

        self.auth_function.assert_called_once_with(1)

        auth_d.callback(('auth-token2', 'catalog2'))

        r1 = self.successResultOf(d1)
        r2 = self.successResultOf(d2)

        self.assertEqual(r1, r2)
        self.assertEqual(r1, ('auth-token2', 'catalog2'))

    def test_cached_value_per_tenant(self):
        """
        authenticate_tenant calls auth_function for each distinct tenant_id
        not found in the cache.
        """
        r1 = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(r1, ('auth-token', 'catalog'))

        self.auth_function.side_effect = lambda _: succeed(
            ('auth-token2', 'catalog2'))

        r2 = self.successResultOf(self.ca.authenticate_tenant(2))

        self.assertEqual(r2, ('auth-token2', 'catalog2'))

    def test_auth_failure_propagated_to_waiters(self):
        """
        authenticate_tenant propagates auth failures to all waiters
        """
        auth_d = Deferred()
        self.auth_function.side_effect = lambda _: auth_d

        d1 = self.ca.authenticate_tenant(1)
        d2 = self.ca.authenticate_tenant(1)

        self.assertNotIdentical(d1, d2)

        auth_d.errback(APIError(500, '500'))

        self.failureResultOf(d1)

        f2 = self.failureResultOf(d2)
        self.assertTrue(f2.check(APIError))

    def test_auth_failure_propagated_to_caller(self):
        """
        authenticate_tenant propagates auth failures to the caller.
        """
        self.auth_function.side_effect = lambda _: fail(APIError(500, '500'))

        d = self.ca.authenticate_tenant(1)
        failure = self.failureResultOf(d)
        self.assertTrue(failure.check(APIError))
Esempio n. 9
0
class CachingAuthenticatorTests(SynchronousTestCase):
    """
    Test the in memory cache of authentication tokens.
    """
    def setUp(self):
        """
        Configure a clock and a fake auth function.
        """
        self.result = ('auth-token', 'catalog')
        self.resps = {1: self.result}

        class FakeAuthenticator(object):
            def authenticate_tenant(fself, tenant_id, log=None):
                r = self.resps[tenant_id]
                if isinstance(r, Deferred):
                    return r
                return fail(r) if isinstance(r, Exception) else succeed(r)

        self.clock = Clock()
        self.ca = CachingAuthenticator(self.clock, FakeAuthenticator(), 10)

    def test_verifyObject(self):
        """
        CachingAuthenticator provides the IAuthenticator interface.
        """
        verifyObject(IAuthenticator, self.ca)

    def test_calls_auth_function_with_empty_cache(self):
        """
        authenticate_tenant with no items in the cache returns the result
        of the auth_function passed to the authenticator.
        """
        result = self.successResultOf(
            self.ca.authenticate_tenant(1, mock.Mock()))
        self.assertEqual(result, self.result)

    def test_returns_token_from_cache(self):
        """
        authenticate_tenant returns tokens from the cache without calling
        auth_function again for subsequent calls.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, self.result)

        # Remove result and it still succeeds since it is from cache
        del self.resps[1]
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, self.result)

    def test_cache_expires(self):
        """
        authenticate_tenant will call auth_function again after the ttl has
        lapsed.
        """
        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, self.result)

        self.clock.advance(20)

        self.resps[1] = ('auth-token2', 'catalog2')

        result = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(result, ('auth-token2', 'catalog2'))

    def test_serialize_auth_requests(self):
        """
        authenticate_tenant will serialize requests to authenticate the same
        tenant to prevent multiple outstanding auth requests when no
        value is cached.
        """
        auth_d = Deferred()
        self.resps[1] = auth_d

        d1 = self.ca.authenticate_tenant(1)
        d2 = self.ca.authenticate_tenant(1)

        self.assertIs(auth_d, d1)
        self.assertNotIdentical(d1, d2)

        del self.resps[1]
        auth_d.callback(('auth-token2', 'catalog2'))

        r1 = self.successResultOf(d1)
        r2 = self.successResultOf(d2)

        self.assertEqual(r1, r2)
        self.assertEqual(r1, ('auth-token2', 'catalog2'))

    def test_cached_value_per_tenant(self):
        """
        authenticate_tenant calls auth_function for each distinct tenant_id
        not found in the cache.
        """
        r1 = self.successResultOf(self.ca.authenticate_tenant(1))
        self.assertEqual(r1, self.result)

        del self.resps[1]
        self.resps[2] = ('auth-token2', 'catalog2')

        r2 = self.successResultOf(self.ca.authenticate_tenant(2))

        self.assertEqual(r2, ('auth-token2', 'catalog2'))

    def test_auth_failure_propagated_to_waiters(self):
        """
        authenticate_tenant propagates auth failures to all waiters
        """
        auth_d = Deferred()
        self.resps[1] = auth_d

        d1 = self.ca.authenticate_tenant(1)
        del self.resps[1]
        d2 = self.ca.authenticate_tenant(1)

        self.assertNotIdentical(d1, d2)

        auth_d.errback(APIError(500, '500'))

        self.failureResultOf(d1, APIError)

        self.failureResultOf(d2, APIError)

    def test_auth_failure_propagated_to_caller(self):
        """
        authenticate_tenant propagates auth failures to the caller.
        """
        self.resps[1] = APIError(500, '500')

        d = self.ca.authenticate_tenant(1)
        self.failureResultOf(d, APIError)

    def test_invalidate(self):
        """
        The invalidate method causes the next authenticate_tenant call to
        re-authenticate.
        """
        d = self.ca.authenticate_tenant(1)
        self.assertEqual(self.successResultOf(d), self.result)
        self.ca.invalidate(1)
        self.resps[1] = 'r2'
        d = self.ca.authenticate_tenant(1)
        self.assertEqual(self.successResultOf(d), 'r2')