Exemplo n.º 1
0
class CachingPermissionAPI(object):
    """The public API to cached permission-related logic in the model."""
    def __init__(self, user):
        self._api = PermissionAPI(user, factory=CachingAPIFactory())

    def set(self, values):
        """See L{PermissionAPI.set}.

        Modified permissions are removed from the cache.
        """
        namespacePaths = [
            path for (path, operation, _, _) in values
            if operation in Operation.NAMESPACE_OPERATIONS
        ]
        tagPaths = [
            path for (path, operation, _, _) in values
            if operation in Operation.TAG_OPERATIONS
        ]
        cache = PermissionCache()
        cache.clearNamespacePermissions(namespacePaths)
        cache.clearTagPermissions(tagPaths)
        self._api.set(values)

    def get(self, values):
        """See L{PermissionAPI.get}."""
        return self._api.get(values)
Exemplo n.º 2
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)
Exemplo n.º 3
0
class SuperuserPermissionCheckerTest(CheckPermissionsTestMixin,
                                     FluidinfoTestCase):

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

    def setUp(self):
        super(SuperuserPermissionCheckerTest, self).setUp()
        self.system = createSystemData()
        UserAPI().create([(u'username', u'password', u'User',
                           u'*****@*****.**')])
        self.user = getUser(u'username')
        self.permissions = PermissionAPI(self.user)

    def testCheckWithSuperuser(self):
        """
        L{checkPermissions} always grants access if the user is superuser.
        """
        TagAPI(self.user).create([(u'username/path', u'description')])
        NamespaceAPI(self.user).create([(u'username/path', u'description')])
        superuser = self.system.users[u'fluiddb']
        # Close all permissions for the tag
        values = [(u'username/path', operation, Policy.CLOSED, [])
                  for operation in Operation.PATH_OPERATIONS]
        self.permissions.set(values)

        values = [(u'username/path', operation)
                  for operation in Operation.PATH_OPERATIONS]
        deniedOperations = checkPermissions(superuser, values)
        self.assertEqual([], deniedOperations)

    def testCheckWithSuperuserUnknownPaths(self):
        """
        L{checkPermissions} raises L{UnknownPathError} if a superuser checks
        permissions for nonexistent tags.
        """
        superuser = self.system.users[u'fluiddb']
        values = [(u'unknown/path', operation)
                  for operation in Operation.PATH_OPERATIONS]
        self.assertRaises(UnknownPathError,
                          checkPermissions, superuser, values)

    def testCheckWithSuperuserWithImplicitPaths(self):
        """
        L{checkPermissions} raises L{UnknownPathError} if a superuser
        checks permissions for nonexistent tags, even if it might be possible
        to create them implicitly.
        """
        superuser = self.system.users[u'fluiddb']
        values = [(u'fluiddb/path', operation)
                  for operation in Operation.PATH_OPERATIONS]
        self.assertRaises(UnknownPathError,
                          checkPermissions, superuser, values)

    def testCheckWithSuperuserWithMissingPermission(self):
        """
        L{checkPermissions} always grants access if the user is superuser,
        even if there is no permission defined for the entity for which access
        is requested.
        """
        TagAPI(self.user).create([(u'username/path', u'description')])
        NamespaceAPI(self.user).create([(u'username/path', u'description')])
        superuser = self.system.users[u'fluiddb']
        # Close all permissions for the tag
        values = [(u'username/path', operation, Policy.CLOSED, [])
                  for operation in Operation.NAMESPACE_OPERATIONS]
        self.permissions.set(values)

        values = [(u'username/path', operation)
                  for operation in Operation.NAMESPACE_OPERATIONS]
        deniedOperations = checkPermissions(superuser, values)
        self.assertEqual([], deniedOperations)

    def testCheckSuperuserWithFluidDBSlashIDVirtualPath(self):
        """
        An L{UnknownPathError} is not raised when the special C{fluiddb/id}
        virtual tag is encountered and L{Tag}-related permission checks always
        succeed.
        """
        superuser = self.system.users[u'fluiddb']
        values = [(u'fluiddb/id', Operation.READ_TAG_VALUE)]
        self.assertEqual([], checkPermissions(superuser, values))
Exemplo n.º 4
0
class UserPermissionCheckerTest(CheckPermissionsTestMixin, FluidinfoTestCase):

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

    def setUp(self):
        super(UserPermissionCheckerTest, self).setUp()
        self.system = createSystemData()
        UserAPI().create([(u'username', u'password', u'User',
                           u'*****@*****.**')])
        self.user = getUser(u'username')
        self.permissions = PermissionAPI(self.user)

    def testCheckOpenPermission(self):
        """
        L{checkPermissions} grants access when the policy is C{Policy.OPEN}
        and the L{User.id} is not in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.OPEN, [])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckOpenPermissionWithException(self):
        """
        L{checkPermissions} denies access when the policy is C{Policy.OPEN}
        and the L{User.id} is in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.OPEN, [u'username'])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username/tag', Operation.UPDATE_TAG)],
                         list(deniedOperations))

    def testCheckClosedPermission(self):
        """
        L{checkPermissions} denies access when the policy is
        C{Policy.CLOSED} and the L{User.id} is not in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.CLOSED, [])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username/tag', Operation.UPDATE_TAG)],
                         deniedOperations)

    def testCheckClosedPermissionWithException(self):
        """
        L{checkPermissions} grants access when the policy is C{Policy.OPEN}
        and the L{User.id} is in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.CLOSED, [u'username'])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckMultipleOpenPermissions(self):
        """L{checkPermissions} can check multiple permissions."""
        UserAPI().create([(u'user1', 'hash', u'User', u'*****@*****.**')])
        UserAPI().create([(u'user2', 'hash', u'User', u'*****@*****.**')])
        user1 = getUser(u'user1')
        user2 = getUser(u'user2')

        TagAPI(user1).create([(u'user1/tag', u'description')])
        self.permissions.set([(u'user1/tag', Operation.UPDATE_TAG,
                               Policy.OPEN, [u'user1', u'user2'])])

        TagAPI(user2).create([(u'user2/tag', u'description')])
        self.permissions.set([(u'user2/tag', Operation.WRITE_TAG_VALUE,
                               Policy.CLOSED, [u'username'])])

        values = [(u'user1/tag', Operation.UPDATE_TAG),
                  (u'user2/tag', Operation.WRITE_TAG_VALUE)]

        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckUserWithUnknownPath(self):
        """
        L{checkPermissions} raises L{UnknownPathError} if a given path does
        not exist.
        """
        values = [(u'unknown/path', Operation.LIST_NAMESPACE)]
        error = self.assertRaises(UnknownPathError, checkPermissions,
                                  self.user, values)
        self.assertEqual([u'unknown/path'], error.paths)

    def testCheckUserWithImplicitTagPath(self):
        """
        L{checkPermissions} ignores an unknown path when a
        L{Operation.WRITE_TAG_VALUE} operation is requested and when the user
        has L{Operation.CREATE_NAMESPACE} access on the parent L{Namespace}.
        """
        values = [(u'username/unknown', Operation.WRITE_TAG_VALUE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithImplicitNamespacePath(self):
        """
        L{checkPermissions} ignores an unknown path when a
        L{Operation.CREATE_NAMESPACE} operation is requested and when the user
        has L{Operation.CREATE_NAMESPACE} access on the final existing
        parent's L{Namespace}.
        """
        values = [(u'username/namespace', Operation.CREATE_NAMESPACE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithImplicitTagAndNamespace(self):
        """
        L{checkPermissions} ignores an unknown path when a
        L{Operation.WRITE_TAG_VALUE} operation is requested and when the user
        has L{Operation.CREATE_NAMESPACE} access on the final existing
        parent's L{Namespace}.
        """
        values = set([(u'username/tag', Operation.WRITE_TAG_VALUE),
                      (u'username/namespace/tag', Operation.WRITE_TAG_VALUE)])
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithImplicitNestedNamespacePath(self):
        """
        L{checkPermissions} does a recursive check to find the parent
        L{Namespace} when a path includes many unknown segments.
        """
        values = [(u'username/nested/namespace', Operation.CREATE_NAMESPACE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithFluidDBSlashIDVirtualPath(self):
        """
        An L{UnknownPathError} is not raised when the special C{fluiddb/id}
        virtual tag is encountered and L{Tag}-related permission checks always
        succeed.
        """
        values = [(u'fluiddb/id', Operation.READ_TAG_VALUE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithMissingPermission(self):
        """
        L{checkPermissions} denies the operation if, for some
        reason, a permission is not available for the entity being requested.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        # FIXME: don't use data functions here.
        [(tag, permission)] = getTagPermissions([u'username/tag'])
        self.store.remove(permission)
        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username/tag', Operation.UPDATE_TAG)],
                         deniedOperations)

    def testCheckReturnsMultipleDeniedPermissions(self):
        """
        L{checkPermissions} returns a C{list} of all denied paths and
        L{Operation}s for the requested actions.
        """
        UserAPI().create([(u'user1', 'hash', u'User', u'*****@*****.**')])
        UserAPI().create([(u'user2', 'hash', u'User', u'*****@*****.**')])
        user1 = getUser(u'user1')
        user2 = getUser(u'user2')

        TagAPI(user1).create([(u'user1/tag', u'description')])
        self.permissions.set([(u'user1/tag', Operation.UPDATE_TAG,
                               Policy.OPEN, [u'user1', u'user2'])])

        TagAPI(user2).create([(u'user2/tag', u'description')])
        self.permissions.set([(u'user2/tag', Operation.WRITE_TAG_VALUE,
                               Policy.OPEN, [u'username'])])

        values = [(u'user1/tag', Operation.UPDATE_TAG),
                  (u'user2/tag', Operation.WRITE_TAG_VALUE)]
        deniedOperations = checkPermissions(self.user, values)
        expected = [(u'user2/tag', Operation.WRITE_TAG_VALUE)]
        self.assertEqual(sorted(expected), sorted(deniedOperations))

    def testCheckUserManagerHasAccessToPerformUserOperations(self):
        """
        L{checkPermissions} always allows user L{Operation}s for
        L{Role.USER_MANAGER} users.
        """
        self.user.role = Role.USER_MANAGER
        values = [(u'username', Operation.CREATE_USER),
                  (u'username', Operation.UPDATE_USER),
                  (u'username', Operation.DELETE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckCreateRootNamespaceIsAlwaysDeniedForNormalUser(self):
        """
        L{checkPermissions} always denies C{CREATE_NAMESPACE} access on the
        root namespace for normal users.
        """
        values = [(None, Operation.CREATE_NAMESPACE)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(None, Operation.CREATE_NAMESPACE)],
                         deniedOperations)

    def testCheckDeleteRootNamespaceIsAlwaysDeniedForNormalUser(self):
        """
        L{checkPermissions} always denies C{DELETE_NAMESPACE} access on the
        root namespace for normal users.
        """
        values = [(u'username', Operation.DELETE_NAMESPACE)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username', Operation.DELETE_NAMESPACE)],
                         deniedOperations)

    def testCheckCreateObjectIsAlwaysGrantedForNormalUser(self):
        """
        L{checkPermissions} always grants C{CREATE_OBJECT} access for
        normal users.
        """
        values = [(u'', Operation.CREATE_OBJECT)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckCreateUserIsAlwaysDeniedForNormalUser(self):
        """
        L{checkPermissions} always denies C{CREATE_USER} access for normal
        users.
        """
        values = [(u'username', Operation.CREATE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username', Operation.CREATE_USER)],
                         deniedOperations)

    def testCheckUpdateUserIsDeniedForOtherNormalUsers(self):
        """
        L{checkPermissions} denies C{UPDATE_USER} access for normal
        users except the own user.
        """
        UserAPI().create([(u'otheruser', u'password', u'User',
                           u'*****@*****.**')])
        values = [(u'otheruser', Operation.UPDATE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'otheruser', Operation.UPDATE_USER)],
                         deniedOperations)

    def testCheckUpdateUserIsAllowedForTheOwnUser(self):
        """
        L{checkPermissions} allows C{UPDATE_USER} access for normal
        users if the requesting user is the same modified user.
        """
        values = [(u'username', Operation.UPDATE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)
Exemplo n.º 5
0
class SuperuserPermissionCheckerTest(CheckPermissionsTestMixin,
                                     FluidinfoTestCase):

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

    def setUp(self):
        super(SuperuserPermissionCheckerTest, self).setUp()
        self.system = createSystemData()
        UserAPI().create([(u'username', u'password', u'User',
                           u'*****@*****.**')])
        self.user = getUser(u'username')
        self.permissions = PermissionAPI(self.user)

    def testCheckWithSuperuser(self):
        """
        L{checkPermissions} always grants access if the user is superuser.
        """
        TagAPI(self.user).create([(u'username/path', u'description')])
        NamespaceAPI(self.user).create([(u'username/path', u'description')])
        superuser = self.system.users[u'fluiddb']
        # Close all permissions for the tag
        values = [(u'username/path', operation, Policy.CLOSED, [])
                  for operation in Operation.PATH_OPERATIONS]
        self.permissions.set(values)

        values = [(u'username/path', operation)
                  for operation in Operation.PATH_OPERATIONS]
        deniedOperations = checkPermissions(superuser, values)
        self.assertEqual([], deniedOperations)

    def testCheckWithSuperuserUnknownPaths(self):
        """
        L{checkPermissions} raises L{UnknownPathError} if a superuser checks
        permissions for nonexistent tags.
        """
        superuser = self.system.users[u'fluiddb']
        values = [(u'unknown/path', operation)
                  for operation in Operation.PATH_OPERATIONS]
        self.assertRaises(UnknownPathError, checkPermissions, superuser,
                          values)

    def testCheckWithSuperuserWithImplicitPaths(self):
        """
        L{checkPermissions} raises L{UnknownPathError} if a superuser
        checks permissions for nonexistent tags, even if it might be possible
        to create them implicitly.
        """
        superuser = self.system.users[u'fluiddb']
        values = [(u'fluiddb/path', operation)
                  for operation in Operation.PATH_OPERATIONS]
        self.assertRaises(UnknownPathError, checkPermissions, superuser,
                          values)

    def testCheckWithSuperuserWithMissingPermission(self):
        """
        L{checkPermissions} always grants access if the user is superuser,
        even if there is no permission defined for the entity for which access
        is requested.
        """
        TagAPI(self.user).create([(u'username/path', u'description')])
        NamespaceAPI(self.user).create([(u'username/path', u'description')])
        superuser = self.system.users[u'fluiddb']
        # Close all permissions for the tag
        values = [(u'username/path', operation, Policy.CLOSED, [])
                  for operation in Operation.NAMESPACE_OPERATIONS]
        self.permissions.set(values)

        values = [(u'username/path', operation)
                  for operation in Operation.NAMESPACE_OPERATIONS]
        deniedOperations = checkPermissions(superuser, values)
        self.assertEqual([], deniedOperations)

    def testCheckSuperuserWithFluidDBSlashIDVirtualPath(self):
        """
        An L{UnknownPathError} is not raised when the special C{fluiddb/id}
        virtual tag is encountered and L{Tag}-related permission checks always
        succeed.
        """
        superuser = self.system.users[u'fluiddb']
        values = [(u'fluiddb/id', Operation.READ_TAG_VALUE)]
        self.assertEqual([], checkPermissions(superuser, values))
Exemplo n.º 6
0
class UserPermissionCheckerTest(CheckPermissionsTestMixin, FluidinfoTestCase):

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

    def setUp(self):
        super(UserPermissionCheckerTest, self).setUp()
        self.system = createSystemData()
        UserAPI().create([(u'username', u'password', u'User',
                           u'*****@*****.**')])
        self.user = getUser(u'username')
        self.permissions = PermissionAPI(self.user)

    def testCheckOpenPermission(self):
        """
        L{checkPermissions} grants access when the policy is C{Policy.OPEN}
        and the L{User.id} is not in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.OPEN, [])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckOpenPermissionWithException(self):
        """
        L{checkPermissions} denies access when the policy is C{Policy.OPEN}
        and the L{User.id} is in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.OPEN, [u'username'])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username/tag', Operation.UPDATE_TAG)],
                         list(deniedOperations))

    def testCheckClosedPermission(self):
        """
        L{checkPermissions} denies access when the policy is
        C{Policy.CLOSED} and the L{User.id} is not in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.CLOSED, [])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username/tag', Operation.UPDATE_TAG)],
                         deniedOperations)

    def testCheckClosedPermissionWithException(self):
        """
        L{checkPermissions} grants access when the policy is C{Policy.OPEN}
        and the L{User.id} is in the exceptions list.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        self.permissions.set([(u'username/tag', Operation.UPDATE_TAG,
                               Policy.CLOSED, [u'username'])])

        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckMultipleOpenPermissions(self):
        """L{checkPermissions} can check multiple permissions."""
        UserAPI().create([(u'user1', 'hash', u'User', u'*****@*****.**')])
        UserAPI().create([(u'user2', 'hash', u'User', u'*****@*****.**')])
        user1 = getUser(u'user1')
        user2 = getUser(u'user2')

        TagAPI(user1).create([(u'user1/tag', u'description')])
        self.permissions.set([(u'user1/tag', Operation.UPDATE_TAG, Policy.OPEN,
                               [u'user1', u'user2'])])

        TagAPI(user2).create([(u'user2/tag', u'description')])
        self.permissions.set([(u'user2/tag', Operation.WRITE_TAG_VALUE,
                               Policy.CLOSED, [u'username'])])

        values = [(u'user1/tag', Operation.UPDATE_TAG),
                  (u'user2/tag', Operation.WRITE_TAG_VALUE)]

        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckUserWithUnknownPath(self):
        """
        L{checkPermissions} raises L{UnknownPathError} if a given path does
        not exist.
        """
        values = [(u'unknown/path', Operation.LIST_NAMESPACE)]
        error = self.assertRaises(UnknownPathError, checkPermissions,
                                  self.user, values)
        self.assertEqual([u'unknown/path'], error.paths)

    def testCheckUserWithImplicitTagPath(self):
        """
        L{checkPermissions} ignores an unknown path when a
        L{Operation.WRITE_TAG_VALUE} operation is requested and when the user
        has L{Operation.CREATE_NAMESPACE} access on the parent L{Namespace}.
        """
        values = [(u'username/unknown', Operation.WRITE_TAG_VALUE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithImplicitNamespacePath(self):
        """
        L{checkPermissions} ignores an unknown path when a
        L{Operation.CREATE_NAMESPACE} operation is requested and when the user
        has L{Operation.CREATE_NAMESPACE} access on the final existing
        parent's L{Namespace}.
        """
        values = [(u'username/namespace', Operation.CREATE_NAMESPACE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithImplicitTagAndNamespace(self):
        """
        L{checkPermissions} ignores an unknown path when a
        L{Operation.WRITE_TAG_VALUE} operation is requested and when the user
        has L{Operation.CREATE_NAMESPACE} access on the final existing
        parent's L{Namespace}.
        """
        values = set([(u'username/tag', Operation.WRITE_TAG_VALUE),
                      (u'username/namespace/tag', Operation.WRITE_TAG_VALUE)])
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithImplicitNestedNamespacePath(self):
        """
        L{checkPermissions} does a recursive check to find the parent
        L{Namespace} when a path includes many unknown segments.
        """
        values = [(u'username/nested/namespace', Operation.CREATE_NAMESPACE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithFluidDBSlashIDVirtualPath(self):
        """
        An L{UnknownPathError} is not raised when the special C{fluiddb/id}
        virtual tag is encountered and L{Tag}-related permission checks always
        succeed.
        """
        values = [(u'fluiddb/id', Operation.READ_TAG_VALUE)]
        self.assertEqual([], checkPermissions(self.user, values))

    def testCheckUserWithMissingPermission(self):
        """
        L{checkPermissions} denies the operation if, for some
        reason, a permission is not available for the entity being requested.
        """
        TagAPI(self.user).create([(u'username/tag', u'description')])
        # FIXME: don't use data functions here.
        [(tag, permission)] = getTagPermissions([u'username/tag'])
        self.store.remove(permission)
        values = [(u'username/tag', Operation.UPDATE_TAG)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username/tag', Operation.UPDATE_TAG)],
                         deniedOperations)

    def testCheckReturnsMultipleDeniedPermissions(self):
        """
        L{checkPermissions} returns a C{list} of all denied paths and
        L{Operation}s for the requested actions.
        """
        UserAPI().create([(u'user1', 'hash', u'User', u'*****@*****.**')])
        UserAPI().create([(u'user2', 'hash', u'User', u'*****@*****.**')])
        user1 = getUser(u'user1')
        user2 = getUser(u'user2')

        TagAPI(user1).create([(u'user1/tag', u'description')])
        self.permissions.set([(u'user1/tag', Operation.UPDATE_TAG, Policy.OPEN,
                               [u'user1', u'user2'])])

        TagAPI(user2).create([(u'user2/tag', u'description')])
        self.permissions.set([(u'user2/tag', Operation.WRITE_TAG_VALUE,
                               Policy.OPEN, [u'username'])])

        values = [(u'user1/tag', Operation.UPDATE_TAG),
                  (u'user2/tag', Operation.WRITE_TAG_VALUE)]
        deniedOperations = checkPermissions(self.user, values)
        expected = [(u'user2/tag', Operation.WRITE_TAG_VALUE)]
        self.assertEqual(sorted(expected), sorted(deniedOperations))

    def testCheckUserManagerHasAccessToPerformUserOperations(self):
        """
        L{checkPermissions} always allows user L{Operation}s for
        L{Role.USER_MANAGER} users.
        """
        self.user.role = Role.USER_MANAGER
        values = [(u'username', Operation.CREATE_USER),
                  (u'username', Operation.UPDATE_USER),
                  (u'username', Operation.DELETE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckCreateRootNamespaceIsAlwaysDeniedForNormalUser(self):
        """
        L{checkPermissions} always denies C{CREATE_NAMESPACE} access on the
        root namespace for normal users.
        """
        values = [(None, Operation.CREATE_NAMESPACE)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(None, Operation.CREATE_NAMESPACE)],
                         deniedOperations)

    def testCheckDeleteRootNamespaceIsAlwaysDeniedForNormalUser(self):
        """
        L{checkPermissions} always denies C{DELETE_NAMESPACE} access on the
        root namespace for normal users.
        """
        values = [(u'username', Operation.DELETE_NAMESPACE)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username', Operation.DELETE_NAMESPACE)],
                         deniedOperations)

    def testCheckCreateObjectIsAlwaysGrantedForNormalUser(self):
        """
        L{checkPermissions} always grants C{CREATE_OBJECT} access for
        normal users.
        """
        values = [(u'', Operation.CREATE_OBJECT)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)

    def testCheckCreateUserIsAlwaysDeniedForNormalUser(self):
        """
        L{checkPermissions} always denies C{CREATE_USER} access for normal
        users.
        """
        values = [(u'username', Operation.CREATE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'username', Operation.CREATE_USER)],
                         deniedOperations)

    def testCheckUpdateUserIsDeniedForOtherNormalUsers(self):
        """
        L{checkPermissions} denies C{UPDATE_USER} access for normal
        users except the own user.
        """
        UserAPI().create([(u'otheruser', u'password', u'User',
                           u'*****@*****.**')])
        values = [(u'otheruser', Operation.UPDATE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([(u'otheruser', Operation.UPDATE_USER)],
                         deniedOperations)

    def testCheckUpdateUserIsAllowedForTheOwnUser(self):
        """
        L{checkPermissions} allows C{UPDATE_USER} access for normal
        users if the requesting user is the same modified user.
        """
        values = [(u'username', Operation.UPDATE_USER)]
        deniedOperations = checkPermissions(self.user, values)
        self.assertEqual([], deniedOperations)
Exemplo n.º 7
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)