work in progress: workspace (parent-) -governed 'children' grants (principal-to-role mappings)
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3616 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									8ad7a0c573
								
							
						
					
					
						commit
						bcd76509e7
					
				
					 9 changed files with 180 additions and 17 deletions
				
			
		
							
								
								
									
										13
									
								
								concept.py
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								concept.py
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -39,6 +39,7 @@ from zope.security.proxy import removeSecurityProxy, isinstance
 | 
			
		|||
from zope.traversing.api import getName, getParent
 | 
			
		||||
from persistent import Persistent
 | 
			
		||||
 | 
			
		||||
from cybertools.meta.interfaces import IOptions
 | 
			
		||||
from cybertools.relation import DyadicRelation
 | 
			
		||||
from cybertools.relation.registry import getRelations
 | 
			
		||||
from cybertools.relation.interfaces import IRelationRegistry, IRelatable
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +105,8 @@ class Concept(Contained, Persistent):
 | 
			
		|||
 | 
			
		||||
    proxyInterface = IConceptView
 | 
			
		||||
 | 
			
		||||
    workspaceInformation = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, title=u''):
 | 
			
		||||
        self.title = title
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +165,16 @@ class Concept(Contained, Persistent):
 | 
			
		|||
                pi.relations.append(rel)
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def isWorkspace(self):
 | 
			
		||||
        ct = self.conceptType
 | 
			
		||||
        if ct != self.getConceptManager().getTypeConcept():
 | 
			
		||||
            from loops.config.base import DummyOptions
 | 
			
		||||
            options = component.queryAdapter(adapted(self), IOptions) or DummyOptions()
 | 
			
		||||
            if options('security.isWorkspace'):
 | 
			
		||||
                return True
 | 
			
		||||
        return IOptions(adapted(ct))('security.isWorkspace')
 | 
			
		||||
 | 
			
		||||
    # concept relations
 | 
			
		||||
 | 
			
		||||
    def getClients(self, relationships=None):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,6 +104,13 @@ class IConcept(IConceptSchema, ILoopsObject, IPotentialTarget):
 | 
			
		|||
        source="loops.conceptTypeSource",
 | 
			
		||||
        required=True)
 | 
			
		||||
 | 
			
		||||
    isWorkspace = Attribute('Marks a concept as responsible for providing '
 | 
			
		||||
                    'special permission settings (children grants) '
 | 
			
		||||
                    'for its sub-objects (children or resources).')
 | 
			
		||||
 | 
			
		||||
    workspaceInformation = Attribute('An object with additional '
 | 
			
		||||
                    'workspace-related information, e.g. children grants.')
 | 
			
		||||
 | 
			
		||||
    def getType():
 | 
			
		||||
        """ Return a concept that provides the object's type.
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -677,6 +684,13 @@ class IPredicate(IConceptSchema):
 | 
			
		|||
        source='loops.PredicateInterfaceSource',
 | 
			
		||||
        required=False)
 | 
			
		||||
 | 
			
		||||
    options = schema.List(
 | 
			
		||||
        title=_(u'Options'),
 | 
			
		||||
        description=_(u'Additional settings.'),
 | 
			
		||||
        value_type=schema.TextLine(),
 | 
			
		||||
        default=[],
 | 
			
		||||
        required=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# probably not useful
 | 
			
		||||
class xxIMappingAttributeRelation(IConceptSchema):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,12 @@ class Predicate(AdapterBase):
 | 
			
		|||
 | 
			
		||||
    _contextAttributes = list(IPredicate) # + list(IConcept)
 | 
			
		||||
 | 
			
		||||
    def getOptions(self):
 | 
			
		||||
        return getattr(self.context, '_options', [])
 | 
			
		||||
    def setOptions(self, value):
 | 
			
		||||
        self.context._options = value
 | 
			
		||||
    options = property(getOptions, setOptions)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PredicateInterfaceSourceList(TypeInterfaceSourceList):
 | 
			
		||||
    """ Collects type interfaces for predicates, i.e. interfaces that
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,10 @@
 | 
			
		|||
        title="[loops-master-role] loops: Master" />
 | 
			
		||||
  <grant role="loops.Master" permission="zope.ManageContent" />
 | 
			
		||||
 | 
			
		||||
  <role id="loops.Member"
 | 
			
		||||
        title="[loops-member-role] loops: Member" />
 | 
			
		||||
  <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" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
#
 | 
			
		||||
#  Copyright (c) 2008 Helmut Merz helmutm@cy55.de
 | 
			
		||||
#  Copyright (c) 2009 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
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,9 @@ Common functions and other stuff for working with permissions and roles.
 | 
			
		|||
$Id$
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from persistent import Persistent
 | 
			
		||||
from zope import component
 | 
			
		||||
from zope.annotation.interfaces import IAttributeAnnotatable
 | 
			
		||||
from zope.app.container.interfaces import IObjectAddedEvent
 | 
			
		||||
from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
 | 
			
		||||
from zope.app.securitypolicy.interfaces import IRolePermissionManager
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +34,7 @@ from zope.lifecycleevent import IObjectCreatedEvent, IObjectModifiedEvent
 | 
			
		|||
from zope.security import canAccess, canWrite
 | 
			
		||||
from zope.security import checkPermission as baseCheckPermission
 | 
			
		||||
from zope.security.management import getInteraction
 | 
			
		||||
from zope.traversing.interfaces import IPhysicallyLocatable
 | 
			
		||||
 | 
			
		||||
from loops.common import adapted
 | 
			
		||||
from loops.interfaces import ILoopsObject, IConcept
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +47,7 @@ allRolesExceptOwner = (
 | 
			
		|||
        'zope.Anonymous', 'zope.Member', 'zope.ContentManager', 'loops.Staff',
 | 
			
		||||
        'loops.xmlrpc.ConceptManager', # relevant for local security?
 | 
			
		||||
        #'loops.SiteManager',
 | 
			
		||||
        'loops.Master',)
 | 
			
		||||
         'loops.Member', 'loops.Master',)
 | 
			
		||||
allRolesExceptOwnerAndMaster = tuple(allRolesExceptOwner[:-1])
 | 
			
		||||
minorPrivilegedRoles = ('zope.Anonymous', 'zope.Member',)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -137,3 +140,21 @@ def revokeAcquiredSecurity(obj, event):
 | 
			
		|||
    setter = ISecuritySetter(aObj)
 | 
			
		||||
    setter.setAcquiredRolePermissions(event.relation, revert=True)
 | 
			
		||||
    setter.setAcquiredPrincipalRoles(event.relation, revert=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# helper stuff
 | 
			
		||||
 | 
			
		||||
class WorkspaceInformation(Persistent):
 | 
			
		||||
    """ For storing security-related stuff pertaining to
 | 
			
		||||
        children and resources of the context (=parent) object.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    implements(IPhysicallyLocatable)
 | 
			
		||||
 | 
			
		||||
    __name__ = u'workspace_information'
 | 
			
		||||
 | 
			
		||||
    def __init__(self, parent):
 | 
			
		||||
        self.__parent__ = parent
 | 
			
		||||
 | 
			
		||||
    def getName(self):
 | 
			
		||||
        return self.__name__
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,10 @@
 | 
			
		|||
 | 
			
		||||
  <zope:adapter factory="loops.security.setter.BaseSecuritySetter" />
 | 
			
		||||
 | 
			
		||||
  <zope:class class="loops.security.common.WorkspaceInformation">
 | 
			
		||||
    <implements interface="zope.annotation.interfaces.IAttributeAnnotatable" />
 | 
			
		||||
  </zope:class>
 | 
			
		||||
 | 
			
		||||
  <zope:adapter
 | 
			
		||||
        for="loops.interfaces.IConcept"
 | 
			
		||||
        factory="zope.app.securitypolicy.rolepermission.AnnotationRolePermissionManager"
 | 
			
		||||
| 
						 | 
				
			
			@ -32,4 +36,18 @@
 | 
			
		|||
        class=".perm.PermissionView"
 | 
			
		||||
        menu="zmi_actions" title="Edit Permissions" />
 | 
			
		||||
 | 
			
		||||
  <browser:page
 | 
			
		||||
        for="loops.interfaces.IConcept"
 | 
			
		||||
        name="grantchildren.html"
 | 
			
		||||
        permission="zope.Security"
 | 
			
		||||
        template="manage_grantchildrenform.pt"
 | 
			
		||||
        class=".perm.GrantChildrenView" />
 | 
			
		||||
 | 
			
		||||
  <browser:menuItem
 | 
			
		||||
        for="loops.interfaces.IConcept"
 | 
			
		||||
        action="@@grantchildren.html"
 | 
			
		||||
        permission="zope.Security"
 | 
			
		||||
        menu="zmi_actions" title="Grant Children"
 | 
			
		||||
        filter="python: context.isWorkspace" />
 | 
			
		||||
 | 
			
		||||
</configure>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										84
									
								
								security/manage_grantchildrenform.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								security/manage_grantchildrenform.pt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
<html metal:use-macro="context/@@standard_macros/page"
 | 
			
		||||
    i18n:domain="zope">
 | 
			
		||||
<body>
 | 
			
		||||
<div metal:fill-slot="body" i18n:domain="zope">
 | 
			
		||||
  <h2 i18n:translate="">Grant Roles for Children of this Object to Principals</h2>
 | 
			
		||||
  <p tal:define="status view/status"
 | 
			
		||||
     tal:condition="status"
 | 
			
		||||
     tal:content="status" i18n:translate=""/>
 | 
			
		||||
             
 | 
			
		||||
           
 | 
			
		||||
 | 
			
		||||
  <div class="form-element"
 | 
			
		||||
       tal:define="perm view/permission"
 | 
			
		||||
       tal:condition="not: view/principal">
 | 
			
		||||
    <table width="100%" cellspacing="0" cellpadding="2" border="0"
 | 
			
		||||
        nowrap="nowrap">
 | 
			
		||||
      <tr class="list-header">
 | 
			
		||||
        <td><strong i18n:translate="">Role</strong></td>
 | 
			
		||||
        <td><strong i18n:translate="">Users/Groups</strong></td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr class="row-normal"
 | 
			
		||||
          tal:repeat="setting perm/roleSettings"
 | 
			
		||||
          tal:attributes="class python:
 | 
			
		||||
                path('repeat/setting/even') and 'row-normal' or 'row-hilite'">
 | 
			
		||||
        <tal:role define="ir repeat/setting/index;
 | 
			
		||||
                          roleId python:path('view/roles')[ir].id">
 | 
			
		||||
          <td align="left" valign="top"
 | 
			
		||||
              tal:content="roleId">Manager</td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <span tal:define="users python: view.listUsersForRole(roleId)"
 | 
			
		||||
                  tal:replace="structure users">User xy</span></td>
 | 
			
		||||
        </tal:role>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </table>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <form action="" method="POST">
 | 
			
		||||
 | 
			
		||||
    <div tal:content="structure view/principal_widget">...</div>
 | 
			
		||||
 | 
			
		||||
    <div tal:condition="view/principal">
 | 
			
		||||
 | 
			
		||||
      <h2 i18n:translate="">Grants for the selected principal</h2>
 | 
			
		||||
      <input type="submit" name="GRANT_SUBMIT" value="Change" 
 | 
			
		||||
             i18n:attributes="value grant-submit" />
 | 
			
		||||
 | 
			
		||||
      <table width="100%" border="0">
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td valign="top">
 | 
			
		||||
            <table class="matrix">
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td i18n:translate=""><strong>Roles</strong> </td>
 | 
			
		||||
                <td i18n:translate=""><strong>Allow</strong> </td>
 | 
			
		||||
                <td i18n:translate=""><strong>Unset</strong> </td>
 | 
			
		||||
                <td i18n:translate=""><strong>Deny</strong> </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr tal:repeat="widget view/roles">
 | 
			
		||||
                <td valign="top" nowrap>
 | 
			
		||||
                  <div class="label">
 | 
			
		||||
                    <label for="field.name" title="The widget's hint"
 | 
			
		||||
                           tal:attributes="for widget/name; title widget/hint"
 | 
			
		||||
                           tal:content="widget/label"
 | 
			
		||||
                           i18n:translate="">The Label</label>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </td>
 | 
			
		||||
                <tal:block tal:content="structure widget">
 | 
			
		||||
                  roles widget
 | 
			
		||||
                </tal:block>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td colspan="2"><a href="#top" i18n:translate="">^ top</a></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </table>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </table>
 | 
			
		||||
      <input type="submit" name="GRANT_SUBMIT" value="Change" 
 | 
			
		||||
             i18n:attributes="value grant-submit" />
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </form>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +1,5 @@
 | 
			
		|||
<html metal:use-macro="context/@@standard_macros/view"
 | 
			
		||||
    i18n:domain="zope">
 | 
			
		||||
<head>
 | 
			
		||||
  <style metal:fill-slot="headers" type="text/css">
 | 
			
		||||
    <!--
 | 
			
		||||
    .row-normal {
 | 
			
		||||
      background-color: #ffffff;
 | 
			
		||||
      border: none;
 | 
			
		||||
    }
 | 
			
		||||
    .row-hilite {
 | 
			
		||||
      background-color: #efefef;
 | 
			
		||||
      border: none;
 | 
			
		||||
    }
 | 
			
		||||
    -->
 | 
			
		||||
  </style>
 | 
			
		||||
</head>
 | 
			
		||||
      i18n:domain="zope">
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
<div metal:fill-slot="body">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,13 +26,17 @@ from zope import component
 | 
			
		|||
from zope.interface import implements
 | 
			
		||||
from zope.cachedescriptors.property import Lazy
 | 
			
		||||
from zope.app.security.interfaces import IPermission
 | 
			
		||||
from zope.app.securitypolicy.browser.granting import Granting
 | 
			
		||||
from zope.app.securitypolicy.browser.rolepermissionview import RolePermissionView
 | 
			
		||||
from zope.app.securitypolicy.interfaces import IPrincipalRoleManager, IRolePermissionMap
 | 
			
		||||
from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager, \
 | 
			
		||||
                                               IPrincipalPermissionMap
 | 
			
		||||
from zope.app.securitypolicy.zopepolicy import SettingAsBoolean
 | 
			
		||||
from zope.security.proxy import removeSecurityProxy
 | 
			
		||||
from zope.traversing.api import getParents
 | 
			
		||||
 | 
			
		||||
from loops.security.common import WorkspaceInformation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PermissionView(object):
 | 
			
		||||
    """ View for permission editing.
 | 
			
		||||
| 
						 | 
				
			
			@ -135,3 +139,16 @@ class PermissionView(object):
 | 
			
		|||
    def getPermissions(self):
 | 
			
		||||
        return sorted(name for name, perm in component.getUtilitiesFor(IPermission))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GrantChildrenView(Granting, PermissionView):
 | 
			
		||||
    """ View for editing grants for children of workspace objects.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, context, request):
 | 
			
		||||
        context = removeSecurityProxy(context)
 | 
			
		||||
        wi = context.workspaceInformation
 | 
			
		||||
        if wi is None:
 | 
			
		||||
            wi = context.workspaceInformation = WorkspaceInformation(context)
 | 
			
		||||
        #self.context = wi
 | 
			
		||||
        #self.request = request
 | 
			
		||||
        PermissionView.__init__(self, wi, request)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue