propagation of security settings (principal roles and role permissions) basically working

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3649 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-12-13 15:41:30 +00:00
parent bea4f70ba3
commit 504092b268
11 changed files with 150 additions and 119 deletions

View file

@ -60,7 +60,7 @@ from cybertools.typology.interfaces import IType, ITypeManager
from loops.common import adapted
from loops.config.base import DummyOptions
from loops.i18n.browser import I18NView
from loops.interfaces import IResource, IView, INode
from loops.interfaces import IResource, IView, INode, ITypeConcept
from loops.organize.tracking import access
from loops.resource import Resource
from loops.security.common import canAccessObject, canListObject, canWriteObject
@ -413,6 +413,8 @@ class BaseView(GenericView, I18NView):
@Lazy
def options(self):
if ITypeConcept.providedBy(self.adapted):
return DummyOptions()
return component.queryAdapter(self.adapted, IOptions) or DummyOptions()
@Lazy

View file

@ -12,6 +12,8 @@
<zope:class class="loops.compound.blog.post.BlogPost">
<require permission="zope.View"
interface="loops.compound.blog.interfaces.IBlogPost" />
<require permission="zope.View"
attributes="context" />
<require permission="zope.ManageContent"
set_schema="loops.compound.blog.interfaces.IBlogPost" />
</zope:class>

View file

@ -43,24 +43,27 @@ class BlogPostSecuritySetter(BaseSecuritySetter):
def setDefaultPrincipalRoles(self):
assignOwner(self.context.context, self.principalId)
def setAcquiredRolePermissions(self, relation, revert=False):
if isAcquiring(relation.predicate):
def setAcquiredSecurity(self, relation, revert=False):
#if self.isAcquiring(relation.predicate):
if relation.predicate in self.acquiringPredicates:
allowEditingForOwner(relation.second, revert=revert)
if self.context.private:
restrictView(relation.second, revert=revert)
def setAcquiredPrincipalRoles(self, relation, revert=False):
if isAcquiring(relation.predicate):
if revert:
removeOwner(relation.second, self.principalId)
else:
assignOwner(relation.second, self.principalId)
@Lazy
def acquiringPredicates(self):
names = ('ispartof',)
return [self.conceptManager.get(n) for n in names]
@Lazy
def principalId(self):
return getCurrentPrincipal().id
def isAcquiring(predicate):
# TODO: use a predicate property for this.
# TODO: use a predicate option for this.
return getName(predicate) in ('ispartof',)

View file

@ -271,11 +271,6 @@ class IBaseResource(ILoopsObject):
source="loops.resourceTypeSource",
required=False)
def getType():
""" Return a concept that provides the object's type, i.e. the
resourceType attribute.
"""
data = schema.Bytes(
title=_(u'Data'),
description=_(u'Resource raw data'),
@ -290,6 +285,38 @@ class IBaseResource(ILoopsObject):
missing_value='',
required=False)
def getType():
""" Return a concept that provides the object's type, i.e. the
resourceType attribute.
"""
def getClients(relationships=None):
""" Return a sequence of objects that the resource is the target of.
"""
def getConcepts(predicates=None):
""" Return a tuple of concepts related to self as parent concepts,
optionally restricted to the predicates given.
"""
def getConceptRelations(predicates=None, concepts=None):
""" Return a sequence of relations to concepts assigned to self
as parent concepts, optionally restricted to the predicates given
or to a certain concept.
"""
def assignConcept(concept, predicate):
""" Assign an existing concept to self using the predicate given.
The assigned concept will be a parent concept of self.
The predicate defaults to the concept manager's default predicate.
"""
def deassignConcept(concept, predicates=None):
""" Remove the concept relations to the concept given from self,
optionally restricting them to the predicates given.
"""
class IBaseResourceSchema(Interface):
""" New schema for resources; to be used by sub-interfaces that will
@ -334,33 +361,6 @@ class IResource(ILoopsObject, IPotentialTarget):
available via a view or a concept.
"""
def getClients(relationships=None):
""" Return a sequence of objects that the resource is the target of.
"""
def getConcepts(predicates=None):
""" Return a tuple of concepts related to self as parent concepts,
optionally restricted to the predicates given.
"""
def getConceptRelations(predicates=None, concepts=None):
""" Return a sequence of relations to concepts assigned to self
as parent concepts, optionally restricted to the predicates given
or to a certain concept.
"""
def assignConcept(concept, predicate):
""" Assign an existing concept to self using the predicate given.
The assigned concept will be a parent concept of self.
The predicate defaults to the concept manager's default predicate.
"""
def deassignConcept(concept, predicates=None):
""" Remove the concept relations to the concept given from self,
optionally restricting them to the predicates given.
"""
class IDocumentSchema(IResourceSchema):

View file

@ -25,13 +25,13 @@
for="loops.interfaces.INode"
name="register_user.html"
class="loops.organize.browser.member.MemberRegistration"
permission="zope.Public" />
permission="zope.View" />
<browser:page
for="loops.interfaces.INode"
name="change_password.html"
class="loops.organize.browser.member.PasswordChange"
permission="zope.Public" />
permission="zope.View" />
<zope:adapter
name="task.html"

View file

@ -59,6 +59,11 @@ def getGroupsFolder(context=None, name='gloops'):
return getPrincipalFolder(authPluginId=name, ignoreErrors=True)
def getGroupId(group):
gf = group.__parent__
return ''.join((gf.__parent__.prefix, gf._groupid(group)))
def getInternalPrincipal(id, context=None, pau=None):
if pau is None:
pau = component.getUtility(IAuthentication, context=context)

View file

@ -50,9 +50,8 @@ class Granting(granting.Granting):
def status(self):
value = super(Granting, self).status()
if value:
setter = ISecuritySetter(adapted(self.context), None)
if setter is not None:
setter.propagatePrincipalRoles()
setter = ISecuritySetter(adapted(self.context))
setter.propagateSecurity()
return value
@ -99,9 +98,8 @@ class PermissionView(object):
def update(self, testing=None):
value = self.delegate.update(testing)
if value:
setter = ISecuritySetter(self.adapted, None)
if setter is not None:
setter.propagateRolePermissions()
setter = ISecuritySetter(self.adapted)
setter.propagateSecurity()
return value
@Lazy

View file

@ -97,6 +97,14 @@ def setRolePermission(rpm, p, r, setting):
else:
rpm.unsetPermissionFromRole(p, r)
def setPrincipalRole(prm, r, p, setting):
if setting == Allow:
prm.assignRoleToPrincipal(r, p)
elif setting == Deny:
prm.removeRoleFromPrincipal(r, p)
else:
prm.unsetRoleForPrincipal(r, p)
def assignOwner(obj, principalId):
prm = IPrincipalRoleManager(obj)
@ -137,24 +145,21 @@ def restrictView(obj, roles=allRolesExceptOwnerAndMaster, revert=False):
def setDefaultSecurity(obj, event):
aObj = adapted(obj)
setter = ISecuritySetter(aObj)
setter.setDefaultRolePermissions()
setter.setDefaultPrincipalRoles()
setter.setDefaultSecurity()
@component.adapter(IConcept, IAssignmentEvent)
def grantAcquiredSecurity(obj, event):
aObj = adapted(obj)
setter = ISecuritySetter(aObj)
setter.setAcquiredRolePermissions(event.relation)
setter.setAcquiredPrincipalRoles(event.relation)
setter.setAcquiredSecurity(event.relation)
@component.adapter(IConcept, IDeassignmentEvent)
def revokeAcquiredSecurity(obj, event):
aObj = adapted(obj)
setter = ISecuritySetter(aObj)
setter.setAcquiredRolePermissions(event.relation, revert=True)
setter.setAcquiredPrincipalRoles(event.relation, revert=True)
setter.setAcquiredSecurity(event.relation, revert=True)
# helper stuff
@ -168,12 +173,12 @@ class WorkspaceInformation(Persistent):
__name__ = u'workspace_information'
propagatePrincipalRoles = False
propagateRolePermissions = 'workspace'
def __init__(self, parent):
self.__parent__ = parent
self.workspaceGroups = PersistentList()
self.workspaceGroupNames = PersistentList()
def getName(self):
return self.__name__

View file

@ -30,6 +30,11 @@ from loops.util import _
class ISecuritySetter(Interface):
def setDefaultSecurity():
""" Set some default role permission assignments (grants) on the
context object.
"""
def setDefaultRolePermissions():
""" Set some default role permission assignments (grants) on the
context object.
@ -40,46 +45,31 @@ class ISecuritySetter(Interface):
(e.g. the user that created the object).
"""
def acquireRolePermissions():
def acquireRolePermissions(revert=False):
""" Check (immediate) parents's settings and set role permission
assignments on the context object accordingly.
"""
def setAcquiredRolePermissions(relation, revert=False, updated=None):
def setAcquiredSecurity(relation, revert=False, updated=None):
""" Grant role permissions on children/resources for the relation given.
If the ``revert`` argument is true unset the corresponding settings.
Do not update objects in the ``updated`` collection if present.
"""
def setAcquiredPrincipalRoles(relation, revert=False, updated=None):
""" Assign roles on children/resources for the relation given.
If the ``revert`` argument is true unset the corresponding settings.
Do not update objects in the ``updated`` collection if present.
"""
def propagateRolePermissions(updated=None):
def propagateSecurity(revert=False, updated=None):
""" Update role permissions on all sub-objects according to the
current setting of the context object.
Ignore objects in the ``updated`` collection if present.
"""
def propagatePrincipalRoles(updated=None):
""" Update roles on all sub-objects according to the
current setting of the context object.
Ignore objects in the ``updated`` collection if present.
"""
class IWorkspaceInformation(Interface):
""" Additional information belonging to a concept that controls
security-related stuff for sub-objects.
"""
propagatePrincipalRoles = Attribute('Should acquired principal roles be '
'propagated to children?')
propagateRolePermissions = Attribute('Which role permissions should be '
'propagated to children?')

View file

@ -24,16 +24,18 @@ $Id$
"""
from zope.app.security.settings import Allow, Deny, Unset
from zope.app.securitypolicy.interfaces import IRolePermissionMap
from zope.app.securitypolicy.interfaces import IRolePermissionManager
from zope.app.securitypolicy.interfaces import \
IRolePermissionMap, IRolePermissionManager, \
IPrincipalRoleMap, IPrincipalRoleManager
from zope import component
from zope.component import adapts
from zope.cachedescriptors.property import Lazy
from zope.interface import implements, Interface
from zope.security.proxy import isinstance
from loops.common import adapted, AdapterBase
from loops.security.common import overrides, setRolePermission
from loops.common import adapted, AdapterBase, baseObject
from loops.organize.util import getPrincipalFolder, getGroupsFolder, getGroupId
from loops.security.common import overrides, setRolePermission, setPrincipalRole
from loops.interfaces import IConceptSchema, IBaseResourceSchema, ILoopsAdapter
from loops.security.interfaces import ISecuritySetter
@ -46,25 +48,39 @@ class BaseSecuritySetter(object):
def __init__(self, context):
self.context = context
@Lazy
def baseObject(self):
return baseObject(self.context)
@Lazy
def conceptManager(self):
return self.baseObject.getLoopsRoot().getConceptManager()
@Lazy
def acquiringPredicates(self):
names = ('hasType', 'standard',)
return [self.conceptManager.get(n) for n in names]
def setDefaultRolePermissions(self):
pass
def setDefaultPrincipalRoles(self):
pass
def setDefaultSecurity(self):
self.setDefaultRolePermissions()
self.setDefaultPrincipalRoles()
def setAcquiredSecurity(self, relation, revert=False, updated=None):
pass
def propagateSecurity(self, revert=False, updated=None):
pass
def acquireRolePermissions(self):
pass
def setAcquiredRolePermissions(self, relation, revert=False, updated=None):
pass
def setAcquiredPrincipalRoles(self, relation, revert=False, updated=None):
pass
def propagateRolePermissions(self, updated=None):
pass
def propagatePrincipalRoles(self, updated=None):
def copyPrincipalRoles(self, source, revert=False):
pass
@ -72,17 +88,21 @@ class LoopsObjectSecuritySetter(BaseSecuritySetter):
parents = []
@Lazy
def baseObject(self):
obj = self.context
if isinstance(obj, AdapterBase):
obj = obj.context
return obj
@Lazy
def rolePermissionManager(self):
return IRolePermissionManager(self.baseObject)
@Lazy
def principalRoleManager(self):
return IPrincipalRoleManager(self.baseObject)
@Lazy
def workspacePrincipals(self):
gFolder = getGroupsFolder(self.baseObject, 'gloops_ws')
if gFolder is None:
return []
return [getGroupId(g) for g in gFolder.values()]
def setDefaultRolePermissions(self):
rpm = self.rolePermissionManager
for p, r, s in rpm.getRolesAndPermissions():
@ -109,38 +129,44 @@ class LoopsObjectSecuritySetter(BaseSecuritySetter):
for (p, r), s in settings.items():
setRolePermission(self.rolePermissionManager, p, r, s)
def copyPrincipalRoles(self, source, revert=False):
prm = IPrincipalRoleMap(baseObject(source.context))
for r, p, s in prm.getPrincipalsAndRoles():
if p in self.workspacePrincipals:
if revert:
setPrincipalRole(self.principalRoleManager, r, p, Unset)
else:
setPrincipalRole(self.principalRoleManager, r, p, s)
class ConceptSecuritySetter(LoopsObjectSecuritySetter):
adapts(IConceptSchema)
def setAcquiredRolePermissions(self, relation, revert=False, updated=None):
def setAcquiredSecurity(self, relation, revert=False, updated=None):
if updated and relation.second in updated:
return
setter = ISecuritySetter(adapted(relation.second), None)
if setter is not None:
if relation.predicate not in self.acquiringPredicates:
return
setter = ISecuritySetter(adapted(relation.second))
setter.setDefaultRolePermissions()
setter.acquireRolePermissions()
setter.propagateRolePermissions(updated)
setter.copyPrincipalRoles(self, revert)
setter.propagateSecurity(revert, updated)
def setAcquiredPrincipalRoles(self, relation, revert=False, updated=None):
pass
def propagateRolePermissions(self, updated=None):
def propagateSecurity(self, revert=False, updated=None):
if updated is None:
updated = set()
obj = self.baseObject
updated.add(obj)
for r in obj.getChildRelations():
self.setAcquiredRolePermissions(r, updated=updated)
for r in obj.getResourceRelations():
self.setAcquiredRolePermissions(r, updated=updated)
def propagatePrincipalRoles(self, updated=None):
pass
for r in obj.getChildRelations(self.acquiringPredicates):
self.setAcquiredSecurity(r, revert, updated)
for r in obj.getResourceRelations(self.acquiringPredicates):
self.setAcquiredSecurity(r, revert, updated)
@Lazy
def parents(self):
return self.baseObject.getParents()
return self.baseObject.getParents(self.acquiringPredicates)
class ResourceSecuritySetter(LoopsObjectSecuritySetter):
@ -149,5 +175,5 @@ class ResourceSecuritySetter(LoopsObjectSecuritySetter):
@Lazy
def parents(self):
return self.baseObject.getConcepts()
return self.baseObject.getConcepts(self.acquiringPredicates)

View file

@ -52,13 +52,13 @@ domain concept (if present, otherwise the top-level type concept):
['children', 'description', 'id', 'name', 'parents', 'resources',
'title', 'type', 'viewName']
>>> startObj['id'], startObj['name'], startObj['title'], startObj['type']
('3', u'domain', u'Domain', '0')
('4', u'domain', u'Domain', '0')
There are a few standard objects we can retrieve directly:
>>> defaultPred = xrf.getDefaultPredicate()
>>> defaultPred['id'], defaultPred['name']
('14', u'standard')
('3', u'standard')
>>> typePred = xrf.getTypePredicate()
>>> typePred['id'], typePred['name']
('1', u'hasType')
@ -78,12 +78,12 @@ applied in an explicit assignment.
We can also retrieve a certain object by its id or its name:
>>> obj2 = xrf.getObjectById('5')
>>> obj2 = xrf.getObjectById('4')
>>> obj2['id'], obj2['name']
('5', u'note')
('4', u'domain')
>>> textdoc = xrf.getObjectByName(u'textdocument')
>>> textdoc['id'], textdoc['name']
('9', u'textdocument')
('10', u'textdocument')
All methods that retrieve one object also returns its children and parents:
@ -115,7 +115,7 @@ We can also retrieve children and parents explicitely:
[u'customer', u'domain', u'file', u'note', u'person', u'predicate',
u'task', u'textdocument', u'topic', u'type']
>>> pa = xrf.getParents('7')
>>> pa = xrf.getParents('6')
>>> len(pa)
1
>>> pa[0]['name']