new role loops.Person for Person object and its children, with zope.View default permission; + security propagation fixes

This commit is contained in:
Helmut Merz 2013-01-09 15:19:35 +01:00
parent 6fad66ea34
commit 2cee73672b
9 changed files with 67 additions and 36 deletions

View file

@ -42,7 +42,7 @@ TypeInterfaceSourceList.typeInterfaces += (ISimpleBlogPost, IBlogPost,)
class SimpleBlogPost(Compound):
implements(IBlogPost)
implements(ISimpleBlogPost)
textContentType = 'text/html'

View file

@ -2,8 +2,6 @@
loops - Linked Objects for Organization and Processing Services
===============================================================
($Id$)
Note: This packages depends on cybertools.organize.
Let's do some basic setup
@ -267,9 +265,9 @@ Person objects that have a user assigned to them receive this user
>>> from zope.app.securitypolicy.interfaces import IPrincipalRoleMap
>>> IPrincipalRoleMap(concepts['john']).getPrincipalsAndRoles()
[('loops.Owner', 'users.john', PermissionSetting: Allow)]
[('loops.Person', 'users.john', PermissionSetting: Allow)]
>>> IPrincipalRoleMap(concepts['person.newuser']).getPrincipalsAndRoles()
[('loops.Owner', u'loops.newuser', PermissionSetting: Allow)]
[('loops.Person', u'loops.newuser', PermissionSetting: Allow)]
The person ``martha`` hasn't got a user id, so there is no role assigned
to it.
@ -307,9 +305,12 @@ Now we are ready to look for the real stuff - what John is allowed to do.
True
Person objects that have an owner may be modified by this owner.
(Changed in 2013-01-14: Owner not set automatically)
>>> canWrite(john, 'title')
True
False
was: True
So let's try with another user with another role setting.

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
"""
Adapters for IConcept providing interfaces from the cybertools.organize package.
$Id$
"""
from persistent.mapping import PersistentMapping
@ -43,9 +41,11 @@ from loops.interfaces import IConcept
from loops.organize.interfaces import IAddress, IPerson, IHasRole
from loops.organize.interfaces import ANNOTATION_KEY
from loops.predicate import RelationAdapter
from loops.security.common import assignOwner, removeOwner, allowEditingForOwner
from loops.type import TypeInterfaceSourceList
from loops.predicate import PredicateInterfaceSourceList
from loops.security.common import assignOwner, removeOwner, allowEditingForOwner
from loops.security.common import assignPersonRole, removePersonRole
from loops.security.interfaces import ISecuritySetter
from loops.type import TypeInterfaceSourceList
from loops import util
@ -84,6 +84,7 @@ class Person(AdapterBase, BasePerson):
def getUserId(self):
return getattr(self.context, '_userId', None)
def setUserId(self, userId):
setter = ISecuritySetter(self)
if userId:
principal = self.getPrincipalForUserId(userId)
if principal is None:
@ -99,13 +100,16 @@ class Person(AdapterBase, BasePerson):
if ann is None: # or not isinstance(ann, PersistentMapping):
ann = pa[ANNOTATION_KEY] = PersistentMapping()
ann[loopsId] = self.context
assignOwner(self.context, userId)
#assignOwner(self.context, userId)
assignPersonRole(self.context, userId)
oldUserId = self.userId
if oldUserId and oldUserId != userId:
self.removeReferenceFromPrincipal(oldUserId)
removeOwner(self.context, oldUserId)
removePersonRole(self.context, oldUserId)
self.context._userId = userId
allowEditingForOwner(self.context, revert=not userId)
setter.propagateSecurity()
allowEditingForOwner(self.context, revert=not userId) # why this?
userId = property(getUserId, setUserId)
def removeReferenceFromPrincipal(self, userId):

View file

@ -2,8 +2,6 @@
loops - Linked Objects for Organization and Processing Services
===============================================================
($Id$)
>>> from zope import component
>>> from zope.traversing.api import getName
@ -183,6 +181,12 @@ Querying objects by state
[<...>]
Task States
===========
>>> from loops.organize.stateful.task import taskStates, publishableTask
Fin de partie
=============

View file

@ -69,37 +69,51 @@ def publishableTask():
color='yellow',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Deny,
('zope.View', 'loops.Member'): Deny,})),
('zope.View', 'loops.Member'): Deny,
('zope.View', 'loops.Person'): Deny,
('zope.View', 'loops.Staff'): Deny,})),
State('active', 'active', ('retract', 'finish', 'publish', 'cancel',),
color='lightblue',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Deny,
('zope.View', 'loops.Member'): Allow,})),
('zope.View', 'loops.Member'): Deny,
('zope.View', 'loops.Person'): Allow,
('zope.View', 'loops.Staff'): Deny,})),
State('active_published', 'active (published)',
('retract', 'finish_published', 'retract', 'cancel',), color='blue',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Allow,
('zope.View', 'loops.Member'): Allow,})),
('zope.View', 'loops.Member'): Allow,
('zope.View', 'loops.Person'): Allow,
('zope.View', 'loops.Staff'): Allow,})),
State('finished', 'finished', ('reopen', 'archive',),
color='lightgreen',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Deny,
('zope.View', 'loops.Member'): Allow,})),
('zope.View', 'loops.Member'): Deny,
('zope.View', 'loops.Person'): Allow,
('zope.View', 'loops.Staff'): Deny,})),
State('finished_published', 'finished (published)', ('reopen', 'archive',),
color='green',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Allow,
('zope.View', 'loops.Member'): Allow,})),
('zope.View', 'loops.Member'): Allow,
('zope.View', 'loops.Person'): Allow,
('zope.View', 'loops.Staff'): Allow,})),
State('cancelled', 'cancelled', ('reopen',),
color='x',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Deny,
('zope.View', 'loops.Member'): Deny,})),
('zope.View', 'loops.Member'): Deny,
('zope.View', 'loops.Person'): Deny,
('zope.View', 'loops.Staff'): Deny,})),
State('archived', 'archived', ('reopen',),
color='grey',
setSecurity=setPermissionsForRoles({
('zope.View', 'zope.Member'): Deny,
('zope.View', 'loops.Member'): Deny,})),
('zope.View', 'loops.Member'): Deny,
('zope.View', 'loops.Person'): Deny,
('zope.View', 'loops.Staff'): Deny,})),
Transition('release', 'release', 'active'),
Transition('release_publish', 'release, publish', 'active_published'),
Transition('publish', 'publish', 'active_published'),

View file

@ -79,6 +79,11 @@
<grant role="loops.Owner" permission="loops.ViewRestricted" />
<grant role="loops.Owner" permission="zope.View" />
<role id="loops.Person"
title="[loops-person-role] Person" />
<grant role="loops.Person" permission="zope.View" />
<grant role="loops.Person" permission="loops.ViewRestricted" />
<!-- moved to etc/securitypolicy.zcml: -->
<!--<grant role="zope.ContentManager" permission="loops.AssignAsParent" />-->

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2010 Helmut Merz helmutm@cy55.de
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
"""
Security-related views.
$Id$
"""
from zope.app.authentication.groupfolder import GroupInformation
@ -145,7 +143,7 @@ class PermissionView(object):
for e in entry:
value = SettingAsBoolean[e[1]]
value = (value is False and '-') or (value and '+') or ''
result.append(value + e[0])
result.append(value + (e[0] or ''))
return ', '.join(result)
def getPrincipalPermissions(self):

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,8 +18,6 @@
"""
Common functions and other stuff for working with permissions and roles.
$Id$
"""
from persistent import Persistent
@ -49,12 +47,12 @@ allRolesExceptOwner = (
'zope.Anonymous', 'zope.Member', 'zope.ContentManager', 'loops.Staff',
'loops.xmlrpc.ConceptManager', # relevant for local security?
#'loops.SiteManager',
'loops.Member', 'loops.Master',)
'loops.Person', 'loops.Member', 'loops.Master')
allRolesExceptOwnerAndMaster = tuple(allRolesExceptOwner[:-1])
minorPrivilegedRoles = ('zope.Anonymous', 'zope.Member',)
localRoles = ('zope.Anonymous', 'zope.Member', 'zope.ContentManager',
'loops.SiteManager', 'loops.Staff', 'loops.Member', 'loops.Master',
'loops.Owner')
'loops.Owner', 'loops.Person')
localPermissions = ('zope.ManageContent', 'zope.View', 'loops.ManageWorkspaces',
'loops.ViewRestricted', 'loops.EditRestricted', 'loops.AssignAsParent',)
@ -127,7 +125,15 @@ def assignOwner(obj, principalId):
def removeOwner(obj, principalId):
prm = IPrincipalRoleManager(obj)
prm.removeRoleFromPrincipal('loops.Owner', principalId)
prm.unsetRoleForPrincipal('loops.Owner', principalId)
def assignPersonRole(obj, principalId):
prm = IPrincipalRoleManager(obj)
prm.assignRoleToPrincipal('loops.Person', principalId)
def removePersonRole(obj, principalId):
prm = IPrincipalRoleManager(obj)
prm.unsetRoleForPrincipal('loops.Person', principalId)
def allowEditingForOwner(obj, deny=allRolesExceptOwner, revert=False):

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -19,8 +19,6 @@
"""
Base classes for security setters, i.e. adapters that provide standardized
methods for setting role permissions and other security-related stuff.
$Id$
"""
from zope.app.security.settings import Allow, Deny, Unset
@ -136,7 +134,7 @@ class LoopsObjectSecuritySetter(BaseSecuritySetter):
def copyPrincipalRoles(self, source, revert=False):
prm = IPrincipalRoleMap(baseObject(source.context))
for r, p, s in prm.getPrincipalsAndRoles():
if p in self.workspacePrincipals:
#if p in self.workspacePrincipals:
if revert:
setPrincipalRole(self.principalRoleManager, r, p, Unset)
else:
@ -155,6 +153,7 @@ class ConceptSecuritySetter(LoopsObjectSecuritySetter):
setter = ISecuritySetter(adapted(relation.second))
setter.setDefaultRolePermissions()
setter.acquireRolePermissions()
# TODO: use setter.acquirePrincipalRoles() instead of copyPrincipalRoles()
wi = baseObject(self.context).workspaceInformation
if wi and not wi.propagateParentSecurity:
return