Пример #1
0
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)
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
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))
Пример #5
0
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()
Пример #6
0
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)
Пример #7
0
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)
Пример #8
0
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)
Пример #9
0
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)
Пример #10
0
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')
Пример #11
0
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)
Пример #12
0
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)
Пример #13
0
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)
Пример #14
0
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'))
Пример #15
0
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)
Пример #16
0
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)
Пример #17
0
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))
Пример #18
0
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)
Пример #19
0
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')))
Пример #20
0
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)
Пример #21
0
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))
Пример #22
0
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)
Пример #23
0
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)
Пример #24
0
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 '))
Пример #25
0
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))
Пример #26
0
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())
Пример #27
0
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)
Пример #28
0
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))
Пример #29
0
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 '))
Пример #30
0
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)