示例#1
0
 def setUp(self):
     super(FacadeUserMixinTest, self).setUp()
     self.transact = Transact(self.threadPool)
     factory = FluidinfoSessionFactory('API-9000')
     self.facade = Facade(self.transact, factory)
     system = createSystemData()
     self.admin = system.users[u'fluiddb']
示例#2
0
 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)
示例#3
0
 def setUp(self):
     super(FacadePermissionTest, self).setUp()
     self.transact = Transact(FakeThreadPool())
     factory = FluidinfoSessionFactory('API-9000')
     self.facade = Facade(self.transact, factory)
     createSystemData()
     UserAPI().create([(u'username', u'password', u'User',
                        u'*****@*****.**')])
     user = getUser(u'username')
     self.permissions = CachingPermissionAPI(user)
     SecureTagAPI(user).create([(u'username/tag', u'description')])
示例#4
0
class FacadeTest(FluidinfoTestCase):
    """
    Simple tests of L{Facade} functionality that are not to do with user
    creation or authentication.
    """

    resources = [('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeTest, self).setUp()
        factory = FluidinfoSessionFactory('API-9000')
        self.transact = Transact(self.threadPool)
        self.facade = Facade(self.transact, factory)
        self.system = createSystemData()

    @inlineCallbacks
    def testCreateAnonymousSession(self):
        """
        L{FacadeAuthMixin.createAnonymousSession} creates a
        L{FluidinfoSession} for the anonymous user C{anon} so that anonymous
        requests coming from the C{WSFE} can be correctly verified by the
        L{Facade}.
        """
        anon = self.system.users[u'anon']
        self.store.commit()

        session = yield self.facade.createAnonymousSession()
        self.assertEqual('anon', session.auth.username)
        self.assertEqual(anon.objectID, session.auth.objectID)
示例#5
0
 def setUp(self):
     super(FacadeUserMixinTest, self).setUp()
     self.transact = Transact(self.threadPool)
     factory = FluidinfoSessionFactory('API-9000')
     self.facade = Facade(self.transact, factory)
     system = createSystemData()
     self.admin = system.users[u'fluiddb']
示例#6
0
 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)
示例#7
0
 def setUp(self):
     super(RootResourceTest, self).setUp()
     factory = FluidinfoSessionFactory('API-9000')
     transact = Transact(self.threadPool)
     createSystemData()
     self.checker = AnonymousChecker()
     self.checker.facadeClient = Facade(transact, factory)
     getConfig().set('service', 'allow-anonymous-access', 'False')
示例#8
0
 def setUp(self):
     super(RecentObjectsActivityResourceTest, 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)
示例#9
0
 def setUp(self):
     super(FacadeNamespaceTest, 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 = PermissionAPI(self.user)
示例#10
0
def setupFacade(config):
    """Get the L{Facade} instance to use in the API service."""
    from fluiddb.api.facade import Facade
    from fluiddb.util.transact import Transact

    maxThreads = int(config.get('service', 'max-threads'))
    threadpool = ThreadPool(minthreads=0, maxthreads=maxThreads)
    reactor.callWhenRunning(threadpool.start)
    reactor.addSystemEventTrigger('during', 'shutdown', threadpool.stop)
    transact = Transact(threadpool)
    factory = FluidinfoSessionFactory('API-%s' % config.get('service', 'port'))
    return Facade(transact, factory)
示例#11
0
class FacadeRecentActivityMixinTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()),
                 ('client', IndexResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeRecentActivityMixinTest, self).setUp()
        self.system = 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 testGetRecentObjectActivity(self):
        """
        L{FacadeRecentActivityMixin.getRecentObjectActivity} returns a C{dict}
        with information about the recent tag values on the given object.
        """
        tagValues = TagValueAPI(self.user)
        objectID1 = ObjectAPI(self.user).create(u'object1')
        objectID2 = uuid4()

        # Use commit() frequently to have different timestamps on each value.
        self.store.commit()
        tagValues.set({objectID1: {u'user/tag1': u'A'}})
        self.store.commit()
        tagValues.set({objectID1: {u'user/tag2': u'B'}})
        self.store.commit()
        tagValues.set({objectID2: {u'user/tag1': u'C'}})
        self.store.commit()
        tagValues.set({objectID2: {u'user/tag2': u'D'}})
        self.store.commit()
        tagValues.set({uuid4(): {u'user/tag1': u'E'}})
        self.store.commit()
        tagValues.set({uuid4(): {u'user/tag2': u'F'}})
        self.store.commit()

        expected = [
            {'tag': u'user/tag2',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'B',
             'username': u'username'},

            {'tag': u'user/tag1',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'A',
             'username': u'username'},

            {'tag': u'fluiddb/about',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'object1',
             'username': u'fluiddb'}]

        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentObjectActivity(
                session, str(objectID1))

            # Remove the creation times from the result.
            for item in result:
                del item['updated-at']

            self.assertEqual(expected, result)

    @inlineCallbacks
    def testGetRecentAboutActivity(self):
        """
        L{FacadeRecentActivityMixin.getRecentAboutActivity} returns a C{dict}
        with information about the recent tag values on the given object.
        """
        tagValues = TagValueAPI(self.user)
        objectID1 = ObjectAPI(self.user).create(u'object1')
        objectID2 = uuid4()

        # Use commit() frequently to have different timestamps on each value.
        self.store.commit()
        tagValues.set({objectID1: {u'user/tag1': u'A'}})
        self.store.commit()
        tagValues.set({objectID1: {u'user/tag2': u'B'}})
        self.store.commit()
        tagValues.set({objectID2: {u'user/tag1': u'C'}})
        self.store.commit()
        tagValues.set({objectID2: {u'user/tag2': u'D'}})
        self.store.commit()
        tagValues.set({uuid4(): {u'user/tag1': u'E'}})
        self.store.commit()
        tagValues.set({uuid4(): {u'user/tag2': u'F'}})
        self.store.commit()

        expected = [
            {'tag': u'user/tag2',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'B',
             'username': u'username'},

            {'tag': u'user/tag1',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'A',
             'username': u'username'},

            {'tag': u'fluiddb/about',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'object1',
             'username': u'fluiddb'}]

        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentAboutActivity(
                session, 'object1')

            # Remove the creation times from the result.
            for item in result:
                del item['updated-at']

            self.assertEqual(expected, result)

    @inlineCallbacks
    def testGetRecentAboutActivityWithUnkownAboutValue(self):
        """
        L{FacadeRecentActivityMixin.getRecentAboutActivity} returns an empty
        C{list} if the about value doesn't exist.
        """
        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentAboutActivity(session,
                                                              'unknown')
            self.assertEqual([], result)

    @inlineCallbacks
    def testGetRecentUserActivity(self):
        """
        L{FacadeRecentActivityMixin.getRecentUserActivity} returns a C{dict}
        with information about the recent tag values on the given user.
        """
        tagValues = TagValueAPI(self.user)
        objectID1 = ObjectAPI(self.user).create(u'object1')
        objectID2 = uuid4()

        # Use commit() frequently to have different timestamps on each value.
        self.store.commit()
        tagValues.set({objectID1: {u'user/tag1': u'A'}})
        self.store.commit()
        tagValues.set({objectID1: {u'user/tag2': u'B'}})
        self.store.commit()

        UserAPI().create([(u'user2', u'secret', u'User', u'*****@*****.**')])
        tagValues = TagValueAPI(getUser(u'user2'))

        tagValues.set({objectID1: {u'user2/tag1': u'C'}})
        self.store.commit()
        tagValues.set({objectID2: {u'user2/tag2': u'D'}})
        self.store.commit()

        UserAPI().create([(u'user3', u'secret', u'User', u'*****@*****.**')])
        tagValues = TagValueAPI(getUser(u'user3'))

        tagValues.set({objectID1: {u'user3/tag1': u'C'}})
        self.store.commit()
        tagValues.set({objectID2: {u'user3/tag2': u'D'}})
        self.store.commit()

        expected = [
            {'tag': u'user/tag2',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'B',
             'username': u'username'},

            {'tag': u'user/tag1',
             'id': str(objectID1),
             'about': u'object1',
             'value': u'A',
             'username': u'username'}]

        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentUserActivity(
                session, self.user.username.encode('utf-8'))
            # Remove the creation times from the result.
            for item in result:
                del item['updated-at']
            self.assertEqual(expected, result)

    @inlineCallbacks
    def testGetRecentUserActivityWithUnkownUser(self):
        """
        L{FacadeRecentActivityMixin.getRecentUserActivity} raises
        L{TNoSuchUser} if the given user doesn't exist.
        """
        with login(self.user.username, uuid4(), self.transact) as session:
            result = self.facade.getRecentUserActivity(session, 'unknown')
            yield self.assertFailure(result, TNoSuchUser)

    @inlineCallbacks
    def testGetRecentActivityForQuery(self):
        """
        L{FacadeRecentActivityMixin.getRecentActivityForQuery} returns a
        C{dict} with information about the recent tag values on the objects
        returned by the given query.
        """
        tagValues = TagValueAPI(self.user)
        objectID1 = ObjectAPI(self.user).create(u'object1')

        # Use commit() frequently to have different timestamps on each value.
        self.store.commit()
        tagValues.set({objectID1: {u'user/following': u'A'}})
        self.store.commit()

        runDataImportHandler(self.client.url)

        expected = [{'about': u'object1',
                     'id': str(objectID1),
                     'tag': u'user/following',
                     'username': u'username',
                     'value': u'A'},
                    {'about': u'object1',
                     'id': str(objectID1),
                     'tag': u'fluiddb/about',
                     'username': u'fluiddb',
                     'value': u'object1'}]

        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentActivityForQuery(
                session, u'has user/following')

            # Remove the creation times from the result.
            for item in result:
                del item['updated-at']

            self.assertEqual(expected, result)

    @inlineCallbacks
    def testGetRecentActivityForQueryWithBadQuery(self):
        """
        L{FacadeRecentActivityMixin.getRecentActivityForQuery} raises
        L{TParseError} if the given query can't be parsed.
        """
        with login(self.user.username, uuid4(), self.transact) as session:
            result = self.facade.getRecentActivityForQuery(session, 'bad')
            yield self.assertFailure(result, TParseError)

    @inlineCallbacks
    def testGetRecentActivityForQueryWithIllegalQuery(self):
        """
        L{FacadeRecentActivityMixin.getRecentActivityForQuery} raises
        L{TBadRequest} if the given query contains illegal sub queries.
        """
        with login(self.user.username, uuid4(), self.transact) as session:
            result = self.facade.getRecentActivityForQuery(
                session, 'has fluiddb/about')
            yield self.assertFailure(result, TBadRequest)

    @inlineCallbacks
    def testGetRecentUserActivityForQuery(self):
        """
        L{FacadeRecentActivityMixin.getRecentUserActivityForQuery} returns a
        C{dict} with information about the recent tag values by the users whose
        objects are returned by the given query.
        """
        UserAPI().create([(u'user2', u'password', u'User',
                           u'*****@*****.**')])
        user2 = getUser(u'user2')

        objectID1 = uuid4()

        # Use commit() frequently to have different timestamps on each value.
        TagValueAPI(self.user).set({objectID1: {u'username/test': u'A'}})
        self.store.commit()
        TagValueAPI(user2).set({objectID1: {u'user2/test': u'B'}})
        self.store.commit()

        runDataImportHandler(self.client.url)

        expected = [{'about': None,
                     'id': str(objectID1),
                     'tag': u'user2/test',
                     'username': u'user2',
                     'value': u'B'},
                    {'about': None,
                     'id': str(objectID1),
                     'tag': u'username/test',
                     'username': u'username',
                     'value': u'A'}]

        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentUserActivityForQuery(
                session,
                u'fluiddb/users/username = "******" '
                'OR fluiddb/users/username = "******"')

            # Remove the creation times from the result.
            for item in result:
                del item['updated-at']

            self.assertEqual(expected, result)

    @inlineCallbacks
    def testGetRecentUserActivityForQueryWithBadQuery(self):
        """
        L{FacadeRecentActivityMixin.getRecentUserActivityForQuery} raises
        L{TParseError} if the given query can't be parsed.
        """
        with login(self.user.username, uuid4(), self.transact) as session:
            result = self.facade.getRecentUserActivityForQuery(session, 'bad')
            yield self.assertFailure(result, TParseError)

    @inlineCallbacks
    def testGetRecentUserActivityForQueryWithIllegalQuery(self):
        """
        L{FacadeRecentActivityMixin.getRecentUserActivityForQuery} raises
        L{TBadRequest} if the given query contains illegal sub queries.
        """
        with login(self.user.username, uuid4(), self.transact) as session:
            result = self.facade.getRecentUserActivityForQuery(
                session, 'has fluiddb/about')
            yield self.assertFailure(result, TBadRequest)

    @inlineCallbacks
    def testGetRecentUserActivityForQueryWithObjectsNotUsers(self):
        """
        L{FacadeRecentActivityMixin.getRecentUserActivityForQuery} returns an
        empty result if the objects returned by the query are not users.
        """
        tagValues = TagValueAPI(self.user)
        objectID1 = ObjectAPI(self.user).create(u'object1')

        # Use commit() frequently to have different timestamps on each value.
        self.store.commit()
        tagValues.set({objectID1: {u'user/following': u'A'}})
        self.store.commit()

        runDataImportHandler(self.client.url)

        with login(self.user.username, uuid4(), self.transact) as session:
            result = yield self.facade.getRecentUserActivityForQuery(
                session, u'has user/following')

            # Remove the creation times from the result.
            for item in result:
                del item['updated-at']

            self.assertEqual([], result)
示例#12
0
 def setUp(self):
     super(FacadeUserCreationTest, self).setUp()
     factory = FluidinfoSessionFactory('API-9000')
     self.transact = Transact(self.threadPool)
     self.facade = Facade(self.transact, factory)
     self.system = createSystemData()
示例#13
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)
示例#14
0
class FacadeObjectMixinTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeObjectMixinTest, self).setUp()
        self.system = 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 testCreateObjectPermissionDenied(self):
        """
        L{FacadeObjectMixin.createObject} raises a
        L{TUnauthorized} exception if the user is the anonymous user.
        """
        self.store.commit()

        with login(u'anon', uuid4(), self.transact) as session:
            deferred = self.facade.createObject(session)
            yield self.assertFailure(deferred, TUnauthorized)

    @inlineCallbacks
    def testCreateObjectWithoutAboutValue(self):
        """
        L{FacadeObjectAPI.createObject} always returns a valid C{UUID} in a
        C{str} for a new object ID if an about value is not given.
        """
        self.store.commit()

        with login(u'username', uuid4(), self.transact) as session:
            objectID = yield self.facade.createObject(session)
            self.assertEqual(objectID, str(UUID(objectID)))

    @inlineCallbacks
    def testCreateObjectWithAboutValue(self):
        """
        L{FacadeObjectAPI.createObject} always returns a valid C{UUID} in a
        C{str} for a new object ID if an about value is given and it doesn't
        already exist.
        """
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectID = yield self.facade.createObject(session, about='foo')
            objectID = UUID(objectID)

        self.store.rollback()
        value = getAboutTagValues([objectID], [u'foo']).one()
        self.assertEqual(u'foo', value.value)

        tag = self.system.tags[u'fluiddb/about']
        value = getTagValues(values=[(objectID, tag.id)]).one()
        self.assertIdentical(self.system.users[u'fluiddb'], value.creator)

    @inlineCallbacks
    def testCreateObjectWithDuplicateAboutValue(self):
        """
        L{FacadeObjectAPI.createObject} returns a valid C{UUID} in a C{str} for
        an existing object ID if an about value is given and already exists in
        the database.
        """
        objectID = uuid4()
        createAboutTagValue(objectID, u'bar')
        values = {objectID: {u'fluiddb/about': u'bar'}}
        SecureTagValueAPI(self.system.superuser).set(values)
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            resultObjectID = yield self.facade.createObject(session,
                                                            about='bar')
            self.assertEqual(str(objectID), resultObjectID)

    @inlineCallbacks
    def testGetObject(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE}.
        """
        objectID = uuid4()
        SecureTagAPI(self.user).create([(u'username/foo', u'A description')])
        values = {objectID: {u'username/foo': u'bar'}}
        SecureTagValueAPI(self.user).set(values)
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID))
            self.assertEqual([u'username/foo'], objectInfo.tagPaths)
            self.assertEqual(None, objectInfo.about)

    @inlineCallbacks
    def testGetObjectWithAboutValue(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE},
        and the L{AboutTagValue.value} if it has one and C{showAbout} is
        C{True}.
        """
        objectID = uuid4()
        SecureTagAPI(self.user).create([(u'username/foo', u'A description')])
        values = {objectID: {u'username/foo': u'bar'}}
        SecureTagValueAPI(self.user).set(values)
        aboutTag = self.system.tags[u'fluiddb/about']
        createAboutTagValue(objectID, u'bar')
        createTagValue(self.user.id, aboutTag.id, objectID, u'about value')
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID),
                                                     showAbout=True)
            self.assertEqual([u'fluiddb/about', u'username/foo'],
                             sorted(objectInfo.tagPaths))
            self.assertEqual('about value', objectInfo.about)

    @inlineCallbacks
    def testGetObjectWithAboutValueDoesNotExist(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE},
        and the L{AboutTagValue.value} if it has one and C{showAbout} is
        C{True}.
        """
        objectID = uuid4()
        tag = createTag(self.user, self.user.namespace, u'foo')
        createTagPermission(tag)
        createTagValue(self.user.id, tag.id, objectID, u'bar')
        session = AuthenticatedSession(self.user.username, uuid4())
        self.store.commit()
        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID),
                                                     showAbout=True)
            self.assertEqual([u'username/foo'], objectInfo.tagPaths)
            self.assertIdentical(None, objectInfo.about)

    @inlineCallbacks
    def testGetObjectDeniedPaths(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE}.
        """
        SecureTagAPI(self.user).create([(u'username/tag1', u'description'),
                                        (u'username/tag2', u'description')])
        objectID = uuid4()
        values = {objectID: {u'username/tag1': 16},
                  objectID: {u'username/tag2': 16}}
        SecureTagValueAPI(self.user).set(values)
        self.permissions.set([(u'username/tag1', Operation.READ_TAG_VALUE,
                               Policy.CLOSED, []),
                              (u'username/tag2', Operation.READ_TAG_VALUE,
                               Policy.OPEN, [])])
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID))
            self.assertEqual([u'username/tag2'], objectInfo.tagPaths)
            self.assertEqual(None, objectInfo.about)

    @inlineCallbacks
    def testGetObjectAllPathsAreDenied(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE}, if
        all of them are denied, L{FacadeObjectAPI.getObject} must return an
        empty L{TObjectInfo}.
        """
        SecureTagAPI(self.user).create([(u'username/tag1', u'description'),
                                        (u'username/tag2', u'description')])
        objectID = uuid4()
        values = {objectID: {u'username/tag1': 16},
                  objectID: {u'username/tag2': 16}}
        SecureTagValueAPI(self.user).set(values)
        self.permissions.set([(u'username/tag1', Operation.READ_TAG_VALUE,
                               Policy.CLOSED, []),
                              (u'username/tag2', Operation.READ_TAG_VALUE,
                               Policy.CLOSED, [])])
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID))
            self.assertEqual([], objectInfo.tagPaths)
            self.assertEqual(None, objectInfo.about)
示例#15
0
class FacadeAuthenticateUserWithPasswordTest(FluidinfoTestCase):
    """Test L{Facade} user+password authentication."""

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeAuthenticateUserWithPasswordTest, self).setUp()
        factory = FluidinfoSessionFactory('API-9000')
        self.transact = Transact(self.threadPool)
        self.facade = Facade(self.transact, factory)
        self.system = createSystemData()

    @inlineCallbacks
    def testAuthenticateUserWithPassword(self):
        """
        L{FacadeAuthMixin.authenticateUserWithPassword} 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()

        session = yield self.facade.authenticateUserWithPassword('user',
                                                                 'pass')

        self.assertEqual('user', session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    @inlineCallbacks
    def testAuthenticateUserWithPasswordIgnoresCase(self):
        """
        L{FacadeAuthMixin.authenticateUserWithPassword} ignores case for the
        the username.
        """
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        self.store.commit()

        session = yield self.facade.authenticateUserWithPassword('UsEr',
                                                                 'secret')

        self.assertEqual('user', session.auth.username)

    @inlineCallbacks
    def testAuthenticateUserWithPasswordUnicodeUsername(self):
        """
        L{FacadeAuthMixin.authenticateUserWithPassword} will accept UTF-8
        encoded C{str}s for the username and the password, and convert them to
        C{unicode} appropiately.
        """
        username = u'\N{HIRAGANA LETTER A}'
        password = u'\N{HIRAGANA LETTER E}'
        fullname = u'\N{HIRAGANA LETTER I}'
        email = u'*****@*****.**'
        user = createUser(username, password, fullname, email)
        self.store.commit()

        session = yield self.facade.authenticateUserWithPassword(
            username.encode('utf-8'), password.encode('utf-8'))
        self.assertEqual(username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    def testAuthenticateUserWithPasswordIncorrectPassword(self):
        """
        L{FacadeAuthMixin.authenticateUserWithPassword} raises a
        L{TPasswordIncorrect} exception if the provided password doesn't match
        the L{User}'s.
        """
        createUser(u'username', u'password', u'User', u'*****@*****.**')
        self.store.commit()

        deferred = self.facade.authenticateUserWithPassword('username',
                                                            'bad-password')
        return self.assertFailure(deferred, TPasswordIncorrect)

    def testAuthenticateUserWithPasswordUnknownUser(self):
        """
        L{FacadeAuthMixin.authenticateUserWithPassword} raises a
        L{TNoSuchUser} exception if the provided username doesn't exist in the
        database.
        """
        self.store.commit()
        deferred = self.facade.authenticateUserWithPassword('unknown', 'pwd')
        return self.assertFailure(deferred, TNoSuchUser)

    @inlineCallbacks
    def testAuthenticateUserWithPasswordStopsSessionOnError(self):
        """
        L{FacadeAuthMixin.authenticateUserWithPassword} stops the session if an
        authentication error occurs, preventing memory leaks.
        """
        self.store.commit()

        # We monkeypatch the Session.close method to know if it was called.
        oldStop = Session.stop

        def stopWrapper(*args, **kwargs):
            self.sessionStopped = True
            return oldStop(*args, **kwargs)
        Session.stop = stopWrapper

        self.sessionStopped = False
        deferred = self.facade.authenticateUserWithPassword('unknown', 'pwd')
        yield self.assertFailure(deferred, TNoSuchUser)
        self.assertTrue(self.sessionStopped)

        self.sessionStopped = False
        deferred = self.facade.authenticateUserWithPassword('username', 'bad')
        yield self.assertFailure(deferred, TNoSuchUser)
        self.assertTrue(self.sessionStopped)

        Session.stop = oldStop
示例#16
0
class FacadeObjectMixinTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()), ('config', ConfigResource()),
                 ('log', LoggingResource()), ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeObjectMixinTest, self).setUp()
        self.system = 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 testCreateObjectPermissionDenied(self):
        """
        L{FacadeObjectMixin.createObject} raises a
        L{TUnauthorized} exception if the user is the anonymous user.
        """
        self.store.commit()

        with login(u'anon', uuid4(), self.transact) as session:
            deferred = self.facade.createObject(session)
            yield self.assertFailure(deferred, TUnauthorized)

    @inlineCallbacks
    def testCreateObjectWithoutAboutValue(self):
        """
        L{FacadeObjectAPI.createObject} always returns a valid C{UUID} in a
        C{str} for a new object ID if an about value is not given.
        """
        self.store.commit()

        with login(u'username', uuid4(), self.transact) as session:
            objectID = yield self.facade.createObject(session)
            self.assertEqual(objectID, str(UUID(objectID)))

    @inlineCallbacks
    def testCreateObjectWithAboutValue(self):
        """
        L{FacadeObjectAPI.createObject} always returns a valid C{UUID} in a
        C{str} for a new object ID if an about value is given and it doesn't
        already exist.
        """
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectID = yield self.facade.createObject(session, about='foo')
            objectID = UUID(objectID)

        self.store.rollback()
        value = getAboutTagValues([objectID], [u'foo']).one()
        self.assertEqual(u'foo', value.value)

        tag = self.system.tags[u'fluiddb/about']
        value = getTagValues(values=[(objectID, tag.id)]).one()
        self.assertIdentical(self.system.users[u'fluiddb'], value.creator)

    @inlineCallbacks
    def testCreateObjectWithDuplicateAboutValue(self):
        """
        L{FacadeObjectAPI.createObject} returns a valid C{UUID} in a C{str} for
        an existing object ID if an about value is given and already exists in
        the database.
        """
        objectID = uuid4()
        createAboutTagValue(objectID, u'bar')
        values = {objectID: {u'fluiddb/about': u'bar'}}
        SecureTagValueAPI(self.system.superuser).set(values)
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            resultObjectID = yield self.facade.createObject(session,
                                                            about='bar')
            self.assertEqual(str(objectID), resultObjectID)

    @inlineCallbacks
    def testGetObject(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE}.
        """
        objectID = uuid4()
        SecureTagAPI(self.user).create([(u'username/foo', u'A description')])
        values = {objectID: {u'username/foo': u'bar'}}
        SecureTagValueAPI(self.user).set(values)
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID))
            self.assertEqual([u'username/foo'], objectInfo.tagPaths)
            self.assertEqual(None, objectInfo.about)

    @inlineCallbacks
    def testGetObjectWithAboutValue(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE},
        and the L{AboutTagValue.value} if it has one and C{showAbout} is
        C{True}.
        """
        objectID = uuid4()
        SecureTagAPI(self.user).create([(u'username/foo', u'A description')])
        values = {objectID: {u'username/foo': u'bar'}}
        SecureTagValueAPI(self.user).set(values)
        aboutTag = self.system.tags[u'fluiddb/about']
        createAboutTagValue(objectID, u'bar')
        createTagValue(self.user.id, aboutTag.id, objectID, u'about value')
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session,
                                                     str(objectID),
                                                     showAbout=True)
            self.assertEqual([u'fluiddb/about', u'username/foo'],
                             sorted(objectInfo.tagPaths))
            self.assertEqual('about value', objectInfo.about)

    @inlineCallbacks
    def testGetObjectWithAboutValueDoesNotExist(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE},
        and the L{AboutTagValue.value} if it has one and C{showAbout} is
        C{True}.
        """
        objectID = uuid4()
        tag = createTag(self.user, self.user.namespace, u'foo')
        createTagPermission(tag)
        createTagValue(self.user.id, tag.id, objectID, u'bar')
        session = AuthenticatedSession(self.user.username, uuid4())
        self.store.commit()
        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session,
                                                     str(objectID),
                                                     showAbout=True)
            self.assertEqual([u'username/foo'], objectInfo.tagPaths)
            self.assertIdentical(None, objectInfo.about)

    @inlineCallbacks
    def testGetObjectDeniedPaths(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE}.
        """
        SecureTagAPI(self.user).create([(u'username/tag1', u'description'),
                                        (u'username/tag2', u'description')])
        objectID = uuid4()
        values = {
            objectID: {
                u'username/tag1': 16
            },
            objectID: {
                u'username/tag2': 16
            }
        }
        SecureTagValueAPI(self.user).set(values)
        self.permissions.set([
            (u'username/tag1', Operation.READ_TAG_VALUE, Policy.CLOSED, []),
            (u'username/tag2', Operation.READ_TAG_VALUE, Policy.OPEN, [])
        ])
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID))
            self.assertEqual([u'username/tag2'], objectInfo.tagPaths)
            self.assertEqual(None, objectInfo.about)

    @inlineCallbacks
    def testGetObjectAllPathsAreDenied(self):
        """
        L{FacadeObjectAPI.getObject} returns a L{TObjectInfo} with the
        L{Tag.path}s for which the L{User} has L{Operation.READ_TAG_VALUE}, if
        all of them are denied, L{FacadeObjectAPI.getObject} must return an
        empty L{TObjectInfo}.
        """
        SecureTagAPI(self.user).create([(u'username/tag1', u'description'),
                                        (u'username/tag2', u'description')])
        objectID = uuid4()
        values = {
            objectID: {
                u'username/tag1': 16
            },
            objectID: {
                u'username/tag2': 16
            }
        }
        SecureTagValueAPI(self.user).set(values)
        self.permissions.set([
            (u'username/tag1', Operation.READ_TAG_VALUE, Policy.CLOSED, []),
            (u'username/tag2', Operation.READ_TAG_VALUE, Policy.CLOSED, [])
        ])
        self.store.commit()

        with login(self.user.username, uuid4(), self.transact) as session:
            objectInfo = yield self.facade.getObject(session, str(objectID))
            self.assertEqual([], objectInfo.tagPaths)
            self.assertEqual(None, objectInfo.about)
示例#17
0
class FacadeUserMixinTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeUserMixinTest, self).setUp()
        self.transact = Transact(self.threadPool)
        factory = FluidinfoSessionFactory('API-9000')
        self.facade = Facade(self.transact, factory)
        system = createSystemData()
        self.admin = system.users[u'fluiddb']

    @inlineCallbacks
    def testGetUserWithoutData(self):
        """
        L{FacadeUserMixin.getUser} raises a L{TNoSuchUser} exception if the
        requested L{User.username} doesn't exist.
        """
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.getUser(session, u'unknown')
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'unknown', error.name)

    @inlineCallbacks
    def testGetUser(self):
        """
        L{FacadeUserMixin.getUser} returns a L{TUser} instance with
        information about the requested L{User}.
        """
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        user = getUser(u'user')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            result = yield self.facade.getUser(session, u'user')
            self.assertEqual(u'user', result.username)
            self.assertEqual(str(user.objectID), result.objectId)
            self.assertEqual(u'User', result.name)
            self.assertEqual(u'USER', result.role)

    @inlineCallbacks
    def testGetUserIgnoresCase(self):
        """L{FacadeUserMixin.getUser} ignores case for the username."""
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            result = yield self.facade.getUser(session, u'uSeR')
            self.assertEqual(u'user', result.username)

    @inlineCallbacks
    def testUpdateUser(self):
        """
        L{FacadeUserMixin.updateUser} updates the description for an existing
        L{User}.
        """
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'test')
        passwordHash = user.passwordHash
        self.store.commit()
        info = TUserUpdate(u'test', u'password', u'new-name',
                           u'*****@*****.**')
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'test', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)

    @inlineCallbacks
    def testUpdateUserWithoutPassword(self):
        """
        If a L{User.password} is not passed to L{FacadeUserMixin.updateUser}
        the existing password will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', None, u'new-name', u'*****@*****.**',
                           'USER_MANAGER')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER_MANAGER, user.role)

    @inlineCallbacks
    def testUpdateUserWithoutName(self):
        """
        If a L{User.fullname} is not passed to L{FacadeUserMixin.updateUser}
        the existing name will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', u's3cr3t', None, u'*****@*****.**',
                           'USER_MANAGER')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER_MANAGER, user.role)

    @inlineCallbacks
    def testUpdateUserWithoutEmail(self):
        """
        If a L{User.email} is not passed to L{FacadeUserMixin.updateUser}
        the existing email address will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', u's3cr3t', u'new-name', None,
                           'USER_MANAGER')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER_MANAGER, user.role)

    @inlineCallbacks
    def testUpdateUserWithoutRole(self):
        """
        If a L{User.role} is not passed to L{FacadeUserMixin.updateUser}
        the existing user role will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', u's3cr3t', u'new-name', '*****@*****.**',
                           None)
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER, user.role)

    @inlineCallbacks
    def testUpdateUserWithBadRole(self):
        """
        If an invalid L{User.role} is passed to L{FacadeUserMixin.updateUser}
        a L{TBadRequest} exception is raised.
        """
        info = TUserUpdate(u'user', u's3cr3t', u'new-name', '*****@*****.**',
                           'BAD_ROLE')
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.updateUser(session, info)
            yield self.assertFailure(deferred, TBadRequest)

    @inlineCallbacks
    def testUpdateUserIgnoresCase(self):
        """
        L{FacadeUserMixin.updateUser} ignores case when updating a new user.
        """
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'test')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'TesT', u'password', u'new-name',
                           u'*****@*****.**')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'test', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)

    @inlineCallbacks
    def testUpdateUserWithUnknownUsername(self):
        """
        L{FacadeUserMixin.updateUser} raises a L{TNoSuchUser} exception
        if the requested L{User.username} doesn't exist.
        """
        info = TUserUpdate(u'unknown', u'password', u'name',
                           u'*****@*****.**')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.updateUser(session, info)
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'unknown', error.name)

    @inlineCallbacks
    def testUpdateUserIsDenied(self):
        """
        L{FacadeUserMixin.updateUser} raises a L{TPathPermissionDenied}
        exception if the user making the request is not a superuser.
        """
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        info = TUserUpdate(u'username', u'secret', u'Username',
                           u'*****@*****.**')
        self.store.commit()
        with login(u'user', uuid4(), self.transact) as session:
            deferred = self.facade.updateUser(session, info)
            error = yield self.assertFailure(deferred, TPathPermissionDenied)
            self.assertEqual(u'username', error.path)

    @inlineCallbacks
    def testDeleteUser(self):
        """L{FacadeUserMixin.deleteUser} deletes a L{User}."""
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')],
                         createPrivateNamespace=False)
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.deleteUser(session, u'test')

        self.store.rollback()
        self.assertIdentical(None, getUser(u'test'))

    @inlineCallbacks
    def testDeleteUserIgnoresCase(self):
        """
        L{FacadeUserMixin.deleteUser} ignores case for the username when
        deleting a user.
        """
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')],
                         createPrivateNamespace=False)
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.deleteUser(session, u'tESt')

        self.store.rollback()
        self.assertIdentical(None, getUser(u'test'))

    @inlineCallbacks
    def testDeleteUserWithUnknownUsername(self):
        """
        L{FacadeUserMixin.deleteUser} raises a L{TNoSuchUser} exception if the
        specified L{User.username} doesn't exist.
        """
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.deleteUser(session, u'unknown')
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'unknown', error.name)

    @inlineCallbacks
    def testDeleteUserIsDenied(self):
        """
        L{FacadeUserMixin.deleteUser} raises a L{TPathPermissionDenied}
        exception if the user making the request is not a superuser.
        """
        [(objectID, username)] = UserAPI().create(
            [(u'user', u'secret', u'User', u'*****@*****.**')])
        self.store.commit()
        with login(u'user', objectID, self.transact) as session:
            deferred = self.facade.deleteUser(session, u'doomed')
            error = yield self.assertFailure(deferred, TPathPermissionDenied)
            self.assertEqual(u'doomed', error.path)
示例#18
0
 def setUp(self):
     super(FacadeAuthenticateUserWithPasswordTest, self).setUp()
     factory = FluidinfoSessionFactory('API-9000')
     self.transact = Transact(self.threadPool)
     self.facade = Facade(self.transact, factory)
     self.system = createSystemData()
示例#19
0
class FacadeAuthenticateUserWithOAuthTest(FluidinfoTestCase):
    """Test L{Facade} OAuth authentication."""

    resources = [('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeAuthenticateUserWithOAuthTest, self).setUp()
        factory = FluidinfoSessionFactory('API-9000')
        self.transact = Transact(self.threadPool)
        self.facade = Facade(self.transact, factory)
        self.system = createSystemData()

    @inlineCallbacks
    def testAuthenticateUserWithOAuth(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} 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()
        consumer = api.register(consumerUser)
        token = api.getAccessToken(consumerUser, user)

        self.store.commit()
        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        request = Request.from_request('GET', u'https://fluidinfo.com/foo',
                                       headers, {'argument1': 'bar'})
        signature = SignatureMethod_HMAC_SHA1().sign(request,
                                                     consumer, None)
        nonce = 'nonce'
        credentials = OAuthCredentials(
            'fluidinfo.com', consumerUser.username, token.encrypt(),
            'HMAC-SHA1', signature, timestamp, nonce, 'GET',
            u'https://fluidinfo.com/foo', headers, arguments)
        session = yield self.facade.authenticateUserWithOAuth(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    @inlineCallbacks
    def testAuthenticateUserWithOAuthIgnoresCase(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} ignores the case in the
        consumer key.
        """
        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()
        consumer = api.register(consumerUser)
        token = api.getAccessToken(consumerUser, user)

        self.store.commit()
        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        request = Request.from_request('GET', u'https://fluidinfo.com/foo',
                                       headers, {'argument1': 'bar'})
        signature = SignatureMethod_HMAC_SHA1().sign(request,
                                                     consumer, None)
        nonce = 'nonce'
        credentials = OAuthCredentials(
            'fluidinfo.com', u'ConsumeR', token.encrypt(),
            'HMAC-SHA1', signature, timestamp, nonce, 'GET',
            u'https://fluidinfo.com/foo', headers, arguments)
        session = yield self.facade.authenticateUserWithOAuth(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    @inlineCallbacks
    def testAuthenticateUserWithOAuthWithMixedCaseInToken(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} ignores the case in the
        username in the token.
        """
        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()
        consumer = api.register(consumerUser)
        token = dataToToken(consumer.secret,
                            {'username': u'UseR',
                             'creationTime': '20121228-161823'})

        self.store.commit()
        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        request = Request.from_request('GET', u'https://fluidinfo.com/foo',
                                       headers, {'argument1': 'bar'})
        signature = SignatureMethod_HMAC_SHA1().sign(request,
                                                     consumer, None)
        nonce = 'nonce'
        credentials = OAuthCredentials(
            'fluidinfo.com', consumerUser.username, token,
            'HMAC-SHA1', signature, timestamp, nonce, 'GET',
            u'https://fluidinfo.com/foo', headers, arguments)
        session = yield self.facade.authenticateUserWithOAuth(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    def testAuthenticateUserWithOAuthIncorrectSignature(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} raises a
        L{TPasswordIncorrect} exception if the signature in the OAuth
        credentials is incorrect.
        """
        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()
        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        signature = 'wrong'
        nonce = 'nonce'
        credentials = OAuthCredentials(
            'fluidinfo.com', user.username, token.encrypt(), u'HMAC-SHA1',
            signature, timestamp, nonce, 'GET', 'https://fluidinfo.com/foo',
            headers, arguments)
        deferred = self.facade.authenticateUserWithOAuth(credentials)
        return self.assertFailure(deferred, TPasswordIncorrect)

    def testAuthenticateUserWithOAuthUnknownConsumer(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} raises
        L{TNoSuchUser} if the consumer does not exist.
        """
        user2 = createUser(u'user2', u'pass2', u'User2', u'*****@*****.**')
        self.store.commit()

        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        token = dataToToken('a' * 16, {'username': user2.username})
        signature = '3MNZYSgsGftopjuwv3g2u5Q+MZM='
        nonce = 'nonce'

        credentials = OAuthCredentials(
            'fluidinfo.com', u'user1', token, 'HMAC-SHA1', signature,
            timestamp, nonce, 'GET', u'https://fluidinfo.com/foo', headers,
            arguments)
        deferred = self.facade.authenticateUserWithOAuth(credentials)

        return self.assertFailure(deferred, TNoSuchUser)

    def testAuthenticateUserWithOAuthUnregisteredConsumer(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} raises
        L{TPasswordIncorrect} if the consumer exists as a Fluidinfo user
        but is not registered as an OAuth consumer.
        """
        user1 = createUser(u'user1', u'pass1', u'User1', u'*****@*****.**')
        user2 = createUser(u'user2', u'pass2', u'User2', u'*****@*****.**')
        self.store.commit()

        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        token = dataToToken('a' * 16, {'username': user2.username})
        signature = '3MNZYSgsGftopjuwv3g2u5Q+MZM='
        nonce = 'nonce'

        credentials = OAuthCredentials(
            'fluidinfo.com', user1.username, token, 'HMAC-SHA1', signature,
            timestamp, nonce, 'GET', u'https://fluidinfo.com/foo', headers,
            arguments)
        deferred = self.facade.authenticateUserWithOAuth(credentials)

        return self.assertFailure(deferred, TPasswordIncorrect)

    def testAuthenticateUserWithOAuthUnknownUsernameInToken(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} raises a
        L{TNoSuchUser} exception if the username in the token does
        not match an existing L{User}.
        """
        user1 = createUser(u'user1', u'pass1', u'User1', u'*****@*****.**')
        oauthConsumer1 = createOAuthConsumer(user1, secret='secret16charlng1')
        self.store.commit()

        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        token = dataToToken(oauthConsumer1.secret,
                            {'username': u'unknownUser'})
        signature = '3MNZYSgsGftopjuwv3g2u5Q+MZM='
        nonce = 'nonce'

        credentials = OAuthCredentials(
            'fluidinfo.com', user1.username, token, u'HMAC-SHA1', signature,
            timestamp, nonce, 'GET', 'https://fluidinfo.com/foo', headers,
            arguments)
        deferred = self.facade.authenticateUserWithOAuth(credentials)

        return self.assertFailure(deferred, TNoSuchUser)
示例#20
0
class FacadePermissionTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource())]

    def setUp(self):
        super(FacadePermissionTest, self).setUp()
        self.transact = Transact(FakeThreadPool())
        factory = FluidinfoSessionFactory('API-9000')
        self.facade = Facade(self.transact, factory)
        createSystemData()
        UserAPI().create([(u'username', u'password', u'User',
                           u'*****@*****.**')])
        user = getUser(u'username')
        self.permissions = CachingPermissionAPI(user)
        SecureTagAPI(user).create([(u'username/tag', u'description')])

    @inlineCallbacks
    def testGetNamespacePermissions(self):
        """
        L{FacadePermissionMixin.getPermission} returns a
        L{TPolicyAndExceptions} object with the policy and exceptions list for
        a given L{Namespace} path.
        """
        self.permissions.set([(u'username', Operation.CREATE_NAMESPACE,
                               Policy.CLOSED, [])])
        with login(u'username', uuid4(), self.transact) as session:
            policyAndExceptions = yield self.facade.getPermission(
                session, u'namespaces', u'create', u'username')
        self.assertEqual(u'closed', policyAndExceptions.policy)
        self.assertEqual([], policyAndExceptions.exceptions)

    @inlineCallbacks
    def testGetTagPermissions(self):
        """
        L{FacadePermissionMixin.getPermission} returns a
        L{TPolicyAndExceptions} object with the policy and exceptions list for
        a given L{Tag} path.
        """
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.CLOSED, [u'username'])])
        with login(u'username', uuid4(), self.transact) as session:
            policyAndExceptions = yield self.facade.getPermission(
                session, u'tags', u'update', u'username/tag')
        self.assertEqual(u'closed', policyAndExceptions.policy)
        self.assertEqual([u'username'], policyAndExceptions.exceptions)

    @inlineCallbacks
    def testGetTagValuePermissions(self):
        """
        L{FacadePermissionMixin.getPermission} returns a
        L{TPolicyAndExceptions} object with the policy and exceptions list for
        a given L{TagValue} path.
        """
        self.permissions.set([(u'username/tag', Operation.WRITE_TAG_VALUE,
                               Policy.CLOSED, [])])
        with login(u'username', uuid4(), self.transact) as session:
            policyAndExceptions = yield self.facade.getPermission(
                session, u'tag-values', u'write', u'username/tag')
        self.assertEqual(u'closed', policyAndExceptions.policy)
        self.assertEqual([], policyAndExceptions.exceptions)

    @inlineCallbacks
    def testGetWithInvalidAction(self):
        """
        L{FacadePermissionMixin.getPermission} raises a L{TBadRequest} error if
        the given C{action} is invalid.
        """
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(session, u'namespaces',
                                                 u'invalid', u'username')
            yield self.assertFailure(deferred, TBadRequest)

    @inlineCallbacks
    def testGetWithInvalidCategory(self):
        """
        L{FacadePermissionMixin.getPermission} raises a L{TBadRequest} error if
        the given C{category} is invalid.
        """
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(session, u'invalid',
                                                 u'create', u'username')
            yield self.assertFailure(deferred, TBadRequest)

    @inlineCallbacks
    def testGetWithUnknownNamespace(self):
        """
        L{FacadePermissionMixin.getPermission} raises a
        L{TNonexistentNamespace} error if the given L{Namespace} path does not
        exist.
        """
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(session, u'namespaces',
                                                 u'create', u'unknown')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testGetWithUnknownTag(self):
        """
        L{FacadePermissionMixin.getPermission} raises a L{TNonexistentTag}
        error if the given L{Tag} path does not exist.
        """
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(
                session, u'tags', u'update', u'username/unknown')
            yield self.assertFailure(deferred, TNonexistentTag)

    @inlineCallbacks
    def testGetNamespacePermissionsIsDenied(self):
        """
        L{FacadePermissionMixin.getPermission} raises a
        L{TPathPermissionDenied} error if the user doesn't have
        C{Operation.CONTROL_NAMESPACE} permissions on the given L{Namespace}.
        """
        self.permissions.set([(u'username', Operation.CONTROL_NAMESPACE,
                               Policy.CLOSED, [])])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(session, u'namespaces',
                                                 u'update', u'username')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testGetTagPermissionsIsDenied(self):
        """
        L{FacadePermissionMixin.getPermission} raises a
        L{TPathPermissionDenied} error if the user doesn't have
        C{Operation.CONTROL_TAG} permissions on the given L{Tag}.
        """
        self.permissions.set([(u'username/tag', Operation.CONTROL_TAG,
                               Policy.CLOSED, [])])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(session, u'tags',
                                                 u'delete', u'username/tag')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testGetTagValuePermissionsIsDenied(self):
        """
        L{FacadePermissionMixin.getPermission} raises a
        L{TPathPermissionDenied} error if the user doesn't have
        C{Operation.CONTROL_TAG_VALUE} permissions on the given L{Tag}.
        """
        self.permissions.set([(u'username/tag', Operation.CONTROL_TAG_VALUE,
                               Policy.CLOSED, [])])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.getPermission(session, u'tag-values',
                                                 u'read', u'username/tag')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testSetNamespacePermissions(self):
        """
        L{FacadePermissionMixin.updatePermission} updates the permissions for a
        given L{Namespace} path.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [])
        with login(u'username', uuid4(), self.transact) as session:
            yield self.facade.updatePermission(session, u'namespaces',
                                               u'create', u'username',
                                               policyAndExceptions)
        pathAndAction = (u'username', Operation.CREATE_NAMESPACE)
        result = self.permissions.get([pathAndAction])
        self.assertEqual((Policy.CLOSED, []), result[pathAndAction])

    @inlineCallbacks
    def testSetTagPermissions(self):
        """
        L{FacadePermissionMixin.updatePermission} updates the permissions for a
        given L{Tag} path.
        """
        policyAndExceptions = TPolicyAndExceptions(u'open', [u'username'])
        with login(u'username', uuid4(), self.transact) as session:
            yield self.facade.updatePermission(session, u'tags', u'update',
                                               u'username/tag',
                                               policyAndExceptions)
        pathAndAction = (u'username/tag', Operation.UPDATE_TAG)
        result = self.permissions.get([pathAndAction])
        self.assertEqual((Policy.OPEN, [u'username']), result[pathAndAction])

    @inlineCallbacks
    def testSetTagValuePermissions(self):
        """
        L{FacadePermissionMixin.updatePermission} updates the permissions for a
        given L{TagValue} path.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [u'username'])
        with login(u'username', uuid4(), self.transact) as session:
            yield self.facade.updatePermission(session, u'tag-values',
                                               u'write', u'username/tag',
                                               policyAndExceptions)
        pathAndAction = (u'username/tag', Operation.WRITE_TAG_VALUE)
        result = self.permissions.get([pathAndAction])
        self.assertEqual((Policy.CLOSED, [u'username']), result[pathAndAction])

    @inlineCallbacks
    def testSetWithInvalidAction(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TBadRequest} error
        if the given C{action} is invalid.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(session, u'namespaces',
                                                    u'invalid', u'username',
                                                    policyAndExceptions)
            yield self.assertFailure(deferred, TBadRequest)

    @inlineCallbacks
    def testSetWithInvalidCategory(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TBadRequest} error
        if the given C{category} is invalid.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(session, u'invalid',
                                                    u'update', u'username',
                                                    policyAndExceptions)
            yield self.assertFailure(deferred, TBadRequest)

    @inlineCallbacks
    def testSetWithInvalidPolicy(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TInvalidPolicy}
        error if the given C{policy} is invalid.
        """
        policyAndExceptions = TPolicyAndExceptions(u'invalid', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(session, u'namespaces',
                                                    u'create', u'username',
                                                    policyAndExceptions)
            yield self.assertFailure(deferred, TInvalidPolicy)

    @inlineCallbacks
    def testSetWithUnknownNamespace(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a
        L{TNonexistentNamespace} error if the given L{Namespace} path does not
        exist.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(session, u'namespaces',
                                                    u'create', u'unknown',
                                                    policyAndExceptions)
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testSetWithUnknownTag(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TNonexistentTag}
        error if the given L{Tag} path does not exist.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tags', u'update', u'username/unknown',
                policyAndExceptions)
            yield self.assertFailure(deferred, TNonexistentTag)

    @inlineCallbacks
    def testSetWithUnknownUser(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TNoSuchUser}
        error if a L{User} in the exceptions list doesn't exist.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [u'unknown'])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tags', u'update', u'username/tag',
                policyAndExceptions)
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual('unknown', error.name)

    @inlineCallbacks
    def testSetWithSuperuser(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TInvalidUsername}
        error if a superuser is specified in the exceptions list.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [u'fluiddb'])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tags', u'update', u'username/tag',
                policyAndExceptions)
            yield self.assertFailure(deferred, TInvalidUsername)

    @inlineCallbacks
    def testSetWithAnonymous(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TInvalidUsername}
        error if the anonymous user is specified in the exceptions list for
        non-allowed operations.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed', [u'anon'])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tags', u'update', u'username/tag',
                policyAndExceptions)
            yield self.assertFailure(deferred, TInvalidUsername)

    @inlineCallbacks
    def testSetWithUnknownUserUTF8EncodesUsername(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a L{TNoSuchUser}
        error if a L{User} in the exceptions list doesn't exist.  The username
        passed to L{TNoSuchUser} is UTF-8 encoded.
        """
        policyAndExceptions = TPolicyAndExceptions(u'closed',
                                                   [u'\N{HIRAGANA LETTER A}'])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tags', u'update', u'username/tag',
                policyAndExceptions)
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'\N{HIRAGANA LETTER A}'.encode('utf-8'),
                             error.name)

    @inlineCallbacks
    def testSetNamespacePermissionsIsDenied(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a
        L{TPathPermissionDenied} error if the user doesn't have
        C{Operation.CONTROL_NAMESPACE} permissions on the given L{Namespace}.
        """
        self.permissions.set([(u'username', Operation.CONTROL_NAMESPACE,
                               Policy.CLOSED, [])])
        policyAndExceptions = TPolicyAndExceptions(u'open', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(session, u'namespaces',
                                                    u'control', u'username',
                                                    policyAndExceptions)
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testSetTagPermissionsIsDenied(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a
        L{TPathPermissionDenied} error if the user doesn't have
        C{Operation.CONTROL_TAG} permissions on the given L{Tag}.
        """
        self.permissions.set([(u'username/tag', Operation.CONTROL_TAG,
                               Policy.CLOSED, [])])
        policyAndExceptions = TPolicyAndExceptions(u'open', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tags', u'control', u'username/tag',
                policyAndExceptions)
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testSetTagValuePermissionsIsDenied(self):
        """
        L{FacadePermissionMixin.updatePermission} raises a
        L{TPathPermissionDenied} error if the user doesn't have
        C{Operation.CONTROL_TAG_VALUE} permissions on the given L{Tag}.
        """
        self.permissions.set([(u'username/tag', Operation.CONTROL_TAG_VALUE,
                               Policy.CLOSED, [])])
        policyAndExceptions = TPolicyAndExceptions(u'open', [])
        with login(u'username', uuid4(), self.transact) as session:
            deferred = self.facade.updatePermission(
                session, u'tag-values', u'control', u'username/tag',
                policyAndExceptions)
            yield self.assertFailure(deferred, TPathPermissionDenied)
示例#21
0
class FacadeAuthenticateUserWithOAuth2Test(FluidinfoTestCase):
    """Test L{Facade} OAuth2 authentication."""

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeAuthenticateUserWithOAuth2Test, self).setUp()
        factory = FluidinfoSessionFactory('API-9000')
        self.transact = Transact(self.threadPool)
        self.facade = Facade(self.transact, factory)
        self.system = createSystemData()

    @inlineCallbacks
    def testAuthenticateUserWithOAuth2(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} 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'*****@*****.**')])
        consumer = getUser(u'consumer')
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        api.register(consumer)
        token = api.getAccessToken(consumer, user)
        self.store.commit()

        credentials = OAuth2Credentials(u'consumer', u'secret',
                                        token.encrypt())
        session = yield self.facade.authenticateUserWithOAuth2(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    @inlineCallbacks
    def testAuthenticateUserWithOAuth2IgnoresCase(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} 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'*****@*****.**')])
        consumer = getUser(u'consumer')
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        api.register(consumer)
        token = api.getAccessToken(consumer, user)
        self.store.commit()

        credentials = OAuth2Credentials(u'ConsumeR', u'secret',
                                        token.encrypt())
        session = yield self.facade.authenticateUserWithOAuth2(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    @inlineCallbacks
    def testAuthenticateUserWithOAuthWithMixedCaseToken(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} ignores case in the
        username in the token.
        """
        UserAPI().create([
            (u'consumer', u'secret', u'Consumer', u'*****@*****.**'),
            (u'user', u'secret', u'User', u'*****@*****.**')])
        consumer = getUser(u'consumer')
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        oauthConsumer = api.register(consumer)
        token = dataToToken(oauthConsumer.secret,
                            {'username': u'UseR',
                             'creationTime': '20121228-161823'})
        self.store.commit()

        credentials = OAuth2Credentials(consumer.username, u'secret', token)
        session = yield self.facade.authenticateUserWithOAuth2(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    @inlineCallbacks
    def testAuthenticateAnonymousUserWithOAuth2(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} should create a
        L{FluidinfoSession} for the anonymous user.
        """
        anonymous = self.system.users[u'anon']
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        api.register(anonymous)
        token = api.getAccessToken(anonymous, user)
        self.store.commit()

        credentials = OAuth2Credentials(u'anon', None, token.encrypt())
        session = yield self.facade.authenticateUserWithOAuth2(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)

    def testAuthenticateUserWithOAuth2ConsumerPasswordIncorrect(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} raises
        L{TPasswordIncorrect} if the consumer's password is not correct.
        """
        user1 = createUser(u'user1', u'pass1', u'User1', u'*****@*****.**')
        oauthConsumer1 = createOAuthConsumer(user1, secret='secret16charlng1')
        user2 = createUser(u'user2', u'pass2', u'User2', u'*****@*****.**')
        self.store.commit()

        token = dataToToken(oauthConsumer1.secret,
                            {'username': user2.username})

        credentials = OAuth2Credentials(u'user1', u'invalid', token)
        deferred = self.facade.authenticateUserWithOAuth2(credentials)

        return self.assertFailure(deferred, TPasswordIncorrect)

    def testAuthenticateUserWithOAuth2UnknownConsumer(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} raises
        L{TNoSuchUser} if the consumer does not exist.
        """
        user = createUser(u'user', u'pass', u'User', u'*****@*****.**')
        oauthConsumer = createOAuthConsumer(user, secret='secret16charlng1')
        self.store.commit()

        token = dataToToken(oauthConsumer.secret, {'username': u'unknownUser'})
        credentials = OAuth2Credentials(u'invalid', u'pass', token)
        deferred = self.facade.authenticateUserWithOAuth2(credentials)

        return self.assertFailure(deferred, TNoSuchUser)

    def testAuthenticateUserWithOAuth2UnregisteredConsumer(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} raises
        L{TPasswordIncorrect} if the consumer exists as a Fluidinfo user
        but is not registered as an OAuth consumer.
        """
        createUser(u'user1', u'pass1', u'User1', u'*****@*****.**')
        createUser(u'user2', u'pass2', u'User2', u'*****@*****.**')
        self.store.commit()

        token = dataToToken('a' * 16, {'username': u'user2'})
        credentials = OAuth2Credentials(u'user1', u'pass1', token)
        deferred = self.facade.authenticateUserWithOAuth2(credentials)

        return self.assertFailure(deferred, TPasswordIncorrect)

    def testAuthenticateUserWithOAuth2UnknownUsernameInToken(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth2} ignores the case in the
        consumer key.
        """
        user = createUser(u'user', u'pass', u'User', u'*****@*****.**')
        oauthConsumer = createOAuthConsumer(user, secret='secret16charlng1')
        self.store.commit()

        token = dataToToken(oauthConsumer.secret, {'username': u'unknownUser'})
        credentials = OAuth2Credentials(u'user', u'pass', token)
        deferred = self.facade.authenticateUserWithOAuth2(credentials)

        return self.assertFailure(deferred, TNoSuchUser)
示例#22
0
class FacadeNamespaceTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeNamespaceTest, 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 = PermissionAPI(self.user)

    @inlineCallbacks
    def testGetNamespaceWithoutData(self):
        """
        L{Facade.getNamespace} raises a L{TNonexistentNamespace} exception if
        the requested L{Namespace.path} doesn't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.getNamespace(session, u'username/unknown',
                                                False, False, False)
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testGetNamespace(self):
        """
        L{Facade.getNamespace} returns a L{TNamespace} instance with
        information about the requested L{Namespace}.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username',
                                                    False, False, False)

        self.assertEqual(str(self.user.namespace.objectID), result.objectId)
        self.assertEqual(u'username', result.path)

    @inlineCallbacks
    def testGetNamespaceWithDescription(self):
        """
        L{Facade.getNamespace} includes the L{Namespace.description}, if it
        was requested.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username/name',
                                                    True, False, False)
        self.assertEqual(u'A namespace.', result.description)

    @inlineCallbacks
    def testGetNamespaceWithNamespaces(self):
        """
        L{Facade.getNamespace} includes child L{Namespace.name}s, if they were
        requested.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username',
                                                    False, True, False)
        self.assertEqual([u'name', u'private'], sorted(result.namespaces))

    @inlineCallbacks
    def testGetNamespaceWithTags(self):
        """
        L{Facade.getNamespace} includes child L{Tag.name}s, if they were
        requested.
        """
        createTag(self.user, self.user.namespace, u'tag')
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username',
                                                    False, False, True)
        self.assertEqual([u'tag'], result.tags)

    @inlineCallbacks
    def testGetNamespaceWithUnknownPath(self):
        """
        L{Facade.getNamespace} raises a L{TNonexistentNamespace} exception
        if the specified L{Namespace} doesn't exist.
        """
        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.getNamespace(session, u'unknown',
                                                returnDescription=False,
                                                returnNamespaces=False,
                                                returnTags=False)
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testGetNamespaceWithPermissionDenied(self):
        """
        L{Facade.getNamespace} raises a L{TPathPermissionDenied} exception
        if the user doesn't have C{LIST} permissions on the specified
        L{Namespace}.
        """
        self.permissions.set([(u'username', Operation.LIST_NAMESPACE,
                               Policy.CLOSED, [])])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.getNamespace(session, u'username',
                                                returnDescription=True,
                                                returnNamespaces=True,
                                                returnTags=True)
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testCreateNamespace(self):
        """L{Facade.createNamespace} creates a new L{Namespace}."""
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            objectID = yield self.facade.createNamespace(
                session, u'username', u'name', u'A namespace.')

        self.store.rollback()
        self.assertNotIdentical(None, objectID)
        objectID = UUID(objectID)
        namespace = getNamespaces(objectIDs=[objectID]).one()
        self.assertIdentical(self.user, namespace.creator)
        self.assertEqual(u'username/name', namespace.path)
        self.assertEqual(u'name', namespace.name)
        self.assertEqual(objectID, namespace.objectID)

    @inlineCallbacks
    def testCreateNamespaceWithExistingPath(self):
        """
        L{Facade.createNamespace} raises a L{TNamespaceAlreadyExists}
        exception if the new L{Namespace} already exists.
        """
        createNamespace(self.user, u'username/name', self.user.namespace.id)
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'username',
                                                   u'name', u'A namespace.')
            yield self.assertFailure(deferred, TNamespaceAlreadyExists)

    @inlineCallbacks
    def testCreateNamespaceWithUnknownParent(self):
        """
        L{Facade.createNamespace} raises a L{TNonexistentNamespace} exception
        if a non-existent parent L{Namespace} is specified.
        """
        createNamespace(self.user, u'username/name', self.user.namespace.id)
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'unknown/parent',
                                                   u'name', u'A  namespace.')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testCreateNamespaceWithInvalidPath(self):
        """
        L{Facade.createNamespace} raises a L{TInvalidPath} exception
        if the path of the L{Namespace} is not well formed.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'username',
                                                   u'bad name', u'description')
            yield self.assertFailure(deferred, TInvalidPath)

    @inlineCallbacks
    def testCreateNamespaceImplicitlyCreatesParent(self):
        """
        L{Facade.createNamespace} implicitly creates parent L{Namespace}s if
        they don't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            objectID = yield self.facade.createNamespace(
                session, u'username/parent', u'name', u'A namespace.')
            namespace = yield self.facade.getNamespace(
                session, u'username/parent/name', returnDescription=False,
                returnNamespaces=False, returnTags=False)
            self.assertEqual(objectID, namespace.objectId)

    @inlineCallbacks
    def testCreateIsDenied(self):
        """
        L{Facade.createNamespace} 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', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'username',
                                                   u'test', u'description')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testUpdateNamespace(self):
        """
        L{Facade.updateNamespace} updates the description for an existing
        L{Namespace}.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            yield self.facade.updateNamespace(session, u'username/name',
                                              u'A new description.')

        self.store.rollback()
        result = namespaces.get([u'username/name'], withDescriptions=True)
        self.assertEqual(u'A new description.',
                         result[u'username/name']['description'])

    @inlineCallbacks
    def testUpdateNamespaceWithUnknownPath(self):
        """
        L{Facade.updateNamespace} raises a L{TNonexistentNamespace} exception
        if the requested L{Namespace.path} doesn't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.updateNamespace(
                session, u'username/unknown', u'A new description.')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testUpdateIsDenied(self):
        """
        L{Facade.updateNamespace} raises a L{TPathPermissionDenied} exception
        if the user doesn't have C{UPDATE} permissions on the specified
        L{Namespace}.
        """
        self.permissions.set([(u'username', Operation.UPDATE_NAMESPACE,
                               Policy.CLOSED, [])])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.updateNamespace(session, u'username',
                                                   u'description')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testDeleteNamespace(self):
        """L{Facade.deleteNamespace} deletes a L{Namespace}."""
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            yield self.facade.deleteNamespace(session, u'username/name')

        self.store.rollback()
        self.assertEqual({}, namespaces.get([u'username/name']))

    @inlineCallbacks
    def testDeleteNamespaceWithUnknownPath(self):
        """
        L{Facade.deleteNamespace} raises a L{TNonexistentNamespace} exception
        if the requested L{Namespace.path} doesn't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.deleteNamespace(session,
                                                   u'username/unknown')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testDeleteNamespaceWithData(self):
        """
        L{Facade.deleteNamespace} raises a L{TNamespaceNotEmpty} exception if
        the requested L{Namespace} has child data such as other L{Namespace}s
        or L{Tag}s.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/parent', u'A parent namespace.')])
        namespaces.create([(u'username/parent/child', u'A child namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.deleteNamespace(session, u'username/parent')
            yield self.assertFailure(deferred, TNamespaceNotEmpty)

    @inlineCallbacks
    def testDeleteIsDenied(self):
        """
        L{Facade.deleteNamespace} raises a L{TPathPermissionDenied} exception
        if the user doesn't have C{DELETE} permissions on the specified
        L{Namespace}.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/test', u'description')])
        self.permissions.set([(u'username/test', Operation.DELETE_NAMESPACE,
                               Policy.OPEN, [u'username'])])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.deleteNamespace(session, u'username/test')
            yield self.assertFailure(deferred, TPathPermissionDenied)
示例#23
0
class FacadeUserCreationTest(FluidinfoTestCase):
    """Test L{Facade} user creation."""

    resources = [('cache', CacheResource()),
                 ('config', ConfigResource()),
                 ('log', LoggingResource()),
                 ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeUserCreationTest, self).setUp()
        factory = FluidinfoSessionFactory('API-9000')
        self.transact = Transact(self.threadPool)
        self.facade = Facade(self.transact, factory)
        self.system = createSystemData()

    @inlineCallbacks
    def testCreateUserWithPassword(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will create a new user in
        the database and return its object ID when invoked by the superuser.
        """
        superuser = self.system.users[u'fluiddb']
        self.store.commit()

        with login(u'fluiddb', superuser.objectID, self.transact) as session:
            objectID = yield self.facade.createUserWithPassword(
                session, 'user', 'secret', 'User', '*****@*****.**')
        self.store.rollback()

        self.assertEqual({u'user': {'id': UUID(objectID), 'name': u'User',
                                    'role': Role.USER}},
                         UserAPI().get([u'user']))

    @inlineCallbacks
    def testCreateUserWithPasswordIgnoresCase(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} ignores the case of the
        username.
        """
        superuser = self.system.users[u'fluiddb']
        self.store.commit()

        with login(u'fluiddb', superuser.objectID, self.transact) as session:
            objectID = yield self.facade.createUserWithPassword(
                session, 'UsEr', 'secret', 'User', '*****@*****.**')
        self.store.rollback()

        self.assertEqual({u'user': {'id': UUID(objectID), 'name': u'User',
                                    'role': Role.USER}},
                         UserAPI().get([u'user']))

    @inlineCallbacks
    def testCreateUserUnicode(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will accept UTF-8 encoded
        C{str}s for the username, the password, the full name and the email
        address and convert them to C{unicode} appropriately.
        """
        superuser = self.system.users[u'fluiddb']
        username = u'\N{HIRAGANA LETTER A}'
        password = u'\N{HIRAGANA LETTER E}'
        name = u'\N{HIRAGANA LETTER I}'
        email = u'*****@*****.**'
        self.store.commit()

        with login(u'fluiddb', superuser.objectID, self.transact) as session:
            objectID = yield self.facade.createUserWithPassword(
                session, username.encode('utf-8'), password.encode('utf-8'),
                name.encode('utf-8'), email.encode('utf-8'))
        self.store.rollback()
        user = getUser(username)

        self.assertEqual(str(user.objectID), objectID)
        self.assertEqual(user.fullname, name)
        self.assertEqual(user.email, email)

    @inlineCallbacks
    def testCreateUserDuplicate(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will raise a
        L{TUserAlreadyExists} if the username given already exists in the
        database.
        """
        createUser(u'fred', u'password', u'Fred', u'*****@*****.**')
        superuser = self.system.users[u'fluiddb']
        self.store.commit()

        with login(u'fluiddb', superuser.objectID, self.transact) as session:
            deferred = self.facade.createUserWithPassword(
                session, 'fred', 'password', 'Fred', '*****@*****.**')
            yield self.assertFailure(deferred, TUserAlreadyExists)

    @inlineCallbacks
    def testCreateUserWithInvalidUsername(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will raise a
        L{TInvalidUsername} exception if the username given is invalid.
        """
        superuser = self.system.users[u'fluiddb']
        self.store.commit()

        with login(u'fluiddb', superuser.objectID, self.transact) as session:
            deferred = self.facade.createUserWithPassword(
                session, '!invalid & ', 'secret', 'None', '*****@*****.**')
            yield self.assertFailure(deferred, TInvalidUsername)

    @inlineCallbacks
    def testCreateUserWithLongUsername(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will raise a
        L{TUsernameTooLong} exception if the username given is longer than 128
        characters.
        """
        superuser = self.system.users[u'fluiddb']
        self.store.commit()

        with login(u'fluiddb', superuser.objectID, self.transact) as session:
            session.auth.login(u'fluiddb', superuser.objectID)
            deferred = self.facade.createUserWithPassword(
                session, 'x' * 129, 'secret', 'None', '*****@*****.**')
            yield self.assertFailure(deferred, TUsernameTooLong)

    @inlineCallbacks
    def testCreateUserNormalUserRole(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will raise a
        L{TPathPermissionDenied} if invoked by a normal user.
        """
        user = createUser(u'user', u'pass', u'User', u'*****@*****.**')
        self.store.commit()

        with login(u'user', user.objectID, self.transact) as session:
            deferred = self.facade.createUserWithPassword(
                session, 'fred', 'password', 'Fred', '*****@*****.**')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testCreateUserByAnonymousRole(self):
        """
        L{FacadeAuthMixin.createUserWithPassword} will raise a
        L{TPathPermissionDenied} if invoked by the anonymous user.
        """
        anonymous = self.system.users[u'anon']
        self.store.commit()

        with login(u'anon', anonymous.objectID, self.transact) as session:
            deferred = self.facade.createUserWithPassword(
                session, 'fred', 'password', 'Fred', '*****@*****.**')
            yield self.assertFailure(deferred, TPathPermissionDenied)
示例#24
0
class FacadeNamespaceTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()), ('config', ConfigResource()),
                 ('log', LoggingResource()), ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeNamespaceTest, 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 = PermissionAPI(self.user)

    @inlineCallbacks
    def testGetNamespaceWithoutData(self):
        """
        L{Facade.getNamespace} raises a L{TNonexistentNamespace} exception if
        the requested L{Namespace.path} doesn't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.getNamespace(session, u'username/unknown',
                                                False, False, False)
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testGetNamespace(self):
        """
        L{Facade.getNamespace} returns a L{TNamespace} instance with
        information about the requested L{Namespace}.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username',
                                                    False, False, False)

        self.assertEqual(str(self.user.namespace.objectID), result.objectId)
        self.assertEqual(u'username', result.path)

    @inlineCallbacks
    def testGetNamespaceWithDescription(self):
        """
        L{Facade.getNamespace} includes the L{Namespace.description}, if it
        was requested.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username/name',
                                                    True, False, False)
        self.assertEqual(u'A namespace.', result.description)

    @inlineCallbacks
    def testGetNamespaceWithNamespaces(self):
        """
        L{Facade.getNamespace} includes child L{Namespace.name}s, if they were
        requested.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username',
                                                    False, True, False)
        self.assertEqual([u'name', u'private'], sorted(result.namespaces))

    @inlineCallbacks
    def testGetNamespaceWithTags(self):
        """
        L{Facade.getNamespace} includes child L{Tag.name}s, if they were
        requested.
        """
        createTag(self.user, self.user.namespace, u'tag')
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            result = yield self.facade.getNamespace(session, u'username',
                                                    False, False, True)
        self.assertEqual([u'tag'], result.tags)

    @inlineCallbacks
    def testGetNamespaceWithUnknownPath(self):
        """
        L{Facade.getNamespace} raises a L{TNonexistentNamespace} exception
        if the specified L{Namespace} doesn't exist.
        """
        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.getNamespace(session,
                                                u'unknown',
                                                returnDescription=False,
                                                returnNamespaces=False,
                                                returnTags=False)
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testGetNamespaceWithPermissionDenied(self):
        """
        L{Facade.getNamespace} raises a L{TPathPermissionDenied} exception
        if the user doesn't have C{LIST} permissions on the specified
        L{Namespace}.
        """
        self.permissions.set([(u'username', Operation.LIST_NAMESPACE,
                               Policy.CLOSED, [])])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.getNamespace(session,
                                                u'username',
                                                returnDescription=True,
                                                returnNamespaces=True,
                                                returnTags=True)
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testCreateNamespace(self):
        """L{Facade.createNamespace} creates a new L{Namespace}."""
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            objectID = yield self.facade.createNamespace(
                session, u'username', u'name', u'A namespace.')

        self.store.rollback()
        self.assertNotIdentical(None, objectID)
        objectID = UUID(objectID)
        namespace = getNamespaces(objectIDs=[objectID]).one()
        self.assertIdentical(self.user, namespace.creator)
        self.assertEqual(u'username/name', namespace.path)
        self.assertEqual(u'name', namespace.name)
        self.assertEqual(objectID, namespace.objectID)

    @inlineCallbacks
    def testCreateNamespaceWithExistingPath(self):
        """
        L{Facade.createNamespace} raises a L{TNamespaceAlreadyExists}
        exception if the new L{Namespace} already exists.
        """
        createNamespace(self.user, u'username/name', self.user.namespace.id)
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'username',
                                                   u'name', u'A namespace.')
            yield self.assertFailure(deferred, TNamespaceAlreadyExists)

    @inlineCallbacks
    def testCreateNamespaceWithUnknownParent(self):
        """
        L{Facade.createNamespace} raises a L{TNonexistentNamespace} exception
        if a non-existent parent L{Namespace} is specified.
        """
        createNamespace(self.user, u'username/name', self.user.namespace.id)
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'unknown/parent',
                                                   u'name', u'A  namespace.')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testCreateNamespaceWithInvalidPath(self):
        """
        L{Facade.createNamespace} raises a L{TInvalidPath} exception
        if the path of the L{Namespace} is not well formed.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'username',
                                                   u'bad name', u'description')
            yield self.assertFailure(deferred, TInvalidPath)

    @inlineCallbacks
    def testCreateNamespaceImplicitlyCreatesParent(self):
        """
        L{Facade.createNamespace} implicitly creates parent L{Namespace}s if
        they don't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            objectID = yield self.facade.createNamespace(
                session, u'username/parent', u'name', u'A namespace.')
            namespace = yield self.facade.getNamespace(session,
                                                       u'username/parent/name',
                                                       returnDescription=False,
                                                       returnNamespaces=False,
                                                       returnTags=False)
            self.assertEqual(objectID, namespace.objectId)

    @inlineCallbacks
    def testCreateIsDenied(self):
        """
        L{Facade.createNamespace} 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', self.user.objectID, self.transact) as session:
            deferred = self.facade.createNamespace(session, u'username',
                                                   u'test', u'description')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testUpdateNamespace(self):
        """
        L{Facade.updateNamespace} updates the description for an existing
        L{Namespace}.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            yield self.facade.updateNamespace(session, u'username/name',
                                              u'A new description.')

        self.store.rollback()
        result = namespaces.get([u'username/name'], withDescriptions=True)
        self.assertEqual(u'A new description.',
                         result[u'username/name']['description'])

    @inlineCallbacks
    def testUpdateNamespaceWithUnknownPath(self):
        """
        L{Facade.updateNamespace} raises a L{TNonexistentNamespace} exception
        if the requested L{Namespace.path} doesn't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.updateNamespace(session,
                                                   u'username/unknown',
                                                   u'A new description.')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testUpdateIsDenied(self):
        """
        L{Facade.updateNamespace} raises a L{TPathPermissionDenied} exception
        if the user doesn't have C{UPDATE} permissions on the specified
        L{Namespace}.
        """
        self.permissions.set([(u'username', Operation.UPDATE_NAMESPACE,
                               Policy.CLOSED, [])])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.updateNamespace(session, u'username',
                                                   u'description')
            yield self.assertFailure(deferred, TPathPermissionDenied)

    @inlineCallbacks
    def testDeleteNamespace(self):
        """L{Facade.deleteNamespace} deletes a L{Namespace}."""
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/name', u'A namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            yield self.facade.deleteNamespace(session, u'username/name')

        self.store.rollback()
        self.assertEqual({}, namespaces.get([u'username/name']))

    @inlineCallbacks
    def testDeleteNamespaceWithUnknownPath(self):
        """
        L{Facade.deleteNamespace} raises a L{TNonexistentNamespace} exception
        if the requested L{Namespace.path} doesn't exist.
        """
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.deleteNamespace(session,
                                                   u'username/unknown')
            yield self.assertFailure(deferred, TNonexistentNamespace)

    @inlineCallbacks
    def testDeleteNamespaceWithData(self):
        """
        L{Facade.deleteNamespace} raises a L{TNamespaceNotEmpty} exception if
        the requested L{Namespace} has child data such as other L{Namespace}s
        or L{Tag}s.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/parent', u'A parent namespace.')])
        namespaces.create([(u'username/parent/child', u'A child namespace.')])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.deleteNamespace(session, u'username/parent')
            yield self.assertFailure(deferred, TNamespaceNotEmpty)

    @inlineCallbacks
    def testDeleteIsDenied(self):
        """
        L{Facade.deleteNamespace} raises a L{TPathPermissionDenied} exception
        if the user doesn't have C{DELETE} permissions on the specified
        L{Namespace}.
        """
        namespaces = NamespaceAPI(self.user)
        namespaces.create([(u'username/test', u'description')])
        self.permissions.set([(u'username/test', Operation.DELETE_NAMESPACE,
                               Policy.OPEN, [u'username'])])
        self.store.commit()

        with login(u'username', self.user.objectID, self.transact) as session:
            deferred = self.facade.deleteNamespace(session, u'username/test')
            yield self.assertFailure(deferred, TPathPermissionDenied)
示例#25
0
class FacadeUserMixinTest(FluidinfoTestCase):

    resources = [('cache', CacheResource()), ('config', ConfigResource()),
                 ('log', LoggingResource()), ('store', DatabaseResource()),
                 ('threadPool', ThreadPoolResource())]

    def setUp(self):
        super(FacadeUserMixinTest, self).setUp()
        self.transact = Transact(self.threadPool)
        factory = FluidinfoSessionFactory('API-9000')
        self.facade = Facade(self.transact, factory)
        system = createSystemData()
        self.admin = system.users[u'fluiddb']

    @inlineCallbacks
    def testGetUserWithoutData(self):
        """
        L{FacadeUserMixin.getUser} raises a L{TNoSuchUser} exception if the
        requested L{User.username} doesn't exist.
        """
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.getUser(session, u'unknown')
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'unknown', error.name)

    @inlineCallbacks
    def testGetUser(self):
        """
        L{FacadeUserMixin.getUser} returns a L{TUser} instance with
        information about the requested L{User}.
        """
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        user = getUser(u'user')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            result = yield self.facade.getUser(session, u'user')
            self.assertEqual(u'user', result.username)
            self.assertEqual(str(user.objectID), result.objectId)
            self.assertEqual(u'User', result.name)
            self.assertEqual(u'USER', result.role)

    @inlineCallbacks
    def testGetUserIgnoresCase(self):
        """L{FacadeUserMixin.getUser} ignores case for the username."""
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            result = yield self.facade.getUser(session, u'uSeR')
            self.assertEqual(u'user', result.username)

    @inlineCallbacks
    def testUpdateUser(self):
        """
        L{FacadeUserMixin.updateUser} updates the description for an existing
        L{User}.
        """
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'test')
        passwordHash = user.passwordHash
        self.store.commit()
        info = TUserUpdate(u'test', u'password', u'new-name',
                           u'*****@*****.**')
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'test', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)

    @inlineCallbacks
    def testUpdateUserWithoutPassword(self):
        """
        If a L{User.password} is not passed to L{FacadeUserMixin.updateUser}
        the existing password will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', None, u'new-name', u'*****@*****.**',
                           'USER_MANAGER')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER_MANAGER, user.role)

    @inlineCallbacks
    def testUpdateUserWithoutName(self):
        """
        If a L{User.fullname} is not passed to L{FacadeUserMixin.updateUser}
        the existing name will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', u's3cr3t', None, u'*****@*****.**',
                           'USER_MANAGER')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER_MANAGER, user.role)

    @inlineCallbacks
    def testUpdateUserWithoutEmail(self):
        """
        If a L{User.email} is not passed to L{FacadeUserMixin.updateUser}
        the existing email address will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', u's3cr3t', u'new-name', None,
                           'USER_MANAGER')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER_MANAGER, user.role)

    @inlineCallbacks
    def testUpdateUserWithoutRole(self):
        """
        If a L{User.role} is not passed to L{FacadeUserMixin.updateUser}
        the existing user role will not be changed.
        """
        UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'user')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'user', u's3cr3t', u'new-name', '*****@*****.**',
                           None)
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'user', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)
        self.assertEqual(Role.USER, user.role)

    @inlineCallbacks
    def testUpdateUserWithBadRole(self):
        """
        If an invalid L{User.role} is passed to L{FacadeUserMixin.updateUser}
        a L{TBadRequest} exception is raised.
        """
        info = TUserUpdate(u'user', u's3cr3t', u'new-name', '*****@*****.**',
                           'BAD_ROLE')
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.updateUser(session, info)
            yield self.assertFailure(deferred, TBadRequest)

    @inlineCallbacks
    def testUpdateUserIgnoresCase(self):
        """
        L{FacadeUserMixin.updateUser} ignores case when updating a new user.
        """
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')])
        user = getUser(u'test')
        passwordHash = user.passwordHash
        info = TUserUpdate(u'TesT', u'password', u'new-name',
                           u'*****@*****.**')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.updateUser(session, info)

        self.store.rollback()
        self.assertEqual(u'test', user.username)
        self.assertNotEqual(passwordHash, user.passwordHash)
        self.assertEqual(u'new-name', user.fullname)
        self.assertEqual(u'*****@*****.**', user.email)

    @inlineCallbacks
    def testUpdateUserWithUnknownUsername(self):
        """
        L{FacadeUserMixin.updateUser} raises a L{TNoSuchUser} exception
        if the requested L{User.username} doesn't exist.
        """
        info = TUserUpdate(u'unknown', u'password', u'name',
                           u'*****@*****.**')
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.updateUser(session, info)
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'unknown', error.name)

    @inlineCallbacks
    def testUpdateUserIsDenied(self):
        """
        L{FacadeUserMixin.updateUser} raises a L{TPathPermissionDenied}
        exception if the user making the request is not a superuser.
        """
        UserAPI().create([(u'user', u'secret', u'User', u'*****@*****.**')])
        info = TUserUpdate(u'username', u'secret', u'Username',
                           u'*****@*****.**')
        self.store.commit()
        with login(u'user', uuid4(), self.transact) as session:
            deferred = self.facade.updateUser(session, info)
            error = yield self.assertFailure(deferred, TPathPermissionDenied)
            self.assertEqual(u'username', error.path)

    @inlineCallbacks
    def testDeleteUser(self):
        """L{FacadeUserMixin.deleteUser} deletes a L{User}."""
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')],
                         createPrivateNamespace=False)
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.deleteUser(session, u'test')

        self.store.rollback()
        self.assertIdentical(None, getUser(u'test'))

    @inlineCallbacks
    def testDeleteUserIgnoresCase(self):
        """
        L{FacadeUserMixin.deleteUser} ignores case for the username when
        deleting a user.
        """
        UserAPI().create([(u'test', u'secret', u'name', u'*****@*****.**')],
                         createPrivateNamespace=False)
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            yield self.facade.deleteUser(session, u'tESt')

        self.store.rollback()
        self.assertIdentical(None, getUser(u'test'))

    @inlineCallbacks
    def testDeleteUserWithUnknownUsername(self):
        """
        L{FacadeUserMixin.deleteUser} raises a L{TNoSuchUser} exception if the
        specified L{User.username} doesn't exist.
        """
        self.store.commit()
        with login(u'fluiddb', self.admin.objectID, self.transact) as session:
            deferred = self.facade.deleteUser(session, u'unknown')
            error = yield self.assertFailure(deferred, TNoSuchUser)
            self.assertEqual(u'unknown', error.name)

    @inlineCallbacks
    def testDeleteUserIsDenied(self):
        """
        L{FacadeUserMixin.deleteUser} raises a L{TPathPermissionDenied}
        exception if the user making the request is not a superuser.
        """
        [(objectID, username)] = UserAPI().create([
            (u'user', u'secret', u'User', u'*****@*****.**')
        ])
        self.store.commit()
        with login(u'user', objectID, self.transact) as session:
            deferred = self.facade.deleteUser(session, u'doomed')
            error = yield self.assertFailure(deferred, TPathPermissionDenied)
            self.assertEqual(u'doomed', error.path)