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']))
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'])
class CachingTagAPI(object): """The public API to cached tag-related logic in the model. @param user: The L{User} to perform operations on behalf of. """ def __init__(self, user): self._api = TagAPI(user, factory=CachingAPIFactory()) def create(self, values): """See L{TagAPI.create}.""" return self._api.create(values) def delete(self, paths): """See L{TagAPI.delete}. Permissions for deleted L{Tag}s are removed from the cache. """ if isgenerator(paths): paths = list(paths) # FIXME getObjectIDs is called twice--once here and once in # TagAPI.delete. It would be better if we only did this once, not to # mention that this breaks encapsulation by bypassing the model layer # and accessing the data layer directly. -jkakar objectIDs = set(getObjectIDs(paths)) RecentObjectActivityCache().clear(objectIDs) usernames = set([path.split('/')[0] for path in paths]) RecentUserActivityCache().clear(usernames) PermissionCache().clearTagPermissions(paths) return self._api.delete(paths) def get(self, paths, withDescriptions=None): """See L{TagAPI.get}.""" return self._api.get(paths, withDescriptions=withDescriptions) def set(self, values): """Set L{TagAPI.set}.""" return self._api.set(values)
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)