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 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 testPrepareForTestingCreatesTags(self): """ L{prepareForTesting} creates all the necessary testing L{Tag}s. """ prepareForTesting() paths = [ u'fluiddb/testing/test1', u'fluiddb/testing/test2', u'testuser1/testing/test1', u'testuser1/testing/test2', u'testuser2/testing/test1', u'testuser2/testing/test2' ] tags = TagAPI(self.admin).get(paths) self.assertEqual(paths, sorted(tags.iterkeys()))
def testPrepareForTestingCreatesTags(self): """ L{prepareForTesting} creates all the necessary testing L{Tag}s. """ prepareForTesting() paths = [u'fluiddb/testing/test1', u'fluiddb/testing/test2', u'testuser1/testing/test1', u'testuser1/testing/test2', u'testuser2/testing/test1', u'testuser2/testing/test2'] tags = TagAPI(self.admin).get(paths) self.assertEqual(paths, sorted(tags.iterkeys()))
def removeTestingData(): """ Delete L{User}s, L{Namespace}s and L{Tag}s used for testing purposes. """ admin = getUser(u'fluiddb') logging.info('Deleting testing tags.') result = TagAPI(admin).get(TESTING_DATA[u'tags']) if result: TagAPI(admin).delete(result.keys()) logging.info('Deleting testing namespaces.') result = NamespaceAPI(admin).get(TESTING_DATA[u'namespaces']) # we must delete namespaces one by one, otherwise we'll get NotEmptyError. for path in sorted(result.keys(), reverse=True): NamespaceAPI(admin).delete([path]) logging.info('Deleting testing users.') result = UserAPI().get(TESTING_DATA[u'users']) if result: for username in result: path = '%s/private' % username try: NamespaceAPI(admin).delete([path]) except FeatureError: # FIXME This is a bit crap, but it's faster than checking to # see if the namespace exists before attempting to delete it. continue if result: UserAPI().delete(result.keys()) getMainStore().commit()
def testCreateChildTagWithDelegatedCreator(self): """ L{TagAPI.create} always ensures that a new L{Tag} is usable by the L{User} that created it. In the case of default permissions, the user creating the new L{Tag} is granted L{Operation.UPDATE_TAG}, L{Operation.DELETE_TAG}, L{Operation.WRITE_TAG_VALUE} and L{Operation.DELETE_TAG_VALUE}. """ UserAPI().create([(u'friend', u'secret', u'name', u'*****@*****.**') ]) PermissionAPI(self.user).set([(u'username', Operation.CREATE_NAMESPACE, Policy.CLOSED, [u'username', u'friend'])]) friend = getUser(u'friend') TagAPI(friend).create([(u'username/tag', u'A shared tag')]) result = getTagPermissions([u'username/tag']) tag, permission = result.one() self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.UPDATE_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.DELETE_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.CONTROL_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.WRITE_TAG_VALUE)) self.assertEqual((Policy.OPEN, []), permission.get(Operation.READ_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.DELETE_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.CONTROL_TAG_VALUE))
def testSearchWithManyQueries(self): """ L{ObjectAPI.search} can be used to resolve many L{Query}s at once. """ TagAPI(self.user).create([(u'user/tag', u'description')]) objectID1 = uuid4() objectID2 = uuid4() index = ObjectIndex(self.client) yield index.update({ objectID1: { u'user/tag': 42 }, objectID2: { u'user/tag': 65 } }) yield index.commit() query1 = parseQuery(u'user/tag = 42') query2 = parseQuery(u'user/tag = 65') result = self.objects.search([query1, query2]) result = yield result.get() self.assertEqual({ query1: set([objectID1]), query2: set([objectID2]) }, result)
def testCreatePrivateChildTagWithDelegatedCreator(self): """ L{TagAPI.create} always ensures that a new L{Tag} is usable by the L{User} that created it. If the L{Operation.READ_TAG_VALUE} permission is L{Policy.CLOSED} the creator is added to the exceptions list. """ UserAPI().create([(u'friend', u'secret', u'name', u'*****@*****.**') ]) PermissionAPI(self.user).set([(u'username', Operation.CREATE_NAMESPACE, Policy.CLOSED, [u'username', u'friend']), (u'username', Operation.LIST_NAMESPACE, Policy.CLOSED, [u'username', u'friend'])]) friend = getUser(u'friend') TagAPI(friend).create([(u'username/tag', u'A shared tag')]) result = getTagPermissions([u'username/tag']) tag, permission = result.one() self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.UPDATE_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.DELETE_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.CONTROL_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.WRITE_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.READ_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id, friend.id]), permission.get(Operation.DELETE_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.CONTROL_TAG_VALUE))
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'])
def testCheckIntegrityChecksErrorInAllRows(self): """ L{checkIntegrity} should check for integrity errors in L{Namespace}s, L{Tag}s, L{User}s, L{AboutTagValue}s and L{TagValue}s. """ createSystemData() [(userObjectID, _)] = UserAPI().create([(u'user', u'pass', u'Name', u'*****@*****.**')]) user = getUser(u'user') result = NamespaceAPI(user).create([(u'user/namespace', u'description') ]) [(namespaceObjectID, _)] = result [(tagObjectID, _)] = TagAPI(user).create([(u'user/tag', u'description') ]) objectID1 = uuid4() objectID2 = uuid4() createAboutTagValue(objectID1, u'Bad about tag') TagValueAPI(user).set({objectID2: {u'fluiddb/about': 'about value'}}) TagValueAPI(user).delete([(userObjectID, u'fluiddb/users/username')]) TagValueAPI(user).delete([(namespaceObjectID, u'fluiddb/namespaces/path')]) TagValueAPI(user).delete([(tagObjectID, u'fluiddb/tags/description')]) checkIntegrity() self.assertEqual( "Integrity Error in namespace u'user/namespace': " 'Path tag is missing.\n' "Integrity Error in tag u'user/tag': Description tag is missing.\n" "Integrity Error in user u'user': Username tag is missing.\n" "Integrity Error in object %s: AboutTagValue doesn't have an " 'associated TagValue.\n' "Integrity Error in object %s: fluiddb/about TagValue doesn't " 'have an associated AboutTagValue.\n' % (objectID1, objectID2), self.log.getvalue())
def setUp(self): super(SecureTagValueAPIWithSuperuserRoleTest, self).setUp() system = createSystemData() self.superuser = system.users[u'fluiddb'] TagAPI(self.superuser).create([(u'fluiddb/tag', u'description')]) self.tagValues = SecureTagValueAPI(self.superuser) self.permissions = CachingPermissionAPI(self.superuser)
def setUp(self): super(TagAPITest, self).setUp() self.system = createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') self.permissions = PermissionAPI(self.user) self.tags = TagAPI(self.user)
def setUp(self): super(SecurePermissionAPIWithNormalUserTest, self).setUp() createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) user = getUser(u'username') TagAPI(user).create([(u'username/tag', u'description')]) self.permissions = SecurePermissionAPI(user)
def testCreateChildTagInheritsPermissions(self): """ L{TagAPI.create} creates new L{Namespace}s based on the provided data. """ UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')]) user = getUser(u'user') TagAPI(user).create([(u'user/tag', u'A description')]) self.assertDefaultPermissions(user, u'user/tag')
def setUp(self): super(SecurePermissionAPIWithAnonymousRoleTest, self).setUp() system = createSystemData() user = system.users[u'anon'] self.permissions = SecurePermissionAPI(user) UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) user = getUser(u'username') TagAPI(user).create([(u'username/tag', u'description')])
def testDeltaImportWithDeletedTag(self): """ L{TagValue}s deleted via delete cascade triggered by a L{Tag} deletion should be deleted in the index too. """ objectID = self.objects.create() self.values.set({objectID: {u'user/tag1': u'string', u'user/tag2': u'text'}}) time.sleep(1) runDataImportHandler(self.client.url) tags = TagAPI(self.user) tags.delete([u'user/tag1']) self.store.commit() values = self.values.get([objectID], [u'user/tag1']) self.assertNotIn(u'user/tag1', values[objectID]) runDataImportHandler(self.client.url, clean=False) yield self.assertQuery([], 'has user/tag1') yield self.assertQuery([], 'user/tag1 = "string"')
def setUp(self): super(SecureObjectAPIWithUserRoleTest, self).setUp() createSystemData() UserAPI().create([(u'username', u'password', u'User', u'*****@*****.**')]) self.user = getUser(u'username') TagAPI(self.user).create([(u'username/tag', u'description')]) self.permissions = CachingPermissionAPI(self.user) self.objects = SecureObjectAPI(self.user)
def testGetTagWithDescription(self): """ L{FacadeTagMixin.getTag} includes the L{Tag.description}, if it was requested. """ TagAPI(self.user).create([(u'username/tag', u'A tag.')]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: result = yield self.facade.getTag(session, u'username/tag', True) self.assertEqual(u'A tag.', result.description)
def testCreateActivationTokenTag(self): """ L{bootstrapWebAdminData} creates a C{fluiddb/users/activation-token} tag. """ createSystemData() bootstrapWebAdminData() superuser = getUser(u'fluiddb') result = TagAPI(superuser).get([u'fluiddb/users/activation-token']) self.assertIn(u'fluiddb/users/activation-token', result)
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 testCreateTagWithExistingPath(self): """ L{FacadeTagMixin.createTag} raises a L{TTagAlreadyExists} exception if the new L{Tag} already exists. """ TagAPI(self.user).create([(u'username/name', u'A tag.')]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.createTag( session, u'username', u'name', u'A tag.', 'ignored', 'ignored') yield self.assertFailure(deferred, TTagAlreadyExists)
def testDeleteIsDenied(self): """ L{Facade.deleteTag} raises a L{TPathPermissionDenied} exception if the user doesn't have C{DELETE} permissions on the specified L{Tag}. """ TagAPI(self.user).create([(u'username/test', u'A tag.')]) self.permissions.set([(u'username/test', Operation.DELETE_TAG, Policy.OPEN, [u'username'])]) self.store.commit() with login(u'username', uuid4(), self.transact) as session: deferred = self.facade.deleteTag(session, u'username/test') yield self.assertFailure(deferred, TPathPermissionDenied)
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 testRemoveTestingDataRemovesCreatesTags(self): """L{removeTestingData} removes all the testing L{Tag}s.""" prepareForTesting() removeTestingData() paths = [ u'fluiddb/testing/test1', u'fluiddb/testing/test2', u'testuser1/testing/test1', u'testuser1/testing/test2', u'testuser2/testing/test1', u'testuser2/testing/test2' ] tags = TagAPI(self.admin).get(paths) self.assertEqual({}, tags)
def removeTestingData(): """ Delete L{User}s, L{Namespace}s and L{Tag}s used for testing purposes. """ admin = getUser(u'fluiddb') logging.info('Deleting testing tags.') result = TagAPI(admin).get(TESTING_DATA[u'tags']) if result: TagAPI(admin).delete(result.keys()) logging.info('Deleting testing namespaces.') result = NamespaceAPI(admin).get(TESTING_DATA[u'namespaces']) # we must delete namespaces one by one, otherwise we'll get NotEmptyError. for path in sorted(result.keys(), reverse=True): NamespaceAPI(admin).delete([path]) logging.info('Deleting testing users.') result = UserAPI().get(TESTING_DATA[u'users']) if result: for username in result: path = '%s/private' % username try: NamespaceAPI(admin).delete([path]) except FeatureError: # FIXME This is a bit crap, but it's faster than checking to # see if the namespace exists before attempting to delete it. continue if result: UserAPI().delete(result.keys()) getMainStore().commit()
def testGetTag(self): """ L{FacadeTagMixin.getTag} returns a L{TTag} instance with information about the requested L{Tag}. """ result = TagAPI(self.user).create([(u'username/tag', u'description')]) [(objectID, path)] = result self.store.commit() with login(u'username', uuid4(), self.transact) as session: result = yield self.facade.getTag(session, u'username/tag', False) self.assertEqual(str(objectID), result.objectId) self.assertEqual(u'username/tag', result.path) self.assertTrue(result.indexed)
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)
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)
def testSetInvalidatesCachedTagPermissions(self): """ L{CachingPermissionAPI.set} invalidates L{TagPermission}s to ensure the cache is always fresh. """ TagAPI(self.user).create([(u'username/tag', u'A tag')]) _, permission = getTagPermissions(paths=[u'username/tag']).one() cache = PermissionCache() cache.saveTagPermissions({u'username/tag': permission}) self.permissions.set([(u'username/tag', Operation.UPDATE_TAG, Policy.OPEN, [])]) cached = cache.getTagPermissions([u'username/tag']) self.assertEqual({}, cached.results) self.assertEqual([u'username/tag'], cached.uncachedValues)
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 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]))
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)
def testGetTagPermissionsCachesMisses(self): """ L{CachingPermissionCheckerAPI.getTagPermissions} adds missing L{TagPermission}s to the cache. """ TagAPI(self.user).create([(u'username/tag', u'A tag')]) result = self.api.getTagPermissions([u'username/tag']) permission = result[u'username/tag'] self.assertTrue(isinstance(permission, TagPermission)) # Go behind everyone's back and kill the TagPermission. self.store.find(TagPermission).remove() result = self.api.getTagPermissions([u'username/tag']) permission = result[u'username/tag'] self.assertTrue(isinstance(permission, TagPermission))
def __init__(self, user): self._api = TagAPI(user, factory=CachingAPIFactory())
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)