Beispiel #1
0
class SecurePermissionAPI(object):
    """The public API to secure permission-related functionality.

    @param user: The L{User} to perform operations on behalf of.
    """

    def __init__(self, user):
        self._user = user
        self._permissions = CachingPermissionAPI(user)

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

        @raise PermissionDeniedError: Raised if the user is not authorized to
            see the specified permissions.
        """
        self._checkPermissions(values)
        return self._permissions.get(values)

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

        @raise PermissionDeniedError: Raised if the user is not authorized to
            change the specified permissions.
        """
        self._checkPermissions([(path, operation)
                                for path, operation, _, _ in values])
        return self._permissions.set(values)

    def _checkPermissions(self, values):
        """Check C{CONTROL} permissions for a set of path-operation pairs.

        @param values: A sequence of C{(path, Operation)} 2-tuples with the
            that should be checked.
        @raise PermissionDeniedError: Raised if the user doesn't have
            C{CONTROL} permissions for a given path-L{Operation} pair.
        @raise RuntimeError: Raised if an invalid L{Operation} is provided.
        """
        pathsAndOperations = set()
        for path, operation in values:
            if operation in [Operation.WRITE_TAG_VALUE,
                             Operation.READ_TAG_VALUE,
                             Operation.DELETE_TAG_VALUE,
                             Operation.CONTROL_TAG_VALUE]:
                pathsAndOperations.add((path, Operation.CONTROL_TAG_VALUE))
            elif operation in [Operation.UPDATE_TAG, Operation.DELETE_TAG,
                               Operation.CONTROL_TAG]:
                pathsAndOperations.add((path, Operation.CONTROL_TAG))
            elif operation in Operation.NAMESPACE_OPERATIONS:
                pathsAndOperations.add((path, Operation.CONTROL_NAMESPACE))
            else:
                raise RuntimeError('Invalid operation %r.' % operation)

        deniedOperations = checkPermissions(self._user, pathsAndOperations)
        if deniedOperations:
            raise PermissionDeniedError(self._user.username, deniedOperations)
Beispiel #2
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)