class SecureRecentActivityAPITest(RecentActivityAPITestMixin, CachingRecentActivityAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('client', IndexResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureRecentActivityAPITest, self).setUp() createSystemData() UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) self.user = getUser(u'user') self.recentActivity = SecureRecentActivityAPI(self.user) def getObjectAPI(self, user): """Get an L{CachingObjectAPI} instance for the specified user. @param user: The L{User} to configure the L{CachingObjectAPI} instance. @return: An L{CachingObjectAPI} instance. """ return CachingObjectAPI(user) def getTagValueAPI(self, user): """Get a L{TagValueAPI} instance for the specified user. @param user: The L{User} to configure the L{TagValueAPI} instance. @return: A L{TagValueAPI} instance. """ return CachingTagValueAPI(user)
class AuthenticateTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def testAuthenticate(self): """ L{authenticate} will be successful if the C{username} and the plaintext C{password} passed match a L{User} in the database. """ user = createUser(u'fred', u'fred-secret', u'Fred', u'*****@*****.**') self.assertIdentical(user, authenticate(u'fred', u'fred-secret')) def testAuthenticateFailsWithIncorrectPassword(self): """ L{authenticate} will be unsuccessful if the C{username} and the plaintext C{password} passed don't match a L{User} in the database. """ createUser(u'fred', u'fred-secret', u'Fred', u'*****@*****.**') self.assertRaises(AuthenticationError, authenticate, u'fred', u'bad-secret') def testAuthenticateFailsWithUnknownUser(self): """ L{authenticate} will be unsuccessful if the C{username} and the plaintext C{password} passed don't match a L{User} in the database. """ error = self.assertRaises(UnknownUserError, authenticate, u'unknown', u'bad-secret') self.assertEqual([u'unknown'], error.usernames)
class GetCacheClientTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource())] def testGetCacheClient(self): """ L{getCacheClient} returns a configured L{Redis} client that is ready to use. """ client = getCacheClient() self.assertIsInstance(client, Redis) def testGetCacheClientUsesGlobalConnectionPool(self): """ L{getCacheClient} returns a L{Redis} client that uses the global connection pool. """ client = getCacheClient() connectionPool = getCacheConnectionPool() self.assertIdentical(client.connection_pool, connectionPool) def testGetCacheClientsUseTheSameConnectionPool(self): """ L{getCacheClient} returns a L{Redis} client that uses the global connection pool. """ client1 = getCacheClient() client2 = getCacheClient() self.assertIdentical(client1.connection_pool, client2.connection_pool)
class SecureNamespaceAPIWithSuperuserTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureNamespaceAPIWithSuperuserTest, self).setUp() system = createSystemData() user = system.users[u'fluiddb'] self.namespaces = SecureNamespaceAPI(user) self.permissions = CachingPermissionAPI(user) def testCreateIsAllowed(self): """ Creating a new L{Namespace} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ values = [(u'fluiddb', Operation.CREATE_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) result = self.namespaces.create([(u'fluiddb/test', u'description')]) self.assertEqual(1, len(result)) def testDeleteIsAllowed(self): """ Deleting a L{Namespace} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ result1 = self.namespaces.create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb/test', Operation.DELETE_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) result2 = self.namespaces.delete([u'fluiddb/test']) self.assertEqual(result1, result2) def testSetIsAllowed(self): """ Updating a L{Namespace} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ self.namespaces.create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb/test', Operation.UPDATE_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) self.namespaces.set({u'fluiddb/test': u'new description'}) def testGetIsAllowed(self): """ Getting information about a L{Namespace} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ self.namespaces.create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb/test', Operation.LIST_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) result = self.namespaces.get([u'fluiddb'], withDescriptions=False, withTags=True, withNamespaces=True) self.assertEqual(1, len(result))
class CachingUserAPITest(UserAPITestMixin, CachingUserAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(CachingUserAPITest, self).setUp() self.system = createSystemData() self.users = CachingUserAPI()
class SecureUserAPITest(UserAPITestMixin, CachingUserAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureUserAPITest, self).setUp() self.system = createSystemData() user = self.system.users[u'fluiddb'] self.users = SecureUserAPI(user)
class SecureUserAPIWithAnonymousRoleTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureUserAPIWithAnonymousRoleTest, self).setUp() system = createSystemData() self.user = system.users[u'anon'] self.users = SecureUserAPI(self.user) def testCreateIsDenied(self): """ L{SecureUserAPI.create} raises a L{PermissionDeniedError} if it's invoked by a L{User} with the L{Role.ANONYMOUS}. """ values = [(u'user', u'secret', u'User', u'*****@*****.**')] error = self.assertRaises(PermissionDeniedError, self.users.create, values) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'user', Operation.CREATE_USER)], error.pathsAndOperations) def testDeleteIsDenied(self): """ L{SecureUserAPI.delete} raises a L{PermissionDeniedError} if it's invoked by a L{User} with the L{Role.ANONYMOUS}. """ error = self.assertRaises(PermissionDeniedError, self.users.delete, [u'user']) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'user', Operation.DELETE_USER)], error.pathsAndOperations) def testGetIsAllowed(self): """ L{SecureUserAPI.get} can always be invoked by a L{User} with the L{Role.ANONYMOUS}. """ UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) result = self.users.get([u'user']) self.assertIn(u'user', result) def testSetIsDenied(self): """ L{SecureUserAPI.set} raises a L{PermissionDeniedError} if it's invoked by a L{User} with the L{Role.ANONYMOUS}. """ values = [(u'user', u'secret', u'User', u'*****@*****.**', None)] error = self.assertRaises(PermissionDeniedError, self.users.set, values) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'user', Operation.UPDATE_USER)], error.pathsAndOperations)
class SecureTagAPIWithSuperuserTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureTagAPIWithSuperuserTest, self).setUp() system = createSystemData() user = system.users[u'fluiddb'] self.tags = SecureTagAPI(user) self.permissions = CachingPermissionAPI(user) def testCreateIsAllowed(self): """ Creating a new L{Tag} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ values = [(u'fluiddb', Operation.CREATE_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) result = self.tags.create([(u'fluiddb/test', u'description')]) self.assertEqual(1, len(result)) def testDeleteIsAllowed(self): """ Deleting a L{Tag} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ result1 = self.tags.create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb/test', Operation.DELETE_TAG, Policy.CLOSED, [])] self.permissions.set(values) result2 = self.tags.delete([u'fluiddb/test']) self.assertEqual(result1, result2) def testSetIsAllowed(self): """ Updating a L{Tag} should be allowed if we're a user with a L{Role.SUPERUSER} no matter what permissions we have. """ result = self.tags.create([(u'fluiddb/test', u'A description')]) [(objectID, _)] = result values = [(u'fluiddb/test', Operation.UPDATE_TAG, Policy.CLOSED, [])] self.permissions.set(values) self.tags.set({u'fluiddb/test': u'A new description'}) result = self.tags.get([u'fluiddb/test'], withDescriptions=True) expected = { u'fluiddb/test': { 'id': objectID, 'description': u'A new description' } } self.assertEqual(expected, result)
class CachingObjectAPITest(ObjectAPITestMixin, CachingObjectAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('client', IndexResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(CachingObjectAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'user', u'password', u'User', u'*****@*****.**') ]) self.user = getUser(u'user') self.objects = CachingObjectAPI(self.user)
class CachingRecentActivityAPITest(RecentActivityAPITestMixin, CachingRecentActivityAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(CachingRecentActivityAPITest, self).setUp() createSystemData() self.recentActivity = CachingRecentActivityAPI() UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) self.user = getUser(u'user')
class CachingPermissionAPITest(PermissionAPITestMixin, CachingPermissionAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(CachingPermissionAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.permissions = CachingPermissionAPI(self.user)
class SecureUserAPIWithSuperuserRoleTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureUserAPIWithSuperuserRoleTest, self).setUp() self.system = createSystemData() self.users = SecureUserAPI(self.system.users[u'fluiddb']) def testCreateIsAllowed(self): """ L{SecureUserAPI.create} can always be invoked by a L{User} with the L{Role.SUPERUSER}. """ self.users.create([(u'user', u'secret', u'User', u'*****@*****.**')]) user = getUser(u'user') self.assertEqual(u'user', user.username) def testDeleteIsAllowed(self): """ L{SecureUserAPI.delete} can always be invoked by a L{User} with the L{Role.SUPERUSER}. """ UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) namespaces = SecureNamespaceAPI(self.system.users['fluiddb']) namespaces.delete([u'user/private']) self.users.delete([u'user']) self.assertIdentical(None, getUser(u'user')) def testGetIsAllowed(self): """ L{SecureUserAPI.get} can always be invoked by a L{User} with the L{Role.SUPERUSER}. """ UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) result = self.users.get([u'user']) self.assertIn(u'user', result) def testSetIsAllowed(self): """ L{SecureUserAPI.set} can always be invoked by a L{User} with the L{Role.SUPERUSER}. """ UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) user = getUser(u'user') self.users.set([(u'user', u'secret', u'User', u'*****@*****.**', None)]) self.assertEqual(u'*****@*****.**', user.email)
class SecureTagAPIWithAnonymousRoleTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureTagAPIWithAnonymousRoleTest, self).setUp() system = createSystemData() self.anon = system.users[u'anon'] UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.tags = SecureTagAPI(self.anon) def testCreateIsDenied(self): """ L{SecureTagAPI.create} raises a L{PermissionDeniedError} if its invoked by a L{User} with the L{Role.ANONYMOUS}. """ error = self.assertRaises(PermissionDeniedError, self.tags.create, [(u'user/foo', 'A foo tag')]) self.assertEqual(self.anon.username, error.username) self.assertEqual([('user', Operation.CREATE_NAMESPACE)], error.pathsAndOperations) def testDeleteIsDenied(self): """ L{SecureTagAPI.delete} raises a L{PermissionDeniedError} if its invoked by a L{User} with the L{Role.ANONYMOUS}. """ createTag(self.user, self.user.namespace, u'path') error = self.assertRaises(PermissionDeniedError, self.tags.delete, [u'user/path']) self.assertEqual(self.anon.username, error.username) self.assertEqual([('user/path', Operation.DELETE_TAG)], error.pathsAndOperations) def testSetIsDenied(self): """ L{SecureTagAPI.set} raises a L{PermissionDeniedError} if its invoked by a L{User} with the L{Role.ANONYMOUS}. """ createTag(self.user, self.user.namespace, u'path') error = self.assertRaises(PermissionDeniedError, self.tags.set, {u'user/path': 'A path tag'}) self.assertEqual(self.anon.username, error.username) self.assertEqual([('user/path', Operation.UPDATE_TAG)], error.pathsAndOperations)
class ObjectCacheTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource(format='%(message)s'))] def setUp(self): super(ObjectCacheTest, self).setUp() self.objectCache = ObjectCache() def testGetReturnsObjectsInCache(self): """L{ObjectCache.get} returns the objectIDs saved in the cache.""" objectID1 = uuid4() objectID2 = uuid4() self.cache.set(u'about:about1', str(objectID1)) self.cache.set(u'about:about2', str(objectID2)) result = self.objectCache.get([u'about1', u'about2']) expected = {u'about1': objectID1, u'about2': objectID2} self.assertEqual(expected, result.results) self.assertEqual([], result.uncachedValues) def testGetReturnsUncachedValues(self): """ L{ObjectCache.get} returns values not found in the cache in the C{uncachedValues} field of the L{CacheResult} object. """ objectID1 = uuid4() self.cache.set(u'about:about1', str(objectID1)) result = self.objectCache.get([u'about1', u'about2', u'about3']) self.assertEqual({u'about1': objectID1}, result.results) self.assertEqual([u'about2', u'about3'], result.uncachedValues) def testGetWithUnicodeAboutValue(self): """ L{ObjectCache.get} correctly get objectIDs with unicode about values. """ objectID1 = uuid4() self.cache.set(u'about:\N{HIRAGANA LETTER A}', str(objectID1)) result = self.objectCache.get([u'\N{HIRAGANA LETTER A}']) self.assertEqual({u'\N{HIRAGANA LETTER A}': objectID1}, result.results) self.assertEqual([], result.uncachedValues) def testSaveStoresValuesInTheCache(self): """L{ObjectCache.save} stores a result in the cache.""" objectID1 = uuid4() objectID2 = uuid4() self.objectCache.save({u'about1': objectID1, u'about2': objectID2}) self.assertEqual(str(objectID1), self.cache.get('about:about1')) self.assertEqual(str(objectID2), self.cache.get('about:about2'))
class FacadeCheckerTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource()), ('store', DatabaseResource()), ('threadPool', ThreadPoolResource())] def setUp(self): super(FacadeCheckerTest, self).setUp() factory = FluidinfoSessionFactory('API-9000') transact = Transact(self.threadPool) createSystemData() self.checker = FacadeChecker() self.checker.facadeClient = Facade(transact, factory) def testRequestAvatarIdWithIncorrectPassword(self): """ L{FacadeChecker.requestAvatarId} when passed credentials with an incorrect password must raise C{UnauthorizedLogin}. """ createUser(u'user', u'pass', u'User', u'*****@*****.**') self.store.commit() credentials = UsernamePassword('user', 'bad password') deferred = self.checker.requestAvatarId(credentials) return self.assertFailure(deferred, UnauthorizedLogin) def testRequestAvatarIdWithNonExistentUser(self): """ L{FacadeChecker.requestAvatarId} when passed credentials with a non-existent user must raise C{UnauthorizedLogin}. """ credentials = UsernamePassword('user', 'pass') deferred = self.checker.requestAvatarId(credentials) return self.assertFailure(deferred, UnauthorizedLogin) @inlineCallbacks def testRequestAvatarId(self): """ L{FacadeChecker.requestAvatarId} when passed credentials creates a L{FluidinfoSession} for the authenticated user only if credentials are correct. """ user = createUser(u'user', u'pass', u'User', u'*****@*****.**') self.store.commit() credentials = UsernamePassword('user', 'pass') session = yield self.checker.requestAvatarId(credentials) self.assertEqual(user.username, session.auth.username) self.assertEqual(user.objectID, session.auth.objectID)
class SecureTagValueAPIWithSuperuserRoleTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureTagValueAPIWithSuperuserRoleTest, self).setUp() system = createSystemData() self.superuser = system.users[u'fluiddb'] TagAPI(self.superuser).create([(u'fluiddb/tag', u'description')]) self.tagValues = SecureTagValueAPI(self.superuser) self.permissions = CachingPermissionAPI(self.superuser) def testGetIsAllowed(self): """L{SecureTagValueAPI.get} is always allowed for the superuser.""" objectID = uuid4() values = {objectID: {u'fluiddb/tag': 16}} self.tagValues.set(values) self.permissions.set([(u'fluiddb/tag', Operation.READ_TAG_VALUE, Policy.CLOSED, [])]) result = self.tagValues.get(objectIDs=[objectID], paths=[u'fluiddb/tag']) self.assertEqual(16, result[objectID][u'fluiddb/tag'].value) def testSetIsAllowed(self): """L{SecureTagValueAPI.set} is always allowed for the superuser.""" self.permissions.set([(u'fluiddb/tag', Operation.WRITE_TAG_VALUE, Policy.CLOSED, [])]) objectID = uuid4() values = {objectID: {u'fluiddb/tag': 16}} self.tagValues.set(values) result = self.tagValues.get(objectIDs=[objectID], paths=[u'fluiddb/tag']) self.assertEqual(16, result[objectID][u'fluiddb/tag'].value) def testDeleteIsAllowed(self): """L{SecureTagValueAPI.delete} is always allowed for the superuser.""" self.permissions.set([(u'fluiddb/tag', Operation.DELETE_TAG_VALUE, Policy.CLOSED, [])]) objectID = uuid4() values = {objectID: {u'fluiddb/tag': 16}} self.tagValues.set(values) self.tagValues.delete([(objectID, u'fluiddb/tag')]) result = self.tagValues.get(objectIDs=[objectID], paths=[u'fluiddb/tag']) self.assertEqual({}, result)
class CachingPermissionCheckerAPITest(PermissionCheckerAPITestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(CachingPermissionCheckerAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.api = CachingPermissionCheckerAPI() def testGetNamespacePermissionsCachesMisses(self): """ L{CachingPermissionCheckerAPI.getNamespacePermissions} adds missing L{NamespacePermission}s to the cache. """ result = self.api.getNamespacePermissions([u'username']) permission = result[u'username'] self.assertTrue(isinstance(permission, NamespacePermission)) # Go behind everyone's back and kill the NamespacePermission. self.store.find(NamespacePermission).remove() result = self.api.getNamespacePermissions([u'username']) permission = result[u'username'] self.assertTrue(isinstance(permission, NamespacePermission)) def testGetTagPermissionsCachesMisses(self): """ L{CachingPermissionCheckerAPI.getTagPermissions} adds missing L{TagPermission}s to the cache. """ TagAPI(self.user).create([(u'username/tag', u'A tag')]) result = self.api.getTagPermissions([u'username/tag']) permission = result[u'username/tag'] self.assertTrue(isinstance(permission, TagPermission)) # Go behind everyone's back and kill the TagPermission. self.store.find(TagPermission).remove() result = self.api.getTagPermissions([u'username/tag']) permission = result[u'username/tag'] self.assertTrue(isinstance(permission, TagPermission))
class CachingGetUserTest(GetUserTestMixin, FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(CachingGetUserTest, self).setUp() self.getUser = cachingGetUser def testCachingGetUserUsesTheCache(self): """L{getUser} adds missing L{User}s to the cache.""" createUser(u'user', u'password', u'User', u'*****@*****.**') user = self.getUser(u'user') self.assertIsInstance(user, User) # Delete the user from the store self.store.remove(user) user = self.getUser(u'user') self.assertIsInstance(user, User)
class PermissionCacheTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource(format='%(message)s'))] def setUp(self): super(PermissionCacheTest, self).setUp() self.permissionCache = PermissionCache() def setList(self, name, values): """Small helper method to put a C{list} in the cache.""" for item in values: self.cache.rpush(name, item) def testGetTagPermissions(self): """ L{PermissionCache.getTagPermissions} returns L{TagPermission}s stored in the cache. """ permissionDict = { Operation.UPDATE_TAG.id: [Policy.OPEN.id, [1, 2, 3]], Operation.DELETE_TAG.id: [Policy.CLOSED.id, [4, 5, 6]], Operation.CONTROL_TAG.id: [Policy.OPEN.id, [7, 8, 9]], Operation.WRITE_TAG_VALUE.id: [Policy.CLOSED.id, [10, 11, 12]], Operation.READ_TAG_VALUE.id: [Policy.OPEN.id, [13, 14, 15]], Operation.DELETE_TAG_VALUE.id: [Policy.CLOSED.id, [16, 17, 18]], Operation.CONTROL_TAG_VALUE.id: [Policy.OPEN.id, [19, 20, 21]] } self.cache.set('permission:tag:test/tag1', json.dumps(permissionDict)) permissionDict = { Operation.UPDATE_TAG.id: [Policy.CLOSED.id, [10, 15, 20]], Operation.DELETE_TAG.id: [Policy.OPEN.id, [25, 30, 35]], Operation.CONTROL_TAG.id: [Policy.CLOSED.id, [40, 45, 50]], Operation.WRITE_TAG_VALUE.id: [Policy.OPEN.id, [55, 60, 65]], Operation.READ_TAG_VALUE.id: [Policy.CLOSED.id, [70, 75, 80]], Operation.DELETE_TAG_VALUE.id: [Policy.OPEN.id, [85, 90, 95]], Operation.CONTROL_TAG_VALUE.id: [Policy.CLOSED.id, [100, 105, 110]] } self.cache.set('permission:tag:test/tag2', json.dumps(permissionDict)) result = self.permissionCache.getTagPermissions( [u'test/tag1', u'test/tag2']) self.assertEqual([], result.uncachedValues) permission1 = result.results[u'test/tag1'] self.assertEqual((Policy.OPEN, [1, 2, 3]), permission1.get(Operation.UPDATE_TAG)) self.assertEqual((Policy.CLOSED, [4, 5, 6]), permission1.get(Operation.DELETE_TAG)) self.assertEqual((Policy.OPEN, [7, 8, 9]), permission1.get(Operation.CONTROL_TAG)) self.assertEqual((Policy.CLOSED, [10, 11, 12]), permission1.get(Operation.WRITE_TAG_VALUE)) self.assertEqual((Policy.OPEN, [13, 14, 15]), permission1.get(Operation.READ_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [16, 17, 18]), permission1.get(Operation.DELETE_TAG_VALUE)) self.assertEqual((Policy.OPEN, [19, 20, 21]), permission1.get(Operation.CONTROL_TAG_VALUE)) permission2 = result.results[u'test/tag2'] self.assertEqual((Policy.CLOSED, [10, 15, 20]), permission2.get(Operation.UPDATE_TAG)) self.assertEqual((Policy.OPEN, [25, 30, 35]), permission2.get(Operation.DELETE_TAG)) self.assertEqual((Policy.CLOSED, [40, 45, 50]), permission2.get(Operation.CONTROL_TAG)) self.assertEqual((Policy.OPEN, [55, 60, 65]), permission2.get(Operation.WRITE_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [70, 75, 80]), permission2.get(Operation.READ_TAG_VALUE)) self.assertEqual((Policy.OPEN, [85, 90, 95]), permission2.get(Operation.DELETE_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [100, 105, 110]), permission2.get(Operation.CONTROL_TAG_VALUE)) def testGetTagPermissionsReturnsUncachedValues(self): """ L{PermissionCache.getTagPermissions} returns the paths of L{TagPermission}s not found in the cache. """ permissionDict = { Operation.UPDATE_TAG.id: [Policy.OPEN.id, [1, 2, 3]], Operation.DELETE_TAG.id: [Policy.CLOSED.id, [4, 5, 6]], Operation.CONTROL_TAG.id: [Policy.OPEN.id, [7, 8, 9]], Operation.WRITE_TAG_VALUE.id: [Policy.CLOSED.id, [10, 11, 12]], Operation.READ_TAG_VALUE.id: [Policy.OPEN.id, [13, 14, 15]], Operation.DELETE_TAG_VALUE.id: [Policy.CLOSED.id, [16, 17, 18]], Operation.CONTROL_TAG_VALUE.id: [Policy.OPEN.id, [19, 20, 21]] } self.cache.set('permission:tag:test/tag1', json.dumps(permissionDict)) result = self.permissionCache.getTagPermissions( [u'test/tag1', u'test/tag2']) self.assertEqual([u'test/tag2'], result.uncachedValues) self.assertIn(u'test/tag1', result.results) def testGetTagPermissionsWithEmptyPaths(self): """ L{PermissionCache.getTagPermissions} returns an empty L{CacheResult} if no paths are provided. """ cached = self.permissionCache.getTagPermissions([]) self.assertEqual({}, cached.results) self.assertEqual([], cached.uncachedValues) def testGetNamespacePermissions(self): """ L{PermissionCache.getNamespacePermissions} returns L{NamespacePermission}s stored in the cache. """ permissionDict = { Operation.CREATE_NAMESPACE.id: [Policy.OPEN.id, [1, 2, 3]], Operation.UPDATE_NAMESPACE.id: [Policy.CLOSED.id, [4, 5, 6]], Operation.DELETE_NAMESPACE.id: [Policy.OPEN.id, [7, 8, 9]], Operation.LIST_NAMESPACE.id: [Policy.CLOSED.id, [10, 11, 12]], Operation.CONTROL_NAMESPACE.id: [Policy.OPEN.id, [13, 14, 15]], } self.cache.set('permission:namespace:test/namespace1', json.dumps(permissionDict)) permissionDict = { Operation.CREATE_NAMESPACE.id: [Policy.CLOSED.id, [5, 10, 15]], Operation.UPDATE_NAMESPACE.id: [Policy.OPEN.id, [20, 25, 30]], Operation.DELETE_NAMESPACE.id: [Policy.CLOSED.id, [35, 40, 45]], Operation.LIST_NAMESPACE.id: [Policy.OPEN.id, [50, 55, 60]], Operation.CONTROL_NAMESPACE.id: [Policy.CLOSED.id, [65, 70, 75]], } self.cache.set('permission:namespace:test/namespace2', json.dumps(permissionDict)) result = self.permissionCache.getNamespacePermissions( [u'test/namespace1', u'test/namespace2']) permission1 = result.results[u'test/namespace1'] self.assertEqual((Policy.OPEN, [1, 2, 3]), permission1.get(Operation.CREATE_NAMESPACE)) self.assertEqual((Policy.CLOSED, [4, 5, 6]), permission1.get(Operation.UPDATE_NAMESPACE)) self.assertEqual((Policy.OPEN, [7, 8, 9]), permission1.get(Operation.DELETE_NAMESPACE)) self.assertEqual((Policy.CLOSED, [10, 11, 12]), permission1.get(Operation.LIST_NAMESPACE)) self.assertEqual((Policy.OPEN, [13, 14, 15]), permission1.get(Operation.CONTROL_NAMESPACE)) permission2 = result.results[u'test/namespace2'] self.assertEqual((Policy.CLOSED, [5, 10, 15]), permission2.get(Operation.CREATE_NAMESPACE)) self.assertEqual((Policy.OPEN, [20, 25, 30]), permission2.get(Operation.UPDATE_NAMESPACE)) self.assertEqual((Policy.CLOSED, [35, 40, 45]), permission2.get(Operation.DELETE_NAMESPACE)) self.assertEqual((Policy.OPEN, [50, 55, 60]), permission2.get(Operation.LIST_NAMESPACE)) self.assertEqual((Policy.CLOSED, [65, 70, 75]), permission2.get(Operation.CONTROL_NAMESPACE)) def testGetNamespacePermissionsReturnsUncachedValues(self): """ L{PermissionCache.getNamespacePermissions} returns the paths of L{NamespacePermission}s not found in the cache. """ permissionDict = { Operation.CREATE_NAMESPACE.id: [Policy.OPEN.id, [1, 2, 3]], Operation.UPDATE_NAMESPACE.id: [Policy.CLOSED.id, [4, 5, 6]], Operation.DELETE_NAMESPACE.id: [Policy.OPEN.id, [7, 8, 9]], Operation.LIST_NAMESPACE.id: [Policy.CLOSED.id, [10, 11, 12]], Operation.CONTROL_NAMESPACE.id: [Policy.OPEN.id, [13, 14, 15]], } self.cache.set('permission:namespace:test/namespace1', json.dumps(permissionDict)) result = self.permissionCache.getNamespacePermissions( [u'test/namespace1', u'test/namespace2']) self.assertEqual([u'test/namespace2'], result.uncachedValues) self.assertIn(u'test/namespace1', result.results) def testGetNamespacePermissionsWithEmptyPaths(self): """ L{PermissionCache.getNamespacePermissions} returns an empty L{CacheResult} if no paths are provided. """ cached = self.permissionCache.getNamespacePermissions([]) self.assertEqual({}, cached.results) self.assertEqual([], cached.uncachedValues) def testClearTagPermissionsRemovesTagPermissions(self): """ L{PermissionCache.clearTagPermissions} removes L{TagPermission}s from the cache, leaving L{NamespacePermission} for the same paths. """ permissionDict = { Operation.UPDATE_TAG.id: [Policy.OPEN.id, [1, 2, 3]], Operation.DELETE_TAG.id: [Policy.CLOSED.id, [4, 5, 6]], Operation.CONTROL_TAG.id: [Policy.OPEN.id, [7, 8, 9]], Operation.WRITE_TAG_VALUE.id: [Policy.CLOSED.id, [10, 11, 12]], Operation.READ_TAG_VALUE.id: [Policy.OPEN.id, [13, 14, 15]], Operation.DELETE_TAG_VALUE.id: [Policy.CLOSED.id, [16, 17, 18]], Operation.CONTROL_TAG_VALUE.id: [Policy.OPEN.id, [19, 20, 21]] } self.cache.set('permission:tag:test/test', json.dumps(permissionDict)) self.permissionCache.clearTagPermissions([u'test/test']) self.assertIdentical(None, self.cache.get('permission:tag:test/test')) def testClearNamespacePermissionsRemovesNamespacePermissions(self): """ L{PermissionCache.clearNamespacePermissions} removes L{NamespacePermission}s from the cache, leaving L{TagPermission} for the same paths. """ permissionDict = { Operation.CREATE_NAMESPACE.id: [Policy.OPEN.id, [1, 2, 3]], Operation.UPDATE_NAMESPACE.id: [Policy.CLOSED.id, [4, 5, 6]], Operation.DELETE_NAMESPACE.id: [Policy.OPEN.id, [7, 8, 9]], Operation.LIST_NAMESPACE.id: [Policy.CLOSED.id, [10, 11, 12]], Operation.CONTROL_NAMESPACE.id: [Policy.OPEN.id, [13, 14, 15]], } self.cache.set('permission:namespace:test/test', json.dumps(permissionDict)) self.permissionCache.clearNamespacePermissions([u'test/test']) self.assertIdentical(None, self.cache.get('permission:namespace:test/test')) def testSaveTagPermissions(self): """ L{PermissionCache.saveTagPermissions} store L{TagPermission}s in the cache. """ permissions = { 'test/tag1': TagPermission(userID=1, tagID=1), 'test/tag2': TagPermission(userID=2, tagID=2) } self.permissionCache.saveTagPermissions(permissions) expected = { str(Operation.UPDATE_TAG.id): [False, [1]], str(Operation.DELETE_TAG.id): [False, [1]], str(Operation.CONTROL_TAG.id): [False, [1]], str(Operation.WRITE_TAG_VALUE.id): [False, [1]], str(Operation.READ_TAG_VALUE.id): [True, []], str(Operation.DELETE_TAG_VALUE.id): [False, [1]], str(Operation.CONTROL_TAG_VALUE.id): [False, [1]] } self.assertEqual( expected, json.loads(self.cache.get('permission:tag:test/tag1'))) expected = { str(Operation.UPDATE_TAG.id): [False, [2]], str(Operation.DELETE_TAG.id): [False, [2]], str(Operation.CONTROL_TAG.id): [False, [2]], str(Operation.WRITE_TAG_VALUE.id): [False, [2]], str(Operation.READ_TAG_VALUE.id): [True, []], str(Operation.DELETE_TAG_VALUE.id): [False, [2]], str(Operation.CONTROL_TAG_VALUE.id): [False, [2]] } self.assertEqual( expected, json.loads(self.cache.get('permission:tag:test/tag2'))) def testSaveNamespacePermissions(self): """ L{PermissionCache.saveNamespacePermissions} store L{NamespacePermission}s in the cache. """ permissions = { 'test/ns1': NamespacePermission(userID=1, namespaceID=1), 'test/ns2': NamespacePermission(userID=2, namespaceID=2) } self.permissionCache.saveNamespacePermissions(permissions) expected = { str(Operation.CREATE_NAMESPACE.id): [False, [1]], str(Operation.UPDATE_NAMESPACE.id): [False, [1]], str(Operation.DELETE_NAMESPACE.id): [False, [1]], str(Operation.LIST_NAMESPACE.id): [True, []], str(Operation.CONTROL_NAMESPACE.id): [False, [1]] } self.assertEqual( expected, json.loads(self.cache.get('permission:namespace:test/ns1'))) expected = { str(Operation.CREATE_NAMESPACE.id): [False, [2]], str(Operation.UPDATE_NAMESPACE.id): [False, [2]], str(Operation.DELETE_NAMESPACE.id): [False, [2]], str(Operation.LIST_NAMESPACE.id): [True, []], str(Operation.CONTROL_NAMESPACE.id): [False, [2]] } self.assertEqual( expected, json.loads(self.cache.get('permission:namespace:test/ns2')))
class SecureUserAPIWithNormalUserRoleTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureUserAPIWithNormalUserRoleTest, self).setUp() createSystemData() UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) self.user = getUser(u'user') self.users = SecureUserAPI(self.user) def testCreateIsDenied(self): """ L{SecureUserAPI.create} raises a L{PermissionDeniedError} if it's invoked by a L{User} with the L{Role.USER}. """ values = [(u'user', u'secret', u'User', u'*****@*****.**')] error = self.assertRaises(PermissionDeniedError, self.users.create, values) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'user', Operation.CREATE_USER)], error.pathsAndOperations) def testDeleteIsDenied(self): """ L{SecureUserAPI.delete} raises a L{PermissionDeniedError} if it's invoked by a L{User} with the L{Role.USER}. """ error = self.assertRaises(PermissionDeniedError, self.users.delete, [u'user']) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'user', Operation.DELETE_USER)], error.pathsAndOperations) def testGetIsAllowed(self): """ L{SecureUserAPI.get} can always be invoked by a L{User} with the L{Role.USER}. """ UserAPI().create([(u'username', u'secret', u'Username', u'*****@*****.**')]) result = self.users.get([u'username']) self.assertIn(u'username', result) def testSetIsDenied(self): """ L{SecureUserAPI.set} raises a L{PermissionDeniedError} if it's invoked by a L{User} with the L{Role.USER} different than the own user. """ UserAPI().create([(u'other', u'secret', u'User', u'*****@*****.**')]) values = [(u'other', u'secret', u'User', u'*****@*****.**', None)] error = self.assertRaises(PermissionDeniedError, self.users.set, values) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'other', Operation.UPDATE_USER)], error.pathsAndOperations) def testSetIsAllowed(self): """ L{SecureUserAPI.set} is allowed for the own L{User}. """ self.users.set([(u'user', u'secret', u'New', u'*****@*****.**', None) ]) self.assertEqual(u'*****@*****.**', self.user.email) self.assertEqual(u'New', self.user.fullname)
class SecureTagAPIWithNormalUserTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureTagAPIWithNormalUserTest, self).setUp() createSystemData() UserAPI().create([(u'user', u'password', u'User', u'*****@*****.**') ]) self.user = getUser(u'user') self.permissions = CachingPermissionAPI(self.user) self.tags = SecureTagAPI(self.user) def testCreateIsAllowed(self): """ L{SecureTagAPI.create} should allow the creation of tags whose parent namespace has open C{Operation.CREATE_NAMESPACE} permissions. """ result = self.tags.create([(u'user/test', u'description')]) self.assertEqual(1, len(result)) def testCreateIsDenied(self): """ L{SecureTagAPI.create} should raise L{PermissonDeniedError} if the user doesn't have C{Operation.CREATE_NAMESPACE} permissions on the parent namespace. """ values = [(u'user', Operation.CREATE_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.tags.create, [(u'user/test', u'description')]) self.assertEqual([(u'user', Operation.CREATE_NAMESPACE)], sorted(error.pathsAndOperations)) def testDeleteIsAllowed(self): """ L{SecureTagAPI.delete} should allow the deletion of a tag if the user has C{Operation.DELETE_TAG} permissions. """ result1 = self.tags.create([(u'user/test', u'description')]) result2 = self.tags.delete([u'user/test']) self.assertEqual(result1, result2) def testDeleteIsDenied(self): """ L{SecureTagAPI.delete} should raise L{PermissonDeniedError} if the user doesn't have C{Operation.DELETE_TAG} permissions. """ self.tags.create([(u'user/test', u'description')]) values = [(u'user/test', Operation.DELETE_TAG, Policy.OPEN, [u'user'])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.tags.delete, [(u'user/test')]) self.assertEqual([(u'user/test', Operation.DELETE_TAG)], sorted(error.pathsAndOperations)) def testSetIsAllowed(self): """ L{SecureTagAPI.get} should allow updating the description of a tag if the user has permissions. """ [(objectID, _)] = self.tags.create([(u'user/test', u'A description')]) self.tags.set({u'user/test': u'A new description'}) result = self.tags.get([u'user/test'], withDescriptions=True) expected = { u'user/test': { 'id': objectID, 'description': u'A new description' } } self.assertEqual(expected, result) def testSetIsDenied(self): """ L{SecureTagAPI.get} should raise L{PermissonDeniedError} if the user doesn't have C{Operation.UPDATE_TAG} permissions when trying to update a tag's description. """ self.tags.create([(u'user/test', u'description')]) values = [(u'user/test', Operation.UPDATE_TAG, Policy.CLOSED, [])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.tags.set, {u'user/test': u'description'}) self.assertEqual([(u'user/test', Operation.UPDATE_TAG)], sorted(error.pathsAndOperations))
class FacadeOAuth2CheckerTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource()), ('store', DatabaseResource()), ('threadPool', ThreadPoolResource())] def setUp(self): super(FacadeOAuth2CheckerTest, self).setUp() factory = FluidinfoSessionFactory('API-9000') transact = Transact(self.threadPool) createSystemData() self.checker = FacadeOAuth2Checker() self.checker.facadeClient = Facade(transact, factory) @inlineCallbacks def testRequestAvatarId(self): """ L{FacadeOAuth2Checker.requestAvatarId} creates a L{FluidinfoSession} for the authenticated user only if credentials are correct. """ UserAPI().create([(u'consumer', u'secret', u'Consumer', u'*****@*****.**'), (u'user', u'secret', u'User', u'*****@*****.**')]) consumerUser = getUser(u'consumer') user = getUser(u'user') api = OAuthConsumerAPI() api.register(consumerUser) token = api.getAccessToken(consumerUser, user) self.store.commit() credentials = OAuth2Credentials(u'consumer', 'secret', token.encrypt()) session = yield self.checker.requestAvatarId(credentials) self.assertEqual(user.username, session.auth.username) self.assertEqual(user.objectID, session.auth.objectID) def testRequestAvatarIdWithTokenMadeFromWrongSecret(self): """ L{FacadeOAuth2Checker.requestAvatarId} creates a L{FluidinfoSession} for the authenticated user only if the access token was created using the consumer's secret. """ user1 = createUser(u'user1', u'pass1', u'User1', u'*****@*****.**') createOAuthConsumer(user1, secret='secret16charlng1') user2 = createUser(u'user2', u'pass2', u'User2', u'*****@*****.**') self.store.commit() token = dataToToken('a' * 16, {'username': user2.username}) credentials = OAuth2Credentials(u'user1', u'pass1', token) deferred = self.checker.requestAvatarId(credentials) return self.assertFailure(deferred, UnauthorizedLogin) def testRequestAvatarIdWithInvalidToken(self): """ L{FacadeOAuth2Checker.requestAvatarId} creates a L{FluidinfoSession} for the authenticated user only if the access token was properly formed (by calling dataToToken). """ user = createUser(u'user', u'pass', u'User', u'*****@*****.**') createOAuthConsumer(user, secret='secret16charlng1') self.store.commit() credentials = OAuth2Credentials(u'user', u'pass', token='xxx') deferred = self.checker.requestAvatarId(credentials) return self.assertFailure(deferred, UnauthorizedLogin)
class FacadeTagMixinTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource()), ('store', DatabaseResource()), ('threadPool', ThreadPoolResource())] def setUp(self): super(FacadeTagMixinTest, self).setUp() createSystemData() self.transact = Transact(self.threadPool) factory = FluidinfoSessionFactory('API-9000') self.facade = Facade(self.transact, factory) UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.permissions = CachingPermissionAPI(self.user) @inlineCallbacks def testGetTagWithoutData(self): """ L{FacadeTagMixin.getTag} raises a L{TNonexistentTag} exception if the requested L{Tag.path} doesn't exist. """ self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.getTag(session, u'username/unknown', False) yield self.assertFailure(deferred, TNonexistentTag) @inlineCallbacks def testGetTag(self): """ L{FacadeTagMixin.getTag} returns a L{TTag} instance with information about the requested L{Tag}. """ result = TagAPI(self.user).create([(u'username/tag', u'description')]) [(objectID, path)] = result self.store.commit() with login(u'username', uuid4(), self.transact) as session: result = yield self.facade.getTag(session, u'username/tag', False) self.assertEqual(str(objectID), result.objectId) self.assertEqual(u'username/tag', result.path) self.assertTrue(result.indexed) @inlineCallbacks def testGetTagWithDescription(self): """ L{FacadeTagMixin.getTag} includes the L{Tag.description}, if it was requested. """ TagAPI(self.user).create([(u'username/tag', u'A tag.')]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: result = yield self.facade.getTag(session, u'username/tag', True) self.assertEqual(u'A tag.', result.description) @inlineCallbacks def testCreateTag(self): """L{FacadeTagMixin.createTag} creates a new L{Tag}.""" self.store.commit() with login(u'username', uuid4(), self.transact) as session: objectID = yield self.facade.createTag( session, u'username', u'tag', u'A tag.', 'ignored', 'ignored') self.assertNotIdentical(None, objectID) self.store.rollback() tag = getTags(paths=[u'username/tag']).one() self.assertIdentical(self.user, tag.creator) self.assertIdentical(self.user.namespace, tag.namespace) self.assertEqual(u'username/tag', tag.path) self.assertEqual(u'tag', tag.name) self.assertEqual(objectID, str(tag.objectID)) @inlineCallbacks def testCreateTagWithExistingPath(self): """ L{FacadeTagMixin.createTag} raises a L{TTagAlreadyExists} exception if the new L{Tag} already exists. """ TagAPI(self.user).create([(u'username/name', u'A tag.')]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.createTag( session, u'username', u'name', u'A tag.', 'ignored', 'ignored') yield self.assertFailure(deferred, TTagAlreadyExists) @inlineCallbacks def testCreateTagWithInvalidPath(self): """ L{FacadeTagMixin.createTag} raises a L{TInvalidPath} exception if the path of the L{Tag} is not well formed. """ self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.createTag(session, u'username', u'bad name', u'A tag.', 'ignored', 'ignored') yield self.assertFailure(deferred, TInvalidPath) @inlineCallbacks def testCreateTagWithUnknownParent(self): """ L{FacadeTagMixin.createTag} raises a L{TNonexistentTag} exception if a non-existent parent L{Tag} is specified. """ self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.createTag( session, u'unknown', u'name', u'A tag.', 'ignored', 'ignored') yield self.assertFailure(deferred, TNonexistentTag) @inlineCallbacks def testCreateIsDenied(self): """ L{Facade.createTag} raises a L{TPathPermissionDenied} exception if the user doesn't have C{CREATE} permissions on the parent L{Namespace}. """ self.permissions.set([(u'username', Operation.CREATE_NAMESPACE, Policy.CLOSED, [])]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.createTag( session, u'username', u'test', u'A tag.', 'ignored', 'ignored') yield self.assertFailure(deferred, TPathPermissionDenied) @inlineCallbacks def testUpdateTag(self): """ L{FacadeTagMixin.updateTag} updates the description for an existing L{Tag}. """ tags = TagAPI(self.user) tags.create([(u'username/name', u'A tag.')]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: yield self.facade.updateTag(session, u'username/name', u'A new description.') self.store.rollback() result = tags.get([u'username/name'], withDescriptions=True) self.assertEqual(u'A new description.', result[u'username/name']['description']) @inlineCallbacks def testUpdateTagWithUnknownPath(self): """ L{FacadeTagMixin.updateTag} raises a L{TNonexistentTag} exception if the requested L{Tag.path} doesn't exist. """ self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.updateTag(session, u'username/unknown', u'A new description.') yield self.assertFailure(deferred, TNonexistentTag) @inlineCallbacks def testUpdateIsDenied(self): """ L{Facade.updateTag} raises a L{TPathPermissionDenied} exception if the user doesn't have C{UPDATE} permissions on the specified L{Tag}. """ TagAPI(self.user).create([(u'username/test', u'A tag.')]) self.permissions.set([(u'username/test', Operation.UPDATE_TAG, Policy.CLOSED, [])]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.updateTag(session, u'username/test', u'A new description.') yield self.assertFailure(deferred, TPathPermissionDenied) @inlineCallbacks def testDeleteTag(self): """L{FacadeTagMixin.deleteTag} deletes a L{Tag}.""" tags = TagAPI(self.user) tags.create([(u'username/name', u'A tag.')]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: yield self.facade.deleteTag(session, u'username/name') self.store.rollback() self.assertEqual({}, tags.get([u'username/name'])) @inlineCallbacks def testDeleteTagWithUnknownPath(self): """ L{FacadeTagMixin.deleteTag} raises a L{TNonexistentTag} exception if the requested L{Tag.path} doesn't exist. """ self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.deleteTag(session, u'username/unknown') yield self.assertFailure(deferred, TNonexistentTag) @inlineCallbacks def testDeleteTagWithData(self): """ L{FacadeTagMixin.deleteTag} removes L{TagValue}s associated with the deleted L{Tag}. """ objectID = uuid4() TagAPI(self.user).create([(u'username/tag', u'A tag.')]) tagValues = TagValueAPI(self.user) tagValues.set({objectID: {u'username/tag': 42}}) self.store.commit() with login(u'username', uuid4(), self.transact) as session: yield self.facade.deleteTag(session, u'username/tag') self.store.rollback() self.assertEqual({}, tagValues.get(objectIDs=[objectID], paths=[u'username/tag'])) @inlineCallbacks def testDeleteIsDenied(self): """ L{Facade.deleteTag} raises a L{TPathPermissionDenied} exception if the user doesn't have C{DELETE} permissions on the specified L{Tag}. """ TagAPI(self.user).create([(u'username/test', u'A tag.')]) self.permissions.set([(u'username/test', Operation.DELETE_TAG, Policy.OPEN, [u'username'])]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.deleteTag(session, u'username/test') yield self.assertFailure(deferred, TPathPermissionDenied)
class CommentImporterTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource(format='%(message)s')), ('store', DatabaseResource())] def setUp(self): super(CommentImporterTest, self).setUp() self.system = createSystemData() UserAPI().create([(u'fluidinfo.com', u'secret', u'User', u'*****@*****.**')]) user = getUser(u'fluidinfo.com') self.objects = SecureObjectAPI(user) self.values = SecureTagValueAPI(user) def testUpload(self): """ Comments are uploaded directly to Fluidinfo. After performing an upload, all the inserted values must be present in Fluidinfo. """ when = datetime.utcnow() floatTime = timegm(when.utctimetuple()) + float(when.strftime('0.%f')) isoTime = when.isoformat() client = CommentImporter(100) client.upload([{ 'about': [u'one', u'two'], 'importer': u'fluidinfo.com', 'text': u'Here is my #wonderful comment', 'timestamp': when, 'url': u'http://twitter.com/status/9373973', 'username': u'joe' }]) about = u'fluidinfo.com joe %s' % isoTime result = self.objects.get([about]) objectID = result[about] result = self.values.get([objectID], [ u'fluidinfo.com/info/about', u'fluidinfo.com/info/text', u'fluidinfo.com/info/timestamp', u'fluidinfo.com/info/url', u'fluidinfo.com/info/username', ]) comment = result[objectID] self.assertEqual([u'one', u'two', u'#wonderful'], comment[u'fluidinfo.com/info/about'].value) self.assertEqual(u'Here is my #wonderful comment', comment[u'fluidinfo.com/info/text'].value) self.assertEqual(floatTime, comment[u'fluidinfo.com/info/timestamp'].value) self.assertEqual(u'http://twitter.com/status/9373973', comment[u'fluidinfo.com/info/url'].value) self.assertEqual(u'joe', comment[u'fluidinfo.com/info/username'].value) def testUploadWithoutAboutValues(self): """ When no explicit about values are in the uploaded comment, there must be no about values stored in Fluidinfo. """ when = datetime.utcnow() isoTime = when.isoformat() client = CommentImporter(100) client.upload([{ 'importer': u'fluidinfo.com', 'text': u'Here is my comment', 'timestamp': when, 'url': u'http://twitter.com/status/9373973', 'username': u'joe' }]) about = u'fluidinfo.com joe %s' % isoTime result = self.objects.get([about]) objectID = result[about] result = self.values.get([objectID], [u'fluidinfo.com/info/about']) comment = result[objectID] self.assertEqual([], comment[u'fluidinfo.com/info/about'].value) def testUploadMultipleComments(self): """Multiple comments are inserted in batches.""" when = datetime.utcnow() isoTime = when.isoformat() client = CommentImporter(100) client.upload([{ 'importer': u'fluidinfo.com', 'text': u'Here is my #wonderful comment', 'timestamp': when, 'url': u'http://twitter.com/status/9373973', 'username': u'joe' }, { 'importer': u'fluidinfo.com', 'text': u'A #crazy comment', 'timestamp': when, 'url': u'http://twitter.com/status/9279479379', 'username': u'mike' }]) about1 = u'fluidinfo.com joe %s' % isoTime about2 = u'fluidinfo.com mike %s' % isoTime result = self.objects.get([about1, about2]) objectID1 = result[about1] objectID2 = result[about2] comments = self.values.get([objectID1, objectID2], [u'fluidinfo.com/info/text']) comment1 = comments[objectID1] self.assertEqual(u'Here is my #wonderful comment', comment1[u'fluidinfo.com/info/text'].value) comment2 = comments[objectID2] self.assertEqual(u'A #crazy comment', comment2[u'fluidinfo.com/info/text'].value) self.assertTrue(self.log.getvalue().startswith( 'Importing 2 new comments.\nImported 2/2 new comments.\n' 'Imported 2 comments in ')) def testUploadUsesBatchSize(self): """ Comments are uploaded in batches when possible, depending on the batch size. """ when = datetime.utcnow() client = CommentImporter(1) client.upload([{ 'importer': u'fluidinfo.com', 'text': u'Here is my #wonderful comment', 'timestamp': when, 'url': u'http://twitter.com/status/9373973', 'username': u'joe' }, { 'importer': u'fluidinfo.com', 'text': u'A #crazy comment', 'timestamp': when, 'url': u'http://twitter.com/status/9279479379', 'username': u'mike' }]) self.assertTrue(self.log.getvalue().startswith( 'Importing 2 new comments.\nImported 1/2 new comments.\n' 'Imported 2/2 new comments.\nImported 2 comments in ')) def testUploadLogsMessage(self): """ Uploads must prefix log output with the passed message. """ when = datetime.utcnow() client = CommentImporter(100) client.upload([{ 'importer': u'fluidinfo.com', 'text': u'Here is my #wonderful comment', 'timestamp': when, 'url': u'http://twitter.com/status/9373973', 'username': u'joe' }], 'message-xxx') self.assertTrue(self.log.getvalue().startswith( 'message-xxx: Importing 1 new comments.\n' 'message-xxx: Imported 1/1 new comments.\n' 'message-xxx: Imported 1 comments in '))
class SecureNamespaceAPIWithNormalUserTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureNamespaceAPIWithNormalUserTest, self).setUp() createSystemData() UserAPI().create([(u'user', u'password', u'User', u'*****@*****.**') ]) self.user = getUser(u'user') self.permissions = CachingPermissionAPI(self.user) self.namespaces = SecureNamespaceAPI(self.user) def testCreateIsAllowed(self): """ L{SecureNamespaceAPI.create} should allow the creation of namespaces whose parent has open CREATE permissions. """ values = [(u'user', Operation.CREATE_NAMESPACE, Policy.OPEN, [])] self.permissions.set(values) result = self.namespaces.create([(u'user/test', u'description')]) self.assertEqual(1, len(result)) def testCreateIsDenied(self): """ L{SecureNamespaceAPI.create} should raise L{PermissonDeniedError} if the user doesn't have CREATE permissions on the parent namespace. """ values = [(u'user', Operation.CREATE_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.create, [(u'user/test', u'description')]) self.assertEqual([(u'user', Operation.CREATE_NAMESPACE)], sorted(error.pathsAndOperations)) def testDeleteIsAllowed(self): """ {SecureNamespaceAPI.delete} should allow the deletion of a namespace if the user has DELETE permissions. """ result1 = self.namespaces.create([(u'user/test', u'description')]) values = [(u'user/test', Operation.DELETE_NAMESPACE, Policy.OPEN, [])] self.permissions.set(values) result2 = self.namespaces.delete([u'user/test']) self.assertEqual(result1, result2) def testDeleteIsDenied(self): """ L{SecureNamespaceAPI.delete} should raise L{PermissonDeniedError} if the user doesn't have DELETE permissions. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user/test', Operation.DELETE_NAMESPACE, Policy.OPEN, [u'user'])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.delete, [(u'user/test')]) self.assertEqual([(u'user/test', Operation.DELETE_NAMESPACE)], sorted(error.pathsAndOperations)) def testGetChildNamespacesIsAllowed(self): """ L{SecureNamespaceAPI.get} should allow getting a list of child namespaces if the user has permissions. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user', Operation.LIST_NAMESPACE, Policy.OPEN, [])] self.permissions.set(values) result = self.namespaces.get([u'user'], withNamespaces=True) self.assertEqual(1, len(result)) def testGetChildNamespacesIsDenied(self): """ L{SecureNamespaceAPI.get} should raise L{PermissonDeniedError} if the user doesn't have LIST permissions when trying to get the child namespaces. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user', Operation.LIST_NAMESPACE, Policy.CLOSED, [])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.get, [(u'user')], withNamespaces=True) self.assertEqual([(u'user', Operation.LIST_NAMESPACE)], sorted(error.pathsAndOperations)) def testGetChildTagsIsAllowed(self): """ L{SecureNamespaceAPI.get} should allow getting a list of child tags if the user has permissions. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user', Operation.LIST_NAMESPACE, Policy.CLOSED, [u'user']) ] self.permissions.set(values) result = self.namespaces.get([u'user'], withTags=True) self.assertEqual(1, len(result)) def testGetChildTagsIsDenied(self): """ L{SecureNamespaceAPI.get} should raise L{PermissonDeniedError} if the user doesn't have LIST permissions when trying to get the child tags. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user', Operation.LIST_NAMESPACE, Policy.OPEN, [u'user'])] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.get, [(u'user')], withTags=True) self.assertEqual([(u'user', Operation.LIST_NAMESPACE)], sorted(error.pathsAndOperations)) def testSetIsAllowed(self): """ L{SecureNamespaceAPI.get} should allow updating the description of a namespace if the user has permissions. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user/test', Operation.UPDATE_NAMESPACE, Policy.OPEN, [])] self.permissions.set(values) self.namespaces.set({u'user/test': u'description'}) def testSetIsDenied(self): """ L{SecureNamespaceAPI.get} should raise L{PermissonDeniedError} if the user doesn't have UPDATE permissions when trying to update a namespace's description. """ self.namespaces.create([(u'user/test', u'description')]) values = [(u'user/test', Operation.UPDATE_NAMESPACE, Policy.CLOSED, []) ] self.permissions.set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.set, {u'user/test': u'description'}) self.assertEqual([(u'user/test', Operation.UPDATE_NAMESPACE)], sorted(error.pathsAndOperations))
class BaseCacheTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource(format='%(message)s'))] def testGetValues(self): """L{BaseCache.getValues} returns values stored in the cache.""" self.cache.set('identifier1', 'test1') self.cache.set('identifier2', 'test2') result = BaseCache().getValues([u'identifier1', u'identifier2']) self.assertEqual([u'test1', u'test2'], result) def testGetValuesWithPrefix(self): """L{BaseCache.getValues} uses the given prefix as key.""" self.cache.set('prefix:identifier1', 'test1') self.cache.set('prefix:identifier2', 'test2') cache = BaseCache() cache.keyPrefix = 'prefix:' result = cache.getValues([u'identifier1', u'identifier2']) self.assertEqual([u'test1', u'test2'], result) def testGetValuesWithUnknownValue(self): """L{BaseCache.getValues} returns L{None} for values not found.""" self.cache.set('identifier1', 'test1') result = BaseCache().getValues([u'identifier1', u'identifier2']) self.assertEqual([u'test1', None], result) def testGetValuesWithEmptyIdentifiers(self): """ L{BaseCache.getValues} returns an empty list if the list of identifiers is empty as well. """ self.assertEqual([], BaseCache().getValues([])) def testGetValuesWithError(self): """ Redis errors are ignored by L{BaseCache.getValues} and a line is written in the logs. """ cache = BaseCache() cache._client.connection_pool = ConnectionPool(port=0) result = cache.getValues([u'identifier1']) self.assertIdentical(None, result) self.assertEqual( 'Redis error: Error 111 connecting localhost:0. ' 'Connection refused.\n', self.log.getvalue()) def testSetValues(self): """L{BaseCache.setValues} sets values in the cache.""" BaseCache().setValues({'identifier1': 'test1', 'identifier2': 'test2'}) self.assertEqual('test1', self.cache.get('identifier1')) self.assertEqual('test2', self.cache.get('identifier2')) def testSetValuesWithTimeout(self): """L{BaseCache.setValues} set the expire timout of the values.""" BaseCache().setValues({'identifier1': 'test1', 'identifier2': 'test2'}) expectedTimeout = self.config.getint('cache', 'expire-timeout') self.assertAlmostEqual(expectedTimeout, self.cache.ttl('identifier1')) self.assertAlmostEqual(expectedTimeout, self.cache.ttl('identifier2')) def testSetValuesWithPrefix(self): """L{BaseCache.setValues} uses the given prefix as key.""" cache = BaseCache() cache.keyPrefix = 'prefix:' cache.setValues({'identifier1': 'test1', 'identifier2': 'test2'}) self.assertEqual('test1', self.cache.get('prefix:identifier1')) self.assertEqual('test2', self.cache.get('prefix:identifier2')) def testSetValuesWithError(self): """ Redis errors are ignored by L{BaseCache.setValues} and a line is written in the logs. """ cache = BaseCache() cache._client.connection_pool = ConnectionPool(port=0) cache.setValues({'identifier': 'test'}) self.assertEqual( 'Redis error: Error 111 connecting localhost:0. ' 'Connection refused.\n', self.log.getvalue()) def testDeleteValues(self): """L{BaseCache.deleteValues} deletes values from the cache.""" self.cache.set('identifier1', 'test1') self.cache.set('identifier2', 'test2') BaseCache().deleteValues([u'identifier1', u'identifier2']) self.assertEqual([None, None], self.cache.mget([u'identifier1', u'identifier2'])) def testDeleteValuesWithPrefix(self): """L{BaseCache.deleteValues} uses the given prefix as key.""" self.cache.set('prefix:identifier1', 'test1') self.cache.set('prefix:identifier2', 'test2') cache = BaseCache() cache.keyPrefix = 'prefix:' cache.deleteValues([u'identifier1', u'identifier2']) self.assertEqual([None, None], self.cache.mget( [u'prefix:identifier1', u'prefix:identifier2'])) def testDeleteValuesWithEmpyIdentifiers(self): """ L{BaseCache.deleteValues} doesn't show errors if an empty list of identifiers is given. """ BaseCache().deleteValues([]) self.assertEqual('', self.log.getvalue()) def testDeleteValuesWithError(self): """ Redis errors are ignored by L{BaseCache.deleteValues} and a line is written in the logs. """ cache = BaseCache() cache._client.connection_pool = ConnectionPool(port=0) cache.deleteValues(['identifier']) self.assertEqual( 'Redis error: Error 111 connecting localhost:0. ' 'Connection refused.\n', self.log.getvalue())
class VerifyUserPasswordResourceTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource()), ('store', DatabaseResource()), ('threadPool', ThreadPoolResource())] def setUp(self): super(VerifyUserPasswordResourceTest, self).setUp() self.transact = Transact(self.threadPool) createSystemData() UserAPI().create([ (u'fluidinfo.com', 'secret', u'Fluidinfo', u'*****@*****.**'), (u'user', u'pass', u'Peter Parker', u'*****@*****.**')]) consumer = getUser(u'anon') OAuthConsumerAPI().register(consumer) self.store.commit() @defer.inlineCallbacks def testPostWithCorrectPasswordReturnsCorrectKeys(self): """ A C{POST} to C{/users/user/verify} with the correct password returns a JSON object with all the expected keys, including valid = True. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.OK) result = loads(request.response) self.assertEqual( ['accessToken', 'fullname', 'renewalToken', 'role', 'valid'], sorted(result.keys())) self.assertTrue(result['valid']) @defer.inlineCallbacks def testPostWithCorrectPasswordDoesNotCauseALogWarning(self): """ A C{POST} to C{/users/user/verify} with the correct password should not cause a complaint about unknown return payload fields in the logging system. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred logOutput = self.log.getvalue() self.assertNotIn("unknown response payload field 'renewalToken'", logOutput) self.assertNotIn("unknown response payload field 'accessToken'", logOutput) @defer.inlineCallbacks def testPostWithCorrectPasswordReturnsCorrectRole(self): """ A C{POST} to C{/users/user/verify} with the correct password returns a JSON object with the correct user role. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.OK) result = loads(request.response) self.assertEqual('USER', result['role']) @defer.inlineCallbacks def testPostWithCorrectPasswordReturnsCorrectFullname(self): """ A C{POST} to C{/users/user/verify} with the correct password returns a JSON object with the user's correct full name. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.OK) result = loads(request.response) self.assertEqual(u'Peter Parker', result['fullname']) @defer.inlineCallbacks def testPostWithIncorrectPasswordReturnsFalse(self): """ A C{POST} to C{/users/user/verify} with the incorrect password returns a C{{'valid': False}} response. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.OK) self.assertEqual(loads(request.response), {'valid': False}) @defer.inlineCallbacks def testPostWithUnknownUsernameReturnsNotFound(self): """ A C{POST} to C{/users/user/verify} with an unknown username returns a 404 Not Found. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'unknown') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.NOT_FOUND) @defer.inlineCallbacks def testPostWithoutPasswordReturnsBadRequest(self): """ A C{POST} to C{/users/user/verify} without a password returns a 400 Bad Request. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = '' headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.BAD_REQUEST) @defer.inlineCallbacks def testPostWithExtraCrapInPayloadReturnsBadRequest(self): """ A C{POST} to C{/users/user/verify} with unexpected data in the payload returns a 400 Bad Request. """ with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******', 'foo': 'bar'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json'], 'X-Forwarded-Protocol': ['https']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.BAD_REQUEST) @defer.inlineCallbacks def testInsecurePostIsRejected(self): """A C{POST} via HTTP is rejected if not in development mode.""" self.config.set('service', 'development', 'false') with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = '' headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.BAD_REQUEST) self.assertEqual( request.getResponseHeader('X-FluidDB-Message'), '/users/<username>/verify requests must use HTTPS') @defer.inlineCallbacks def testInsecurePostIsNotRejectedInDevelopmentMode(self): """A C{POST} via HTTP is not rejected when in development mode.""" self.config.set('service', 'development', 'true') with login(None, None, self.transact) as session: resource = VerifyUserPasswordResource(None, session, 'user') payload = dumps({'password': '******'}) headers = {'Content-Length': [str(len(payload))], 'Content-Type': ['application/json']} request = FakeRequest(method='POST', headers=Headers(headers), body=payload) self.assertEqual(NOT_DONE_YET, resource.render(request)) yield resource.deferred self.assertEqual(request.code, http.OK)
class SecureNamespaceAPIWithAnonymousRoleTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('store', DatabaseResource())] def setUp(self): super(SecureNamespaceAPIWithAnonymousRoleTest, self).setUp() self.system = createSystemData() self.user = self.system.users[u'anon'] self.namespaces = SecureNamespaceAPI(self.user) def testCreateIsDenied(self): """ L{SecureNamespaceAPI.create} raises a L{PermissionDeniedError} if its invoked by a L{User} with the L{Role.ANONYMOUS}. """ error = self.assertRaises(PermissionDeniedError, self.namespaces.create, [(u'anon/test', u'description')]) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'anon', Operation.CREATE_NAMESPACE)], sorted(error.pathsAndOperations)) def testDeleteIsDenied(self): """ L{SecureNamespaceAPI.delete} raises a L{PermissionDeniedError} if its invoked by a L{User} with the L{Role.ANONYMOUS}. """ error = self.assertRaises(PermissionDeniedError, self.namespaces.delete, [u'anon']) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'anon', Operation.DELETE_NAMESPACE)], sorted(error.pathsAndOperations)) def testSetIsDenied(self): """ L{SecureNamespaceAPI.set} raises a L{PermissionDeniedError} if its invoked by a L{User} with the L{Role.ANONYMOUS}. """ error = self.assertRaises(PermissionDeniedError, self.namespaces.set, {u'anon': u'new description'}) self.assertEqual(self.user.username, error.username) self.assertEqual([(u'anon', Operation.UPDATE_NAMESPACE)], sorted(error.pathsAndOperations)) def testGetChildNamespacesIsAllowed(self): """ L{SecureNamespaceAPI.get} should allow getting a list of child namespaces if the I{anon} user has permissions. """ admin = self.system.users[u'fluiddb'] SecureNamespaceAPI(admin).create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb', Operation.LIST_NAMESPACE, Policy.OPEN, [])] CachingPermissionAPI(admin).set(values) result = self.namespaces.get([u'fluiddb'], withNamespaces=True) self.assertEqual(1, len(result)) def testGetChildNamespacesIsDenied(self): """ L{SecureNamespaceAPI.get} should raise L{PermissonDeniedError} if the I{anon} user doesn't have LIST permissions when trying to get the child namespaces. """ admin = self.system.users[u'fluiddb'] SecureNamespaceAPI(admin).create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb', Operation.LIST_NAMESPACE, Policy.CLOSED, [])] CachingPermissionAPI(admin).set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.get, [(u'fluiddb')], withNamespaces=True) self.assertEqual([(u'fluiddb', Operation.LIST_NAMESPACE)], sorted(error.pathsAndOperations)) def testGetChildTagsIsAllowed(self): """ L{SecureNamespaceAPI.get} should allow getting a list of child tags if the I{anon} user has permissions. """ admin = self.system.users[u'fluiddb'] SecureNamespaceAPI(admin).create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb', Operation.LIST_NAMESPACE, Policy.CLOSED, [u'anon'])] CachingPermissionAPI(admin).set(values) result = self.namespaces.get([u'fluiddb'], withTags=True) self.assertEqual(1, len(result)) def testGetChildTagsIsDenied(self): """ L{SecureNamespaceAPI.get} should raise L{PermissonDeniedError} if the L{anon} user doesn't have LIST permissions when trying to get the child tags. """ admin = self.system.users[u'fluiddb'] SecureNamespaceAPI(admin).create([(u'fluiddb/test', u'description')]) values = [(u'fluiddb', Operation.LIST_NAMESPACE, Policy.OPEN, [u'anon'])] CachingPermissionAPI(admin).set(values) error = self.assertRaises(PermissionDeniedError, self.namespaces.get, [(u'fluiddb')], withTags=True) self.assertEqual([(u'fluiddb', Operation.LIST_NAMESPACE)], sorted(error.pathsAndOperations))
class DatasetImporterTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('log', LoggingResource(format='%(message)s')), ('store', DatabaseResource())] def setUp(self): super(DatasetImporterTest, self).setUp() self.system = createSystemData() UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')]) user = getUser(u'user') self.objects = SecureObjectAPI(user) self.values = SecureTagValueAPI(user) def testUpload(self): """ Object data is converted into a format compatible with the L{TagValueAPI.set} method before being uploaded directly into Fluidinfo. """ client = DatasetImporter(100) client.upload(u'user', [{ 'about': u'hello world', 'values': { u'user/bar': 13 } }]) result = self.objects.get([u'hello world']) objectID = result[u'hello world'] result = self.values.get([objectID], [u'user/bar']) value = result[objectID][u'user/bar'] self.assertEqual(13, value.value) def testUploadMultipleObjects(self): """Multiple objects are inserted in batches.""" client = DatasetImporter(100) client.upload(u'user', [{ 'about': u'hello world', 'values': { u'user/bar': 13 } }, { 'about': u'wubble', 'values': { u'user/quux': 42 } }]) aboutValues = self.objects.get([u'hello world', u'wubble']) objectID = aboutValues[u'hello world'] result = self.values.get([objectID], [u'user/bar']) value = result[objectID][u'user/bar'] self.assertEqual(13, value.value) objectID = aboutValues[u'wubble'] result = self.values.get([objectID], [u'user/quux']) value = result[objectID][u'user/quux'] self.assertEqual(42, value.value) self.assertTrue(self.log.getvalue().startswith( 'Importing 2 new objects.\nImported 2/2 new objects.\n' 'Imported 2 objects in ')) def testUploadUsesBatchSize(self): """ Objects are uploaded in batches when possible, depending on the batch size. """ client = DatasetImporter(1) client.upload(u'user', [{ 'about': u'hello world', 'values': { u'user/bar': 13 } }, { 'about': u'wubble', 'values': { u'user/quux': 42 } }]) self.assertTrue(self.log.getvalue().startswith( 'Importing 2 new objects.\nImported 1/2 new objects.\n' 'Imported 2/2 new objects.\nImported 2 objects in ')) def testUploadWithUncreatablePath(self): """ L{DatasetImporter.upload} checks permissions when importing data. An L{UnknownPathError} is raised if a specified tag doesn't exist and the L{User} doesn't have permissions to create it. """ client = DatasetImporter(100) self.assertRaises(UnknownPathError, client.upload, u'user', [{ 'about': u'hello world', 'values': { u'foo/bar': 13 } }]) def testUploadWithPermissionViolation(self): """L{DatasetImporter.upload} checks permissions when importing data.""" UserAPI().create([(u'user1', u'pwd', u'User 1', u'*****@*****.**')]) client = DatasetImporter(100) self.assertRaises(PermissionDeniedError, client.upload, u'user', [{ 'about': u'hello world', 'values': { u'user1/bar': 13 } }]) def testUploadWithUnknownUser(self): """ L{DatasetImporter.upload} raises an L{UnknownUserError} if the specified L{User} doesn't exist. """ client = DatasetImporter(100) self.assertRaises(UnknownUserError, client.upload, u'unknown', [{ 'about': u'hello world', 'values': { u'unknown/bar': 13 } }]) def testUploadLogsMessage(self): """ Uploads must prefix log output with the passed message. """ client = DatasetImporter(100) client.upload(u'user', [{ 'about': u'hello world', 'values': { u'user/bar': 13 } }], 'message-xxx') self.assertTrue(self.log.getvalue().startswith( 'message-xxx: Importing 1 new objects.\n' 'message-xxx: Imported 1/1 new objects.\n' 'message-xxx: Imported 1 objects in '))
class ConcreteUserResourceTest(FluidinfoTestCase): resources = [('cache', CacheResource()), ('config', ConfigResource()), ('client', IndexResource()), ('log', LoggingResource()), ('store', DatabaseResource()), ('threadPool', ThreadPoolResource())] def setUp(self): super(ConcreteUserResourceTest, self).setUp() createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') factory = FluidinfoSessionFactory('API-9000') self.transact = Transact(self.threadPool) self.facade = Facade(self.transact, factory) self.store.commit() @defer.inlineCallbacks def testGET(self): """ A GET request on /users/<username> returns the complete details about the user. """ request = FakeRequest() with login(u'username', self.user.objectID, self.transact) as session: resource = ConcreteUserResource(self.facade, session, 'username') body = yield resource.deferred_render_GET(request) body = loads(body) expected = {"role": "USER", "name": "User", "id": str(self.user.objectID)} self.assertEqual(expected, body) self.assertEqual(http.OK, request.code) @defer.inlineCallbacks def testPUT(self): """ A PUT request on C{/users/<username>} updates the data for the user. """ body = dumps({'name': 'New name', 'email': '*****@*****.**', 'role': 'USER_MANAGER'}) headers = Headers({'content-length': [len(body)], 'content-type': ['application/json']}) request = FakeRequest(body=body, headers=headers) with login(u'username', self.user.objectID, self.transact) as session: resource = ConcreteUserResource(self.facade, session, 'username') yield resource.deferred_render_PUT(request) self.assertEqual(http.NO_CONTENT, request.code) body = yield resource.deferred_render_GET(FakeRequest()) body = loads(body) expected = {'role': 'USER_MANAGER', 'name': 'New name', 'id': str(self.user.objectID)} self.assertEqual(expected, body) @defer.inlineCallbacks def testPUTToUpdateRoleOnly(self): """ A PUT request on C{/users/<username>} can update only the role for the user even if other arguments are not given. """ body = dumps({'role': 'USER_MANAGER'}) headers = Headers({'content-length': [len(body)], 'content-type': ['application/json']}) request = FakeRequest(body=body, headers=headers) with login(u'username', self.user.objectID, self.transact) as session: resource = ConcreteUserResource(self.facade, session, 'username') yield resource.deferred_render_PUT(request) self.assertEqual(http.NO_CONTENT, request.code) body = yield resource.deferred_render_GET(FakeRequest()) body = loads(body) expected = {'role': 'USER_MANAGER', 'name': 'User', 'id': str(self.user.objectID)} self.assertEqual(expected, body)