implement workspace-based security management

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3891 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2010-06-12 10:51:17 +00:00
parent 6fbf8a08ae
commit 3d7c87b7b9
18 changed files with 313 additions and 90 deletions

View file

@ -120,13 +120,17 @@ class BaseView(GenericView, I18NView):
self.context = removeSecurityProxy(context) self.context = removeSecurityProxy(context)
try: try:
if not self.checkPermissions(): if not self.checkPermissions():
raise Unauthorized('%r: title' % (self.context)) raise Unauthorized(str(self.contextInfo))
except ForbiddenAttribute: # ignore when testing except ForbiddenAttribute: # ignore when testing
pass pass
def checkPermissions(self): def checkPermissions(self):
return canAccessObject(self.context) return canAccessObject(self.context)
@Lazy
def contextInfo(self):
return dict(view=self, context=getName(self.context))
@Lazy @Lazy
def conceptMacros(self): def conceptMacros(self):
return concept_macros.macros return concept_macros.macros

View file

@ -554,7 +554,7 @@
name="create_object.html" name="create_object.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.CreateObjectForm" class="loops.browser.form.CreateObjectForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
@ -568,49 +568,49 @@
name="edit_object.html" name="edit_object.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.EditObjectForm" class="loops.browser.form.EditObjectForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
name="create_concept.html" name="create_concept.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.CreateConceptForm" class="loops.browser.form.CreateConceptForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
name="edit_concept.html" name="edit_concept.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.EditConceptForm" class="loops.browser.form.EditConceptForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
name="edit_concept_page.html" name="edit_concept_page.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.EditConceptPage" class="loops.browser.form.EditConceptPage"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
name="inner_form.html" name="inner_form.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.InnerForm" class="loops.browser.form.InnerForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
name="inner_concept_form.html" name="inner_concept_form.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.InnerConceptForm" class="loops.browser.form.InnerConceptForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<page <page
name="inner_concept_edit_form.html" name="inner_concept_edit_form.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.browser.form.InnerConceptEditForm" class="loops.browser.form.InnerConceptEditForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<zope:adapter <zope:adapter
@ -618,7 +618,7 @@
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.CreateObject" factory="loops.browser.form.CreateObject"
permission="zope.ManageContent" permission="zope.View"
/> />
<zope:adapter <zope:adapter
@ -626,7 +626,7 @@
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.EditObject" factory="loops.browser.form.EditObject"
permission="zope.ManageContent" permission="zope.View"
/> />
<zope:adapter <zope:adapter
@ -634,14 +634,14 @@
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.CreateConcept" factory="loops.browser.form.CreateConcept"
permission="zope.ManageContent" /> permission="zope.View" />
<zope:adapter <zope:adapter
name="edit_concept" name="edit_concept"
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.EditConcept" factory="loops.browser.form.EditConcept"
permission="zope.ManageContent" /> permission="zope.View" />
<!-- inner HTML views --> <!-- inner HTML views -->

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # Copyright (c) 2010 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -35,7 +35,9 @@ from zope.cachedescriptors.property import Lazy
from zope.contenttype import guess_content_type from zope.contenttype import guess_content_type
from zope.publisher.browser import FileUpload from zope.publisher.browser import FileUpload
from zope.publisher.interfaces import BadRequest from zope.publisher.interfaces import BadRequest
from zope.security.interfaces import ForbiddenAttribute, Unauthorized
from zope.security.proxy import isinstance, removeSecurityProxy from zope.security.proxy import isinstance, removeSecurityProxy
from zope.traversing.api import getName
from cybertools.ajax import innerHtml from cybertools.ajax import innerHtml
from cybertools.browser.form import FormController from cybertools.browser.form import FormController
@ -58,6 +60,7 @@ from loops.i18n.browser import I18NView
from loops.query import ConceptQuery, IQueryConcept from loops.query import ConceptQuery, IQueryConcept
from loops.resource import Resource from loops.resource import Resource
from loops.schema.field import relation_macros from loops.schema.field import relation_macros
from loops.security.common import canAccessObject, canListObject, canWriteObject
from loops.type import ITypeConcept from loops.type import ITypeConcept
from loops import util from loops import util
from loops.util import _ from loops.util import _
@ -77,12 +80,20 @@ class ObjectForm(NodeView):
isPopup = False isPopup = False
showAssignments = True showAssignments = True
def __init__(self, context, request): def checkPermissions(self):
super(ObjectForm, self).__init__(context, request) obj = self.target
# target is the object the view acts upon - this is not necessarily if obj is None:
# the same object as the context (the object the view was created for) obj = self.context
self.target = context return canWriteObject(obj)
#self.registerDojoForm()
@Lazy
def target(self):
return self.virtualTargetObject or self.context
@Lazy
def contextInfo(self):
return dict(view=self, context=getName(self.context),
target=getName(self.target))
def closeAction(self, submit=False): def closeAction(self, submit=False):
if self.isPopup: if self.isPopup:
@ -196,18 +207,13 @@ class ObjectForm(NodeView):
class EditObjectForm(ObjectForm): class EditObjectForm(ObjectForm):
@Lazy
def macro(self):
return self.template.macros['edit']
title = _(u'Edit Resource') title = _(u'Edit Resource')
form_action = 'edit_resource' form_action = 'edit_resource'
dialog_name = 'edit' dialog_name = 'edit'
def __init__(self, context, request): @Lazy
super(EditObjectForm, self).__init__(context, request) def macro(self):
#self.url = self.url # keep virtual target URL (???) return self.template.macros['edit']
self.target = self.virtualTargetObject
@property @property
def assignments(self): def assignments(self):
@ -251,13 +257,13 @@ class EditConceptPage(EditConceptForm):
class CreateObjectForm(ObjectForm): class CreateObjectForm(ObjectForm):
@property
def macro(self): return self.template.macros['create']
defaultTitle = u'Create Resource, Type = ' defaultTitle = u'Create Resource, Type = '
form_action = 'create_resource' form_action = 'create_resource'
dialog_name = 'create' dialog_name = 'create'
@property
def macro(self): return self.template.macros['create']
@Lazy @Lazy
def fixedType(self): def fixedType(self):
return self.request.form.get('fixed_type') return self.request.form.get('fixed_type')
@ -445,6 +451,25 @@ class EditObject(FormController, I18NView):
prefix = 'form.' prefix = 'form.'
conceptPrefix = 'assignments.' conceptPrefix = 'assignments.'
def __init__(self, context, request):
super(EditObject, self).__init__(context, request)
try:
if not self.checkPermissions():
raise Unauthorized(str(self.contextInfo))
except ForbiddenAttribute: # ignore when testing
pass
def checkPermissions(self):
return canWriteObject(self.target)
@Lazy
def contextInfo(self):
return dict(formcontroller=self, view=self.view, target=getName(self.target))
@Lazy
def target(self):
return self.view.virtualTargetObject or self.context
@Lazy @Lazy
def adapted(self): def adapted(self):
return adapted(self.object, self.languageInfoForUpdate) return adapted(self.object, self.languageInfoForUpdate)
@ -476,7 +501,7 @@ class EditObject(FormController, I18NView):
def update(self): def update(self):
# create new version if necessary # create new version if necessary
target = self.view.virtualTargetObject target = self.target
obj = self.checkCreateVersion(target) obj = self.checkCreateVersion(target)
if obj != target: if obj != target:
# make sure new version is used by the view # make sure new version is used by the view

View file

@ -176,12 +176,15 @@ standard checker defined in the test setup.
The automatic assignment of the blog post is done in the form controller The automatic assignment of the blog post is done in the form controller
used for creating the blog post. used for creating the blog post.
>>> home = views['home']
>>> home.target = myBlog
>>> from loops.compound.blog.browser import CreateBlogPostForm, CreateBlogPost >>> from loops.compound.blog.browser import CreateBlogPostForm, CreateBlogPost
>>> input = {'title': u'John\'s first post', 'text': u'Text of John\'s post', >>> input = {'title': u'John\'s first post', 'text': u'Text of John\'s post',
... 'date': '2008-02-02T15:54:11', ... 'date': '2008-02-02T15:54:11',
... 'privateComment': u'John\'s private comment', ... 'privateComment': u'John\'s private comment',
... 'form.type': '.loops/concepts/blogpost'} ... 'form.type': '.loops/concepts/blogpost'}
>>> cbpForm = CreateBlogPostForm(myBlog, TestRequest(form=input)) >>> cbpForm = CreateBlogPostForm(home, TestRequest(form=input))
>>> cbpController = CreateBlogPost(cbpForm, cbpForm.request) >>> cbpController = CreateBlogPost(cbpForm, cbpForm.request)
>>> cbpController.update() >>> cbpController.update()
False False

View file

@ -36,7 +36,7 @@ from loops.browser.form import CreateConceptForm, EditConceptForm
from loops.browser.form import CreateConcept, EditConcept from loops.browser.form import CreateConcept, EditConcept
from loops.common import adapted from loops.common import adapted
from loops.organize.party import getPersonForUser from loops.organize.party import getPersonForUser
from loops.security.common import checkPermission from loops.security.common import checkPermission, canAccessObject
from loops import util from loops import util
from loops.util import _ from loops.util import _
@ -175,20 +175,30 @@ class EditBlogPostForm(EditConceptForm):
title = _(u'Edit Blog Post') title = _(u'Edit Blog Post')
form_action = 'edit_blogpost' form_action = 'edit_blogpost'
def checkPermissions(self):
return canAccessObject(self.target)
class CreateBlogPostForm(CreateConceptForm): class CreateBlogPostForm(CreateConceptForm):
title = _(u'Create Blog Post') title = _(u'Create Blog Post')
form_action = 'create_blogpost' form_action = 'create_blogpost'
def checkPermissions(self):
return canAccessObject(self.target)
class EditBlogPost(EditConcept): class EditBlogPost(EditConcept):
pass def checkPermissions(self):
return canAccessObject(self.target)
class CreateBlogPost(CreateConcept): class CreateBlogPost(CreateConcept):
def checkPermissions(self):
return canAccessObject(self.target)
def collectAutoConcepts(self): def collectAutoConcepts(self):
#super(CreateBlogPost, self).collectConcepts(fieldName, value) #super(CreateBlogPost, self).collectConcepts(fieldName, value)
person = getPersonForUser(self.container, self.request) person = getPersonForUser(self.container, self.request)

View file

@ -46,14 +46,14 @@
name="create_blogpost.html" name="create_blogpost.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.compound.blog.browser.CreateBlogPostForm" class="loops.compound.blog.browser.CreateBlogPostForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<browser:page <browser:page
name="edit_blogpost.html" name="edit_blogpost.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.compound.blog.browser.EditBlogPostForm" class="loops.compound.blog.browser.EditBlogPostForm"
permission="zope.ManageContent" permission="zope.View"
/> />
<zope:adapter <zope:adapter
@ -62,7 +62,7 @@
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.interface.Interface" provides="zope.interface.Interface"
factory="loops.compound.blog.browser.CreateBlogPost" factory="loops.compound.blog.browser.CreateBlogPost"
permission="zope.ManageContent" permission="zope.View"
/> />
<zope:adapter <zope:adapter
@ -70,7 +70,7 @@
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.compound.blog.browser.EditBlogPost" factory="loops.compound.blog.browser.EditBlogPost"
permission="zope.ManageContent" permission="zope.View"
/> />
</configure> </configure>

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: $Id$\n" "Project-Id-Version: $Id$\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n" "POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2010-05-16 12:00 CET\n" "PO-Revision-Date: 2010-06-11 12:00 CET\n"
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n" "Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
"Language-Team: loops developers <helmutm@cy55.de>\n" "Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -159,16 +159,16 @@ msgid "Create a new event"
msgstr "Einen neuen Termin anlegen" msgstr "Einen neuen Termin anlegen"
msgid "Create Task..." msgid "Create Task..."
msgstr "Aufgabe anlegen..." msgstr "Crear tarea..."
msgid "Create a new task" msgid "Create a new task"
msgstr "Eine neue Aufgabe anlegen" msgstr "Crear una nueva tarea"
msgid "Edit Task..." msgid "Edit Task..."
msgstr "Aufgabe bearbeiten..." msgstr "Editar tarea..."
msgid "Modify task" msgid "Modify task"
msgstr "Aufgabe bearbeiten" msgstr "Modificar la tarea"
msgid "Create Work Item..." msgid "Create Work Item..."
msgstr "Aktivität anlegen..." msgstr "Aktivität anlegen..."
@ -243,7 +243,7 @@ msgid "Topic"
msgstr "Thema" msgstr "Thema"
msgid "Task" msgid "Task"
msgstr "Aufgabe" msgstr "Tarea"
msgid "Domain" msgid "Domain"
msgstr "Bereich" msgstr "Bereich"

View file

@ -35,6 +35,7 @@ from loops.browser.node import NodeView
from loops.organize.comment.base import Comment from loops.organize.comment.base import Comment
from loops.organize.party import getPersonForUser from loops.organize.party import getPersonForUser
from loops.organize.tracking.report import TrackDetails from loops.organize.tracking.report import TrackDetails
from loops.security.common import canAccessObject
from loops.setup import addObject from loops.setup import addObject
from loops import util from loops import util
from loops.util import _ from loops.util import _
@ -91,6 +92,9 @@ class CreateCommentForm(ObjectForm):
template = comment_macros template = comment_macros
def checkPermissions(self):
return canAccessObject(self.target)
@Lazy @Lazy
def macro(self): def macro(self):
return self.template.macros['create_comment'] return self.template.macros['create_comment']
@ -98,6 +102,9 @@ class CreateCommentForm(ObjectForm):
class CreateComment(EditObject): class CreateComment(EditObject):
def checkPermissions(self):
return canAccessObject(self.target)
@Lazy @Lazy
def personId(self): def personId(self):
p = getPersonForUser(self.context, self.request) p = getPersonForUser(self.context, self.request)

View file

@ -58,8 +58,15 @@ def getPrincipalFolder(context=None, authPluginId=None, ignoreErrors=False):
return plugin return plugin
def getGroupsFolder(context=None, name='gloops'): def getGroupsFolder(context=None, name='gloops', create=False):
return getPrincipalFolder(authPluginId=name, ignoreErrors=True) gf = getPrincipalFolder(authPluginId=name, ignoreErrors=True)
if gf is None and create:
pau = component.getUtility(IAuthentication, context=context)
gf = pau[name] = PrincipalFolder()
gf.prefix = name + '.'
pau.authenticatorPlugins = tuple(
list(pau.authenticatorPlugins) + ['name'])
return gf
def getGroupId(group): def getGroupId(group):

View file

@ -47,6 +47,7 @@ from loops.organize.stateful.browser import StateAction
from loops.organize.tracking.browser import BaseTrackView from loops.organize.tracking.browser import BaseTrackView
from loops.organize.tracking.report import TrackDetails from loops.organize.tracking.report import TrackDetails
from loops.organize.work.base import WorkItem from loops.organize.work.base import WorkItem
from loops.security.common import canAccessObject, canListObject, canWriteObject
from loops import util from loops import util
from loops.util import _ from loops.util import _
@ -277,10 +278,19 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
template = work_macros template = work_macros
def checkPermissions(self):
return canAccessObject(self.task or self.target)
@Lazy @Lazy
def macro(self): def macro(self):
return self.template.macros['create_workitem'] return self.template.macros['create_workitem']
@Lazy
def task(self):
uid = self.track.taskId
if uid:
return util.getObjectForUid(uid)
@Lazy @Lazy
def track(self): def track(self):
id = self.request.form.get('id') id = self.request.form.get('id')
@ -352,6 +362,17 @@ class CreateWorkItemForm(ObjectForm, BaseTrackView):
class CreateWorkItem(EditObject, BaseTrackView): class CreateWorkItem(EditObject, BaseTrackView):
def checkPermissions(self):
return canAccessObject(self.task or self.target)
@Lazy
def task(self):
if self.track is None:
return None
uid = self.track.taskId
if uid:
return util.getObjectForUid(uid)
@Lazy @Lazy
def track(self): def track(self):
id = self.request.form.get('id') id = self.request.form.get('id')
@ -368,7 +389,8 @@ class CreateWorkItem(EditObject, BaseTrackView):
@Lazy @Lazy
def object(self): def object(self):
return self.view.virtualTargetObject return self.target
#return self.view.virtualTargetObject
def processForm(self): def processForm(self):
form = self.request.form form = self.request.form

View file

@ -50,7 +50,7 @@
name="create_workitem.html" name="create_workitem.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
class="loops.organize.work.browser.CreateWorkItemForm" class="loops.organize.work.browser.CreateWorkItemForm"
permission="zope.ManageContent" /> permission="zope.View" />
<zope:adapter <zope:adapter
name="create_workitem" name="create_workitem"

View file

@ -31,6 +31,10 @@
id="loops.EditRestricted" id="loops.EditRestricted"
title="[loops-edit-restricted-permission] loops: Edit Restricted Information" /> title="[loops-edit-restricted-permission] loops: Edit Restricted Information" />
<permission
id="loops.AssignAsParent"
title="[loops-assign-as-parent-permission] loops: Assign as Parent" />
<permission <permission
id="loops.Execute" id="loops.Execute"
title="[loops-execute-permission] loops: Execute" /> title="[loops-execute-permission] loops: Execute" />
@ -42,13 +46,19 @@
<grant role="loops.SiteManager" permission="loops.ManageSite" /> <grant role="loops.SiteManager" permission="loops.ManageSite" />
<grant role="loops.SiteManager" permission="loops.ManageTypes" /> <grant role="loops.SiteManager" permission="loops.ManageTypes" />
<grant role="loops.SiteManager" permission="loops.ManageWorkspaces" /> <grant role="loops.SiteManager" permission="loops.ManageWorkspaces" />
<grant role="loops.SiteManager" permission="loops.AssignAsParent" />
<grant role="loops.SiteManager" permission="loops.xmlrpc.ManageConcepts" /> <grant role="loops.SiteManager" permission="loops.xmlrpc.ManageConcepts" />
<grant role="loops.SiteManager" permission="zope.ManageContent" /> <grant role="loops.SiteManager" permission="zope.ManageContent" />
<grant role="loops.SiteManager" permission="zope.View" /> <grant role="loops.SiteManager" permission="zope.View" />
<role id="loops.xmlrpc.ConceptManager"
title="[xmlrpc-manage-concepts-role] loops: Concept Manager (XML-RPC)" />
<grant role="loops.xmlrpc.ConceptManager" permission="loops.xmlrpc.ManageConcepts" />
<role id="loops.Staff" <role id="loops.Staff"
title="[loops-staff-role] loops: Staff" /> title="[loops-staff-role] loops: Staff" />
<grant role="loops.Staff" permission="loops.ManageWorkspaces" /> <grant role="loops.Staff" permission="loops.ManageWorkspaces" />
<grant role="loops.Staff" permission="loops.AssignAsParent" />
<grant role="loops.Staff" permission="loops.EditRestricted" /> <grant role="loops.Staff" permission="loops.EditRestricted" />
<grant role="loops.Staff" permission="zope.ManageContent" /> <grant role="loops.Staff" permission="zope.ManageContent" />
<grant role="loops.Staff" permission="zope.View" /> <grant role="loops.Staff" permission="zope.View" />
@ -56,19 +66,19 @@
<role id="loops.Master" <role id="loops.Master"
title="[loops-master-role] loops: Master" /> title="[loops-master-role] loops: Master" />
<grant role="loops.Master" permission="zope.ManageContent" /> <grant role="loops.Master" permission="zope.ManageContent" />
<grant role="loops.Master" permission="loops.AssignAsParent" />
<role id="loops.Member" <role id="loops.Member"
title="[loops-member-role] loops: Member" /> title="[loops-member-role] loops: Member" />
<grant role="loops.Member" permission="zope.View" /> <grant role="loops.Member" permission="zope.View" />
<role id="loops.xmlrpc.ConceptManager"
title="[xmlrpc-manage-concepts-role] loops: Concept Manager (XML-RPC)" />
<grant role="loops.xmlrpc.ConceptManager" permission="loops.xmlrpc.ManageConcepts" />
<role id="loops.Owner" <role id="loops.Owner"
title="[loops-owner-role] Owner" /> title="[loops-owner-role] Owner" />
<grant role="loops.Owner" permission="zope.ManageContent" /> <grant role="loops.Owner" permission="zope.ManageContent" />
<grant role="loops.Owner" permission="loops.ViewRestricted" /> <grant role="loops.Owner" permission="loops.ViewRestricted" />
<grant role="loops.Owner" permission="zope.View" /> <grant role="loops.Owner" permission="zope.View" />
<!-- moved to etc/securitypolicy.zcml: -->
<!--<grant role="zope.ContentManager" permission="loops.AssignAsParent" />-->
</configure> </configure>

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # Copyright (c) 2010 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -22,8 +22,10 @@ Security-related views.
$Id$ $Id$
""" """
from zope.app.authentication.groupfolder import GroupInformation
from zope.app.pagetemplate import ViewPageTemplateFile from zope.app.pagetemplate import ViewPageTemplateFile
from zope.app.security.interfaces import IPermission from zope.app.security.interfaces import IPermission
from zope.app.security.settings import Allow, Deny, Unset
from zope.app.securitypolicy.browser import granting from zope.app.securitypolicy.browser import granting
from zope.app.securitypolicy.browser.rolepermissionview import RolePermissionView from zope.app.securitypolicy.browser.rolepermissionview import RolePermissionView
from zope.app.securitypolicy.interfaces import IPrincipalRoleManager, \ from zope.app.securitypolicy.interfaces import IPrincipalRoleManager, \
@ -32,13 +34,17 @@ from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager, \
IPrincipalPermissionMap IPrincipalPermissionMap
from zope.app.securitypolicy.zopepolicy import SettingAsBoolean from zope.app.securitypolicy.zopepolicy import SettingAsBoolean
from zope import component from zope import component
from zope.event import notify
from zope.interface import implements from zope.interface import implements
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from zope.traversing.api import getParent, getParents from zope.traversing.api import getName, getParent, getParents
from loops.common import adapted from loops.common import adapted
from loops.organize.util import getGroupsFolder
from loops.security.common import WorkspaceInformation from loops.security.common import WorkspaceInformation
from loops.security.common import localPermissions, localRoles, setPrincipalRole
from loops.security.interfaces import ISecuritySetter from loops.security.interfaces import ISecuritySetter
@ -162,7 +168,11 @@ class PermissionView(object):
return result return result
def getPermissions(self): def getPermissions(self):
return sorted(name for name, perm in component.getUtilitiesFor(IPermission)) return sorted(name for name, perm in component.getUtilitiesFor(IPermission)
if name in localPermissions)
def hideRole(self, role):
return role not in localRoles
class ManageWorkspaceView(PermissionView): class ManageWorkspaceView(PermissionView):
@ -176,12 +186,86 @@ class ManageWorkspaceView(PermissionView):
wi = context.workspaceInformation = WorkspaceInformation(context) wi = context.workspaceInformation = WorkspaceInformation(context)
PermissionView.__init__(self, wi, request) PermissionView.__init__(self, wi, request)
def update(self, testing=None):
if 'SUBMIT_PERMS' in self.request.form:
super(ManageWorkspaceView, self).update(testing)
elif 'save_wsinfo' in self.request.form:
self.saveWSInfo()
def saveWSInfo(self):
gn = {}
form = self.request.form
gfName = self.context.workspaceGroupsFolderName
gf = getGroupsFolder(self.context, gfName, create=True)
parentRM = IPrincipalRoleManager(self.parent)
wsiRM = IPrincipalRoleManager(self.context)
for pn in form.get('predicate_name', []):
groupName = form.get('group_name_' + pn)
gn[pn] = groupName
if groupName and groupName not in gf:
group = GroupInformation(groupName)
notify(ObjectCreatedEvent(group))
gf[groupName] = group
notify(ObjectModifiedEvent(group))
roleParent = bool(form.get('role_parent_' + pn))
roleWSI = bool(form.get('role_wsi_' + pn))
roleName = 'loops.' + pn.lstrip('is').title()
gid = '.'.join((gfName, groupName))
setPrincipalRole(parentRM, roleName, gid,
roleParent and Allow or None)
setPrincipalRole(wsiRM, roleName, gid,
roleWSI and Allow or None)
self.context.workspaceGroupNames = gn
@Lazy @Lazy
def permission_macros(self): def permission_macros(self):
return permission_template.macros return permission_template.macros
@Lazy
def parent(self):
return self.context.getParent()
@Lazy @Lazy
def adapted(self): def adapted(self):
return adapted(getParent(self.context)) return adapted(self.parent)
def getGroupsInfo(self):
root = self.parent.getLoopsRoot()
conceptManager = root.getConceptManager()
def getDefaultGroupName(predicateName):
rootName = '_'.join([getName(obj) for obj in
reversed(getParents(conceptManager)[:-1])])
objName = getName(self.parent)
return '.'.join((rootName, objName, predicateName.strip('is')))
apn = [pn for pn in self.context.allocationPredicateNames
if pn in conceptManager]
gn = self.context.workspaceGroupNames
if not isinstance(gn, dict): # backwards compatibility
gn = {}
result = [dict(predicateName=pn,
predicateTitle=conceptManager[pn].title,
groupName='', groupExists=False,
roleParent=False, roleWSI=False)
for pn in apn]
gfName = self.context.workspaceGroupsFolderName
gf = getGroupsFolder(self.context, gfName)
if gf is None:
return result
parentRMget = IPrincipalRoleManager(self.parent).getPrincipalsForRole
wsiRMget = IPrincipalRoleManager(self.context).getPrincipalsForRole
for item in result:
pn = item['predicateName']
groupName = item['groupName'] = gn.get(pn, getDefaultGroupName(pn))
roleName = 'loops.' + pn.lstrip('is').title()
if gf is not None and groupName in gf:
item['groupExists'] = True
gid = '.'.join((gfName, groupName))
item['roleParent'] = isSet(parentRMget(roleName), gid)
item['roleWSI'] = isSet(wsiRMget(roleName), gid)
return result
def isSet(entry, id):
for name, setting in entry:
if name == id:
return SettingAsBoolean[setting]

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # Copyright (c) 2010 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -23,7 +23,6 @@ $Id$
""" """
from persistent import Persistent from persistent import Persistent
from persistent.list import PersistentList
from zope import component from zope import component
from zope.annotation.interfaces import IAttributeAnnotatable from zope.annotation.interfaces import IAttributeAnnotatable
from zope.app.container.interfaces import IObjectAddedEvent from zope.app.container.interfaces import IObjectAddedEvent
@ -52,6 +51,15 @@ allRolesExceptOwner = (
'loops.Member', 'loops.Master',) 'loops.Member', 'loops.Master',)
allRolesExceptOwnerAndMaster = tuple(allRolesExceptOwner[:-1]) allRolesExceptOwnerAndMaster = tuple(allRolesExceptOwner[:-1])
minorPrivilegedRoles = ('zope.Anonymous', 'zope.Member',) minorPrivilegedRoles = ('zope.Anonymous', 'zope.Member',)
localRoles = ('zope.Anonymous', 'zope.Member', 'zope.ContentManager',
'loops.Staff', 'loops.Member', 'loops.Master', 'loops.Owner')
localPermissions = ('zope.ManageContent', 'zope.View', 'loops.ManageWorkspaces',
'loops.ViewRestricted', 'loops.EditRestricted', 'loops.AssignAsParent',)
allocationPredicateNames = ('ismaster', 'ismember')
workspaceGroupsFolderName = 'gloops_ws'
# checking and querying functions # checking and querying functions
@ -70,6 +78,9 @@ def canWriteObject(obj):
def canEditRestricted(obj): def canEditRestricted(obj):
return checkPermission('loops.EditRestricted', obj) return checkPermission('loops.EditRestricted', obj)
def canAssignAsParent(obj):
return checkPermission('loops.AssignAsParent', obj)
def checkPermission(permission, obj): def checkPermission(permission, obj):
return baseCheckPermission(permission, obj) return baseCheckPermission(permission, obj)
@ -174,11 +185,15 @@ class WorkspaceInformation(Persistent):
__name__ = u'workspace_information' __name__ = u'workspace_information'
propagateRolePermissions = 'workspace' propagateRolePermissions = 'workspace'
allocationPredicateNames = allocationPredicateNames
workspaceGroupsFolderName = workspaceGroupsFolderName
def __init__(self, parent): def __init__(self, parent):
self.__parent__ = parent self.__parent__ = parent
self.workspaceGroupNames = PersistentList() self.workspaceGroupNames = {}
def getName(self): def getName(self):
return self.__name__ return self.__name__
def getParent(self):
return self.__parent__

View file

@ -70,6 +70,6 @@ class IWorkspaceInformation(Interface):
security-related stuff for sub-objects. security-related stuff for sub-objects.
""" """
propagateRolePermissions = Attribute('Which role permissions should be ' propagateRolePermissions = Attribute('Whose role permissions should be '
'propagated to children?') 'propagated to children (workspace_informaton or parent)?')

View file

@ -37,37 +37,32 @@
tal:attributes="value permId" /> tal:attributes="value permId" />
<div class="form-element"> <div class="form-element">
<table width="100%" cellspacing="0" cellpadding="2" border="0" <table class="listing" cellspacing="0" cellpadding="2" border="0"
nowrap="nowrap"> nowrap="nowrap">
<tr class="list-header"> <tr class="list-header">
<td><strong i18n:translate="">Role</strong></td> <th i18n:translate="">Role</th>
<td><strong i18n:translate="">Users/Groups</strong></td> <th i18n:translate="">Users/Groups</th>
<td><strong i18n:translate="">Acquired Setting</strong></td> <th i18n:translate="">Acquired Setting</th>
<td><strong i18n:translate="">Setting</strong></td> <th i18n:translate="">Setting</th>
</tr> </tr>
<tal:role tal:repeat="setting perm/roleSettings">
<tr class="row-normal" <tr class="row-normal"
tal:repeat="setting perm/roleSettings" tal:define="ir repeat/setting/index;
tal:attributes="class python: roleId python:path('view/roles')[ir].id"
path('repeat/setting/even') and 'row-normal' or 'row-hilite'"> tal:attributes="style python:view.hideRole(roleId) and
<tal:role define="ir repeat/setting/index; 'visibility: collapse' or ''">
roleId python:path('view/roles')[ir].id">
<td align="left" valign="top" <td align="left" valign="top"
tal:content="roleId"> tal:content="roleId" />
Manager
</td>
<td> <td>
<span tal:define="users python: view.listUsersForRole(roleId)" <span tal:define="users python: view.listUsersForRole(roleId)"
tal:replace="structure users"> tal:replace="structure users" /></td>
User xy <td class="center">
</span>
</td>
<td>
<span tal:replace="python: <span tal:replace="python:
view.getAcquiredPermissionSetting(roleId, permId)" /> view.getAcquiredPermissionSetting(roleId, permId)" />
</td> </td>
<td> <td class="center">
<select name="settings:list"> <select name="settings:list">
<option value="Unset" <option value="Unset"
tal:repeat="option view/availableSettings" tal:repeat="option view/availableSettings"
@ -77,16 +72,16 @@
i18n:translate="">+</option> i18n:translate="">+</option>
</select> </select>
</td> </td>
</tal:role>
</tr> </tr>
<tr tal:define="principals view/getPrincipalPermissions" </tal:role>
<tr tal:define="principals view/getPrincipalPermissions"
tal:condition="principals"> tal:condition="principals">
<td> <td>
<strong i18n:translate="">Direct Settings</strong> <strong i18n:translate="">Direct Settings</strong>
</td> </td>
<td colspan="3" tal:content="structure principals">+xyz</td> <td colspan="3" tal:content="structure principals">+xyz</td>
</tr> </tr>
</table> </table>
</div> </div>

View file

@ -2,10 +2,51 @@
i18n:domain="zope"> i18n:domain="zope">
<body> <body>
<div metal:fill-slot="body" i18n:domain="zope"> <div metal:fill-slot="body" i18n:domain="zope">
<h2 i18n:translate="">Assign Permissions to Roles for Children of this Object</h2> <h1 i18n:translate="">Define Workspace Properties</h1>
<p tal:define="status view/update" <p tal:define="status view/update"
tal:content="status" i18n:translate=""/> tal:content="status" i18n:translate=""/>
<form method="post">
<table class="listing">
<tr>
<th colspan="3"></th>
<th colspan="2">Assign role in</th>
</tr>
<tr>
<th>Predicate</th>
<th>Group name</th>
<th>Exists</th>
<th>Parent</th>
<th>WS Info</th>
</tr>
<tr tal:repeat="gi view/getGroupsInfo">
<td>
<input type="hidden" name="predicate_name:list"
tal:attributes="value gi/predicateName" />
<span tal:content="gi/predicateTitle" />
</td>
<td>
<input type="text" size="40"
tal:attributes="name string:group_name_${gi/predicateName};
value gi/groupName">
</td>
<td class="center"
tal:content="python:gi['groupExists'] and 'yes' or 'no'" />
<td class="center">
<input type="checkbox" value="true"
tal:attributes="name string:role_parent_${gi/predicateName};
checked gi/roleParent" /></td>
<td class="center">
<input type="checkbox" value="true"
tal:attributes="name string:role_wsi_${gi/predicateName};
checked gi/roleWSI" /></td>
</tr>
</table>
<br />
<input type="submit" name="save_wsinfo" value="Save Settings" />
</form>
<br />
<h2 i18n:translate="">Assign Permissions to Roles for Children of this Object</h2>
<br />
<metal:permissions use-macro="view/permission_macros/permission_form" /> <metal:permissions use-macro="view/permission_macros/permission_form" />
</div> </div>