Esempio n. 1
0
        def run():
            objects = SecureObjectAPI(session.auth.user)

            try:
                searchQueries = objects.search(valuesByQuery.keys())
            except UnknownPathError as error:
                session.log.exception(error)
                unknownPath = error.paths[0]
                raise TNonexistentTag(unknownPath.encode('utf-8'))
            except PermissionDeniedError as error:
                session.log.exception(error)
                path_, operation = error.pathsAndOperations[0]
                if operation == Operation.CREATE_OBJECT:
                    raise TUnauthorized()
                else:
                    raise TNonexistentTag(path_)

            # Run queries.
            try:
                with session.timer.track('index-search'):
                    result = blockingCallFromThread(reactor, searchQueries.get)
            except SearchError as error:
                session.log.exception(error)
                raise TParseError(query, error.message)

            # Build a result set from the searches.
            values = {}
            for parsedQuery, objectIDs in result.iteritems():
                for objectID in objectIDs:
                    for tagAndValue in valuesByQuery[parsedQuery]:
                        value = guessValue(tagAndValue.value)
                        # FIXME: this code sucks, but I rather not having
                        # to modify guessValue to return a list, as that
                        # would break other code.
                        # Hopefully, we'll be able to remove this pretty
                        # soon.
                        if isinstance(value, list):
                            value = [item.decode('utf-8') for item in value]
                        if objectID not in values:
                            values[objectID] = {}
                        values[objectID][tagAndValue.path] = value

            # Update values.
            if values:
                tagValues = SecureTagValueAPI(session.auth.user)
                try:
                    result = tagValues.set(values)
                except UnknownPathError as error:
                    session.log.exception(error)
                    path = error.paths[0]
                    raise TNonexistentTag(path.encode('utf-8'))
                except MalformedPathError as error:
                    # FIXME: Modify MalformedPathError to have a path field.
                    raise TInvalidPath(str(error).encode('utf-8'))
                except PermissionDeniedError as error:
                    session.log.exception(error)
                    path_, operation = error.pathsAndOperations[0]
                    category, action = getCategoryAndAction(operation)
                    raise TPathPermissionDenied(category, action, path_)
Esempio n. 2
0
class SecureObjectAPIWithAnonymousRoleTest(FluidinfoTestCase):

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

    def setUp(self):
        super(SecureObjectAPIWithAnonymousRoleTest, self).setUp()
        system = createSystemData()
        self.anon = system.users[u'anon']
        UserAPI().create([(u'username', u'password', u'User',
                           u'*****@*****.**')])
        self.user = getUser(u'username')
        self.tags = TagAPI(self.user)
        self.tags.create([(u'username/tag', u'description')])
        self.permissions = CachingPermissionAPI(self.user)
        self.objects = SecureObjectAPI(self.anon)

    def testCreateIsDenied(self):
        """
        L{SecureObjectAPI.create} raises a L{PermissionDeniedError} if it's
        invoked by a L{User} with the L{Role.ANONYMOUS}.
        """
        objects = SecureObjectAPI(self.anon)
        error = self.assertRaises(PermissionDeniedError, objects.create)
        self.assertEqual(self.anon.username, error.username)
        self.assertEqual([(None, Operation.CREATE_OBJECT)],
                         error.pathsAndOperations)

    def testGetTagsByObjectsPathIsAllowed(self):
        """
        L{SecureObjectAPI.getTagsByObjects} will return all the tags for
        which the anonymous user has C{Operation.READ_TAG_VALUE} permissions.
        """
        objectID = uuid4()
        values = {objectID: {u'username/tag': 16}}
        SecureTagValueAPI(self.user).set(values)
        self.permissions.set([(u'username/tag', Operation.READ_TAG_VALUE,
                               Policy.OPEN, [])])
        self.assertEqual({objectID: [u'username/tag']},
                         self.objects.getTagsByObjects([objectID]))

    def testGetTagsByObjectsReturnsOnlyAllowedTags(self):
        """
        L{SecureObjectAPI.getTagsByObjects} will return all the tags for
        which the anonymous user has C{Operation.READ_TAG_VALUE} permissions,
        but not those for which the user doesn't have.
        """
        self.tags.create([(u'username/tag1', u'description'),
                          (u'username/tag2', u'description')])
        objectID = uuid4()

        values = {objectID: {u'username/tag1': 16,
                             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, [])])

        result = self.objects.getTagsByObjects([objectID])
        expected = {objectID: [u'username/tag2']}
        self.assertEqual(expected, result)

    def testGetTagsByObjectsReturnsNoneIfDenied(self):
        """
        L{SecureObjectAPI.getTagsByObjects} will return an empty C{dict} if
        the L{User} does not have C{Operation.READ_TAG_VALUE} permission on
        none of the L{Tag}s an object has.
        """
        self.tags.create([(u'username/tag1', u'description'),
                          (u'username/tag2', u'description')])
        objectID = uuid4()

        values = {objectID: {u'username/tag1': 16,
                             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, [])])

        result = self.objects.getTagsByObjects([objectID])
        self.assertEqual({}, result)

    def testGetTagsByObjectsWithCustomPermission(self):
        """
        L{SecureObjectAPI.getTagsByObjects} optionally accepts a permission
        type to check for instead of L{Operation.READ_TAG_VALUE}).
        """
        TagAPI(self.user).create([(u'username/open', u'An accessible tag'),
                                  (u'username/closed', u'A denied tag')])
        objectID = uuid4()
        SecureTagValueAPI(self.user).set({objectID: {u'username/open': 13,
                                                     u'username/closed': 17}})
        self.permissions.set([(u'username/closed', Operation.DELETE_TAG_VALUE,
                               Policy.CLOSED, [])])
        result = self.objects.getTagsByObjects(
            [objectID], permission=Operation.DELETE_TAG_VALUE)
        # Result is empty because anonymous users are never allowed to delete
        # values.
        self.assertEqual({}, result)

    def testGetTagsForObjectsOnlyReturnsAccessibleTags(self):
        """
        L{SecureObjectAPI.getTagsForObjects} only returns L{Tag.path}s that
        the user has C{Operation.READ_TAG_VALUE} permissions for.
        """
        TagAPI(self.user).create([(u'username/tag1', u'description'),
                                  (u'username/tag2', u'description')])
        objectID = uuid4()
        SecureTagValueAPI(self.user).set({objectID: {u'username/tag1': 13,
                                                     u'username/tag2': 17}})
        self.permissions.set([(u'username/tag2', Operation.READ_TAG_VALUE,
                               Policy.CLOSED, [])])
        self.assertEqual([u'username/tag1'],
                         self.objects.getTagsForObjects([objectID]))

    @inlineCallbacks
    def testSearch(self):
        """
        L{SecureObjectAPI.search} resolves the specified L{Query}s if the
        anonymous user has C{Operation.READ_TAG_VALUE} permissions on the
        requested L{Tag.path}s.
        """
        objectID = uuid4()
        index = ObjectIndex(self.client)
        yield index.update({objectID: {u'username/tag': 42}})
        yield self.client.commit()
        query = parseQuery(u'username/tag = 42')
        result = self.objects.search([query])
        result = yield result.get()
        self.assertEqual({query: set([objectID])}, result)

    @inlineCallbacks
    def testSearchWithoutPermission(self):
        """
        L{SecureObjectAPI.search} raises a L{PermissionDeniedError} if the
        anonymous user doesn't have C{Operation.READ_TAG_VALUE} permissions on
        the requested L{Tag.path}s.
        """
        objectID = uuid4()
        index = ObjectIndex(self.client)
        yield index.update({objectID: {u'username/tag': 42}})
        yield self.client.commit()
        self.permissions.set([(u'username/tag', Operation.READ_TAG_VALUE,
                               Policy.CLOSED, [])])
        query = parseQuery(u'username/tag = 42')
        error = self.assertRaises(PermissionDeniedError, self.objects.search,
                                  [query])
        self.assertEqual(u'anon', error.username)
        self.assertEqual([('username/tag', Operation.READ_TAG_VALUE)],
                         error.pathsAndOperations)

    @inlineCallbacks
    def testSearchWithImplicitObjectCreation(self):
        """
        L{SecureObjectAPI.search} doesn't raise a L{PermissionDeniedError} if
        the anonymous user tries to create new objects using C{fluiddb/about}
        queries, instead an empty result is returned.
        """
        query = parseQuery(u'fluiddb/about = "TestObject"')
        result = self.objects.search([query], True)
        result = yield result.get()
        self.assertEqual({query: set()}, result)