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 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 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
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)
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))
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')
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))
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')