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)
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)
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)
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 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 testCreateChildTagInheritsParentNamespacePermissions(self): """ L{TagAPI.create} creates new L{Tag}s with permissions inherited from the parent L{Namespace}'s permissions. """ PermissionAPI(self.user).set([ (u'username', Operation.CREATE_NAMESPACE, Policy.CLOSED, [u'username']), (u'username', Operation.UPDATE_NAMESPACE, Policy.OPEN, []), (u'username', Operation.DELETE_NAMESPACE, Policy.OPEN, []), (u'username', Operation.LIST_NAMESPACE, Policy.CLOSED, [u'username']), (u'username', Operation.CONTROL_NAMESPACE, Policy.OPEN, []) ]) self.tags.create([(u'username/tag', u'A child tag')]) result = getTagPermissions([u'username/tag']) tag, permission = result.one() self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.UPDATE_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.DELETE_TAG)) self.assertEqual((Policy.OPEN, []), permission.get(Operation.CONTROL_TAG)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.WRITE_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.READ_TAG_VALUE)) self.assertEqual((Policy.CLOSED, [self.user.id]), permission.get(Operation.DELETE_TAG_VALUE)) self.assertEqual((Policy.OPEN, []), permission.get(Operation.CONTROL_TAG_VALUE))
def setVersionTag(version): """Updates the fluiddb/version tag. @param version: The new version string. """ user = getUser(u'fluiddb') objectID = ObjectAPI(user).create(u'fluidinfo') releaseDate = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') values = { objectID: { u'fluiddb/api-version': { 'mime-type': 'text/plain', 'contents': version }, u'fluiddb/release-date': { 'mime-type': 'text/plain', 'contents': releaseDate + '\n' } } } TagValueAPI(user).set(values) PermissionAPI(user).set([ (u'fluiddb/api-version', Operation.READ_TAG_VALUE, Policy.OPEN, []), (u'fluiddb/release-date', Operation.READ_TAG_VALUE, Policy.OPEN, []) ]) try: transaction.commit() except: transaction.abort() raise
def testCreateChildNamespaceInheritsParentNamespacePermissions(self): """ L{NamespaceAPI.create} creates new L{Namespace}s with L{Operation.CREATE_NAMESPACE} permissions inherited from the parent L{Namespace}'s permissions. """ UserAPI().create([(u'user', u'secret', u'name', u'*****@*****.**')]) user = getUser(u'user') PermissionAPI(self.user).set([ (u'user', Operation.CREATE_NAMESPACE, Policy.OPEN, []), (u'user', Operation.UPDATE_NAMESPACE, Policy.OPEN, []), (u'user', Operation.DELETE_NAMESPACE, Policy.OPEN, []), (u'user', Operation.LIST_NAMESPACE, Policy.CLOSED, [u'user']), (u'user', Operation.CONTROL_NAMESPACE, Policy.OPEN, []) ]) self.namespaces.create([(u'user/child', u'A child namespace')]) result = getNamespacePermissions([u'user/child']) namespace, permission = result.one() self.assertEqual((Policy.OPEN, []), permission.get(Operation.CREATE_NAMESPACE)) self.assertEqual((Policy.OPEN, []), permission.get(Operation.UPDATE_NAMESPACE)) self.assertEqual((Policy.OPEN, []), permission.get(Operation.DELETE_NAMESPACE)) self.assertEqual((Policy.CLOSED, [user.id]), permission.get(Operation.LIST_NAMESPACE)) self.assertEqual((Policy.OPEN, []), permission.get(Operation.CONTROL_NAMESPACE))
def setUp(self): super(TagValueAPITest, 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.tagValues = TagValueAPI(self.user)
def testSetWithSuperuserInExceptions(self): """ L{PermissionAPI.set} raises L{UserNotAllowedInExceptionError} if a superuser is given in one of the exceptions lists. """ superuser = self.system.users['fluiddb'] values = [(u'username', Operation.CREATE_NAMESPACE, Policy.OPEN, [u'fluiddb'])] self.assertRaises(UserNotAllowedInExceptionError, PermissionAPI(superuser).set, values)
def testSetWithAnonymousUserAndForbiddenOperation(self): """ L{PermissionAPI.set} raises L{UserNotAllowedInExceptionError} if an anonymous user is given in one of the exceptions list and the operation is forbidden for anonymous users. """ anon = self.system.users[u'anon'] values = [(u'username', Operation.CREATE_NAMESPACE, Policy.OPEN, [u'anon'])] self.assertRaises(UserNotAllowedInExceptionError, PermissionAPI(anon).set, values)
def testSetWithAnonymousUserAndPermittedOperation(self): """ L{PermissionAPI.set} updates existing permissions for the anonymous user if the operation is allowed for anonymous users. """ anon = self.system.users[u'anon'] values = [(u'username', Operation.LIST_NAMESPACE, Policy.OPEN, [u'anon'])] PermissionAPI(anon).set(values) namespace, permission = getNamespacePermissions([u'username']).one() self.assertEqual(Policy.OPEN, permission.listPolicy) self.assertEqual([anon.id], permission.listExceptions)
def testActivationTokenTagPermission(self): """ L{bootstrapWebAdminData} creates a C{fluiddb/users/activation-token} tag with write permissions for the C{fluidinfo.com} user. """ createSystemData() bootstrapWebAdminData() superuser = getUser(u'fluiddb') pathAndOperation = (u'fluiddb/users/activation-token', Operation.WRITE_TAG_VALUE) result = PermissionAPI(superuser).get([pathAndOperation]) policy, exceptions = result[pathAndOperation] self.assertEqual(Policy.CLOSED, policy) self.assertEqual([u'fluidinfo.com'], exceptions)
def bootstrapWebAdminData(): """Create system data in a database.""" try: superuser = getUser(u'fluiddb') UserAPI().create([((u'fluidinfo.com', u'secret', u'Fluidinfo website', u'*****@*****.**'))]) webuser = getUser(u'fluidinfo.com') webuser.role = Role.USER_MANAGER TagAPI(superuser).create([(u'fluiddb/users/activation-token', u'Activation token for the user')]) PermissionAPI(superuser).set([ (u'fluiddb/users/activation-token', Operation.WRITE_TAG_VALUE, Policy.CLOSED, [u'fluidinfo.com']) ]) anonuser = getUser(u'anon') OAuthConsumerAPI.register(anonuser) except: transaction.abort() raise else: transaction.commit()
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)
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)
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))
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)
def __init__(self, user): self._api = PermissionAPI(user, factory=CachingAPIFactory())
def permissions(self, user): """Get a new L{PermissionAPI} instance.""" from fluiddb.model.permission import PermissionAPI return PermissionAPI(user)