[Zope3-checkins]
SVN: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/
Merged from trunk:
Jim Fulton
jim at zope.com
Fri Jul 23 14:42:15 EDT 2004
Log message for revision 26714:
Merged from trunk:
r26668 | jim | 2004-07-21 18:52:23 -0400 (Wed, 21 Jul 2004) | 17 lines
- Fixed a bug (actually a missfeature). It wasn't possible
for local settings to override global (zcml) settings.
- Changed the way role denies work. A role deny simply prevents
a principal from having a role. A principal may still
have access through other roles or through principal grants.
Role grants or denies never override principal grants or denies
*even* if the role-based grants or denies are more local.
- Implemented a caching scheme that provides huge performance
benefits when the authenticated principal is defined in a local auth
service, rather than a global one (zcml).
- Refactored the way security maps were implemented and used.
Especially changed the way annotations were handled.
Changed:
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/configure.zcml
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/rolepermissionview.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/configure.zcml
A Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/grantinfo.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/interfaces.py
D Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/permissionroles.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalpermission.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalrole.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/rolepermission.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/securitymap.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_securitymap.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_zopepolicy.py
U Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.py
A Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.txt
-=-
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/configure.zcml
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/configure.zcml 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/configure.zcml 2004-07-23 18:42:15 UTC (rev 26714)
@@ -76,6 +76,17 @@
template="grant.pt"
menu="zmi_actions" title="Grant" />
+ <zope:class class=".rolepermissionview.PermissionRoles">
+ <zope:require permission="zope.Security"
+ attributes="roles rolesInfo id title description" />
+ </zope:class>
+
+ <zope:class class=".rolepermissionview.RolePermissions">
+ <zope:require
+ permission="zope.Security"
+ attributes="permissions permissionsInfo id title description" />
+ </zope:class>
+
<!-- Principal Roles -->
<page
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/rolepermissionview.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/rolepermissionview.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/browser/rolepermissionview.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -17,14 +17,13 @@
"""
from datetime import datetime
+from zope.interface import implements
+
from zope.app import zapi
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.app.security.settings import Unset, Allow, Deny
from zope.app.security.interfaces import IPermission
-
from zope.app.securitypolicy.interfaces import IRole, IRolePermissionManager
-from zope.app.securitypolicy.permissionroles import PermissionRoles
-from zope.app.securitypolicy.rolepermission import RolePermissions
class RolePermissionView:
@@ -141,3 +140,76 @@
return status
+
+class PermissionRoles(object):
+
+ implements(IPermission)
+
+ def __init__(self, permission, context, roles):
+ self._permission = permission
+ self._context = context
+ self._roles = roles
+
+ def _getId(self):
+ return self._permission.id
+
+ id = property(_getId)
+
+ def _getTitle(self):
+ return self._permission.title
+
+ title = property(_getTitle)
+
+ def _getDescription(self):
+ return self._permission.description
+
+ description = property(_getDescription)
+
+ def roleSettings(self):
+ """
+ Returns the list of setting names of each role for this permission.
+ """
+ prm = IRolePermissionManager(self._context)
+ proles = prm.getRolesForPermission(self._permission.id)
+ settings = {}
+ for role, setting in proles:
+ settings[role] = setting.getName()
+ nosetting = Unset.getName()
+ return [settings.get(role.id, nosetting) for role in self._roles]
+
+class RolePermissions(object):
+
+ implements(IRole)
+
+ def __init__(self, role, context, permissions):
+ self._role = role
+ self._context = context
+ self._permissions = permissions
+
+ def _getId(self):
+ return self._role.id
+
+ id = property(_getId)
+
+ def _getTitle(self):
+ return self._role.title
+
+ title = property(_getTitle)
+
+ def _getDescription(self):
+ return self._role.description
+
+ description = property(_getDescription)
+
+ def permissionsInfo(self):
+ prm = IRolePermissionManager(self._context)
+ rperms = prm.getPermissionsForRole(self._role.id)
+ settings = {}
+ for permission, setting in rperms:
+ settings[permission] = setting.getName()
+ nosetting = Unset.getName()
+ return [{'id': permission.id,
+ 'title': permission.title,
+ 'setting': settings.get(permission.id, nosetting)}
+ for permission in self._permissions]
+
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/configure.zcml
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/configure.zcml 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/configure.zcml 2004-07-23 18:42:15 UTC (rev 26714)
@@ -3,29 +3,56 @@
i18n_domain="zope"
>
- <content class=".permissionroles.PermissionRoles">
- <require permission="zope.Security"
- attributes="roles rolesInfo id title description" />
- </content>
-
- <content class=".rolepermission.RolePermissions">
- <require permission="zope.Security"
- attributes="permissions permissionsInfo id title description" />
- </content>
-
<adapter factory=".rolepermission.AnnotationRolePermissionManager"
provides=".interfaces.IRolePermissionManager"
- for="zope.app.annotation.interfaces.IAnnotatable" />
+ for="zope.app.annotation.interfaces.IAnnotatable"
+ trusted="true"
+ />
+ <class class=".rolepermission.AnnotationRolePermissionManager">
+ <require
+ permission="zope.Security"
+ attributes="grantPermissionToRole denyPermissionToRole
+ unsetPermissionFromRole"
+ />
+ <allow interface=".interfaces.IRolePermissionMap" />
+ </class>
+
<adapter factory=".principalrole.AnnotationPrincipalRoleManager"
provides=".interfaces.IPrincipalRoleManager"
- for="zope.app.annotation.interfaces.IAnnotatable" />
+ for="zope.app.annotation.interfaces.IAnnotatable"
+ trusted="true"
+ />
+ <class class=".principalrole.AnnotationPrincipalRoleManager">
+ <require
+ permission="zope.Security"
+ attributes="assignRoleToPrincipal removeRoleFromPrincipal
+ unsetRoleForPrincipal"
+ />
+ <allow interface=".interfaces.IPrincipalRoleMap" />
+ </class>
+
<adapter factory=".principalpermission.AnnotationPrincipalPermissionManager"
provides=".interfaces.IPrincipalPermissionManager"
- for="zope.app.annotation.interfaces.IAnnotatable" />
+ for="zope.app.annotation.interfaces.IAnnotatable"
+ trusted="true"
+ />
+ <class class=".principalpermission.AnnotationPrincipalPermissionManager">
+ <require
+ permission="zope.Security"
+ attributes="grantPermissionToRole denyPermissionToRole
+ unsetPermissionFromRole"
+ />
+ <allow interface=".interfaces.IPrincipalPermissionMap" />
+ </class>
+ <adapter factory=".grantinfo.AnnotationGrantInfo"
+ provides=".interfaces.IGrantInfo"
+ for="zope.app.annotation.interfaces.IAnnotatable"
+ />
+
<!-- protect Roles and Permissions -->
<content class=".role.Role">
<allow interface=".interfaces.IRole" />
Copied: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/grantinfo.py (from rev 26668, Zope3/trunk/src/zope/app/securitypolicy/grantinfo.py)
Property changes on: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/grantinfo.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/interfaces.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/interfaces.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/interfaces.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -18,28 +18,6 @@
from zope.interface import Interface
from zope.schema import TextLine, Text
-class ISecurityMap(Interface):
- """Security map to hold matrix-like relationships."""
-
- def addCell(rowentry, colentry, value):
- " add a cell "
-
- def delCell(rowentry, colentry):
- " delete a cell "
-
- # XXX queryCell / getCell ?
- def getCell(rowentry, colentry, default=None):
- " return the value of a cell by row, entry "
-
- def getRow(rowentry):
- " return a list of (colentry, value) tuples from a row "
-
- def getCol(colentry):
- " return a list of (rowentry, value) tuples from a col "
-
- def getAllCells():
- " return a list of (rowentry, colentry, value) "
-
class IRole(Interface):
"""A role object."""
@@ -220,3 +198,27 @@
"""Remove the permission (either denied or allowed) from the
principal.
"""
+
+class IGrantInfo(Interface):
+ """Get grant info needed for checking access
+ """
+
+ def principalPermissionGrant(principal, permission):
+ """Return the principal-permission grant if any
+
+ The return value is one of Allow, Deny, or Unset
+ """
+
+ def getRolesForPermission(permission):
+ """Return the role grants for the permission
+
+ The role grants are an iterable of role, setting tuples, where
+ setting is either Allow or Deny.
+ """
+
+ def getRolesForPrincipal(principal):
+ """Return the role grants for the principal
+
+ The role grants are an iterable of role, setting tuples, where
+ setting is either Allow or Deny.
+ """
Deleted: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/permissionroles.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/permissionroles.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/permissionroles.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -1,57 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""
-$Id$
-"""
-from zope.interface import implements
-
-from zope.app.security.interfaces import IPermission
-from zope.app.security.settings import Unset
-from zope.app.securitypolicy.interfaces import IRolePermissionManager
-
-class PermissionRoles(object):
-
- implements(IPermission)
-
- def __init__(self, permission, context, roles):
- self._permission = permission
- self._context = context
- self._roles = roles
-
- def _getId(self):
- return self._permission.id
-
- id = property(_getId)
-
- def _getTitle(self):
- return self._permission.title
-
- title = property(_getTitle)
-
- def _getDescription(self):
- return self._permission.description
-
- description = property(_getDescription)
-
- def roleSettings(self):
- """
- Returns the list of setting names of each role for this permission.
- """
- prm = IRolePermissionManager(self._context)
- proles = prm.getRolesForPermission(self._permission.id)
- settings = {}
- for role, setting in proles:
- settings[role] = setting.getName()
- nosetting = Unset.getName()
- return [settings.get(role.id, nosetting) for role in self._roles]
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalpermission.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalpermission.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalpermission.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -17,7 +17,6 @@
"""
from zope.interface import implements
-from zope.app.annotation.interfaces import IAnnotations
from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager
from zope.app.security.settings import Allow, Deny, Unset
@@ -25,87 +24,37 @@
from zope.app.security.permission import allPermissions
from zope.app.securitypolicy.securitymap import SecurityMap
+from zope.app.securitypolicy.securitymap import AnnotationSecurityMap
-# This is misspelled, but that's OK. It just has to be unique.
-# we'll keep it as is, to prevent breaking on data:
-annotation_key = 'zopel.app.security.AnnotationPrincipalPermissionManager'
-class AnnotationPrincipalPermissionManager:
+class AnnotationPrincipalPermissionManager(AnnotationSecurityMap):
"""Mappings between principals and permissions."""
+ # the annotation key is a holdover from this module's old
+ # location, but cannot change without breaking existing databases
+ # It is also is misspelled, but that's OK. It just has to be unique.
+ # we'll keep it as is, to prevent breaking old data:
+ key = 'zopel.app.security.AnnotationPrincipalPermissionManager'
+
implements(IPrincipalPermissionManager)
- def __init__(self, context):
- self._context = context
-
def grantPermissionToPrincipal(self, permission_id, principal_id):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions(create=1)
- pp.addCell(permission_id, principal_id, Allow)
- self._context._p_changed = 1
+ AnnotationSecurityMap.addCell(self, permission_id, principal_id, Allow)
def denyPermissionToPrincipal(self, permission_id, principal_id):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions(create=1)
- pp.addCell(permission_id, principal_id, Deny)
- self._context._p_changed = 1
+ AnnotationSecurityMap.addCell(self, permission_id, principal_id, Deny)
- def unsetPermissionForPrincipal(self, permission_id, principal_id):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions()
- # Only unset if there is a security map, otherwise, we're done
- if pp:
- pp.delCell(permission_id, principal_id)
- self._context._p_changed = 1
+ unsetPermissionForPrincipal = AnnotationSecurityMap.delCell
+ getPrincipalsForPermission = AnnotationSecurityMap.getRow
+ getPermissionsForPrincipal = AnnotationSecurityMap.getCol
- def getPrincipalsForPermission(self, permission_id):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions()
- if pp:
- return pp.getRow(permission_id)
- return []
+ def getSetting(self, permission_id, principal_id, default=Unset):
+ return AnnotationSecurityMap.queryCell(
+ self, permission_id, principal_id, default)
+
+ getPrincipalsAndPermissions = AnnotationSecurityMap.getAllCells
- def getPermissionsForPrincipal(self, principal_id):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions()
- if pp:
- return pp.getCol(principal_id)
- return []
- def getSetting(self, permission_id, principal_id):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions()
- if pp:
- return pp.getCell(permission_id, principal_id, default=Unset)
- return []
-
- def getPrincipalsAndPermissions(self):
- ''' See the interface IPrincipalPermissionManager '''
- pp = self._getPrincipalPermissions()
- if pp:
- return pp.getAllCells()
- return []
-
- # Implementation helpers
-
- def _getPrincipalPermissions(self, create=0):
- """ Get the principal permission map stored in the context, optionally
- creating one if necessary """
- # need to remove security proxies here, otherwise we enter
- # an infinite loop, becuase checking security depends on
- # getting PrincipalPermissions.
- from zope.proxy import removeAllProxies
- context = removeAllProxies(self._context)
- annotations = IAnnotations(context)
- try:
- return annotations[annotation_key]
- except KeyError:
- if create:
- rp = annotations[annotation_key] = SecurityMap()
- return rp
- return None
-
-
class PrincipalPermissionManager(SecurityMap):
"""Mappings between principals and permissions."""
@@ -151,9 +100,9 @@
''' See the interface IPrincipalPermissionManager '''
return self.getCol(principal_id)
- def getSetting(self, permission_id, principal_id):
+ def getSetting(self, permission_id, principal_id, default=Unset):
''' See the interface IPrincipalPermissionManager '''
- return self.getCell(permission_id, principal_id, default=Unset)
+ return self.queryCell(permission_id, principal_id, default)
def getPrincipalsAndPermissions(self):
''' See the interface IPrincipalPermissionManager '''
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalrole.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalrole.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/principalrole.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -16,95 +16,46 @@
__metaclass__ = type
from zope.interface import implements
-from zope.security.proxy import trustedRemoveSecurityProxy
-from zope.app.annotation.interfaces import IAnnotations
from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
-from zope.app.securitypolicy.interfaces import IPrincipalRoleMap
from zope.app.security.settings import Allow, Deny, Unset
from zope.app.securitypolicy.securitymap import SecurityMap
-from zope.app.securitypolicy.securitymap import PersistentSecurityMap
+from zope.app.securitypolicy.securitymap import AnnotationSecurityMap
from zope.app.security.principal import checkPrincipal
from zope.app.securitypolicy.role import checkRole
-annotation_key = 'zope.app.security.AnnotationPrincipalRoleManager'
-
-class AnnotationPrincipalRoleManager:
+class AnnotationPrincipalRoleManager(AnnotationSecurityMap):
"""Mappings between principals and roles."""
+ # the annotation key is a holdover from this module's old
+ # location, but cannot change without breaking existing databases
+ key = 'zope.app.security.AnnotationPrincipalRoleManager'
+
implements(IPrincipalRoleManager)
- def __init__(self, context):
- self._context = context
-
def assignRoleToPrincipal(self, role_id, principal_id):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles(create=1)
- pp.addCell(role_id, principal_id, Allow)
+ AnnotationSecurityMap.addCell(self, role_id, principal_id, Allow)
def removeRoleFromPrincipal(self, role_id, principal_id):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles(create=1)
- pp.addCell(role_id, principal_id, Deny)
+ AnnotationSecurityMap.addCell(self, role_id, principal_id, Deny)
- def unsetRoleForPrincipal(self, role_id, principal_id):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles()
- # Only unset if there is a security map, otherwise, we're done
- if pp:
- pp.delCell(role_id, principal_id)
-
- def getPrincipalsForRole(self, role_id):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles()
- if pp:
- return pp.getRow(role_id)
- return []
-
- def getRolesForPrincipal(self, principal_id):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles()
- if pp:
- return pp.getCol(principal_id)
- return []
-
+ unsetRoleForPrincipal = AnnotationSecurityMap.delCell
+ getPrincipalsForRole = AnnotationSecurityMap.getRow
+ getRolesForPrincipal = AnnotationSecurityMap.getCol
+
def getSetting(self, role_id, principal_id):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles()
- if pp:
- return pp.getCell(role_id, principal_id, default=Unset)
- return Unset
+ return AnnotationSecurityMap.queryCell(
+ self, role_id, principal_id, default=Unset)
- def getPrincipalsAndRoles(self):
- ''' See the interface IPrincipalRoleManager '''
- pp = self._getPrincipalRoles()
- if pp:
- return pp.getAllCells()
- return []
+ getPrincipalsAndRoles = AnnotationSecurityMap.getAllCells
- # Implementation helpers
- def _getPrincipalRoles(self, create=0):
- """ Get the principal role map stored in the context, optionally
- creating one if necessary """
- annotations = IAnnotations(self._context)
- try:
- # there's a chance that annotations is security proxied -
- # remove proxy to avoid authentication failure on role lookup
- return trustedRemoveSecurityProxy(annotations)[annotation_key]
- except KeyError:
- if create:
- rp = annotations[annotation_key] = PersistentSecurityMap()
- return rp
- return None
-
-
class PrincipalRoleManager(SecurityMap):
"""Mappings between principals and roles."""
- implements(IPrincipalRoleManager, IPrincipalRoleMap)
+ implements(IPrincipalRoleManager)
def assignRoleToPrincipal(self, role_id, principal_id, check=True):
''' See the interface IPrincipalRoleManager '''
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/rolepermission.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/rolepermission.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/rolepermission.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -16,7 +16,6 @@
"""
from zope.interface import implements
-from zope.app.annotation.interfaces import IAnnotations
from zope.app.security.settings import Allow, Deny, Unset
from zope.app.security.permission import allPermissions
@@ -25,135 +24,35 @@
from zope.app.securitypolicy.interfaces import IRolePermissionManager
from zope.app.securitypolicy.interfaces import IRole
from zope.app.securitypolicy.interfaces import IRolePermissionMap
-from zope.app.securitypolicy.securitymap import PersistentSecurityMap
+from zope.app.securitypolicy.securitymap import AnnotationSecurityMap
from zope.app.securitypolicy.securitymap import SecurityMap
-# the annotation_key is a holdover from this module's old location, but cannot
-# change without breaking existing databases
-annotation_key = 'zope.app.security.AnnotationRolePermissionManager'
-class AnnotationRolePermissionManager(object):
+class AnnotationRolePermissionManager(AnnotationSecurityMap):
"""Provide adapter that manages role permission data in an object attribute
"""
- implements(IRolePermissionManager, IRolePermissionMap)
+ # the annotation key is a holdover from this module's old
+ # location, but cannot change without breaking existing databases
+ key = 'zope.app.security.AnnotationRolePermissionManager'
- def __init__(self, context):
- self._context = context
+ implements(IRolePermissionManager)
def grantPermissionToRole(self, permission_id, role_id):
- ''' See the interface IRolePermissionManager '''
- rp = self._getRolePermissions(create=1)
- rp.addCell(permission_id, role_id, Allow)
- # probably not needed, as annotations should manage
- # their own persistence
- #self._context._p_changed = 1
+ AnnotationSecurityMap.addCell(self, permission_id, role_id, Allow)
def denyPermissionToRole(self, permission_id, role_id):
- ''' See the interface IRolePermissionManager '''
- rp = self._getRolePermissions(create=1)
- rp.addCell(permission_id, role_id, Deny)
- # probably not needed, as annotations should manage
- # their own persistence
- #self._context._p_changed = 1
+ AnnotationSecurityMap.addCell(self, permission_id, role_id, Deny)
- def unsetPermissionFromRole(self, permission_id, role_id):
- ''' See the interface IRolePermissionManager '''
- rp = self._getRolePermissions()
- # Only unset if there is a security map, otherwise, we're done
- if rp:
- rp.delCell(permission_id, role_id)
- # probably not needed, as annotations should manage
- # their own persistence
- #self._context._p_changed = 1
+ unsetPermissionFromRole = AnnotationSecurityMap.delCell
+ getRolesForPermission = AnnotationSecurityMap.getRow
+ getPermissionsForRole = AnnotationSecurityMap.getCol
+ getRolesAndPermissions = AnnotationSecurityMap.getAllCells
- def getRolesForPermission(self, permission_id):
- '''See interface IRolePermissionMap'''
- rp = self._getRolePermissions()
- if rp:
- return rp.getRow(permission_id)
- else:
- return []
-
- def getPermissionsForRole(self, role_id):
- '''See interface IRolePermissionMap'''
- rp = self._getRolePermissions()
- if rp:
- return rp.getCol(role_id)
- else:
- return []
-
- def getRolesAndPermissions(self):
- '''See interface IRolePermissionMap'''
- rp = self._getRolePermissions()
- if rp:
- return rp.getAllCells()
- else:
- return []
-
def getSetting(self, permission_id, role_id):
- '''See interface IRolePermissionMap'''
- rp = self._getRolePermissions()
- if rp:
- return rp.getCell(permission_id, role_id)
- else:
- return Unset
+ return AnnotationSecurityMap.queryCell(
+ self, permission_id, role_id, default=Unset)
- def _getRolePermissions(self, create=0):
- """Get the role permission map stored in the context, optionally
- creating one if necessary"""
- # need to remove security proxies here, otherwise we enter
- # an infinite loop, becuase checking security depends on
- # getting RolePermissions.
- from zope.proxy import removeAllProxies
- context = removeAllProxies(self._context)
- annotations = IAnnotations(context)
- try:
- return annotations[annotation_key]
- except KeyError:
- if create:
- rp = annotations[annotation_key] = PersistentSecurityMap()
- return rp
- return None
-
-class RolePermissions(object):
-
- implements(IRole)
-
- def __init__(self, role, context, permissions):
- self._role = role
- self._context = context
- self._permissions = permissions
-
-
- def _getId(self):
- return self._role.id
-
- id = property(_getId)
-
- def _getTitle(self):
- return self._role.title
-
- title = property(_getTitle)
-
- def _getDescription(self):
- return self._role.description
-
- description = property(_getDescription)
-
- def permissionsInfo(self):
- prm = IRolePermissionManager(self._context)
- rperms = prm.getPermissionsForRole(self._role.id)
- settings = {}
- for permission, setting in rperms:
- settings[permission] = setting.getName()
- nosetting = Unset.getName()
- return [{'id': permission.id,
- 'title': permission.title,
- 'setting': settings.get(permission.id, nosetting)}
- for permission in self._permissions]
-
-
class RolePermissionManager(SecurityMap):
"""Mappings between roles and permissions."""
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/securitymap.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/securitymap.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/securitymap.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -14,14 +14,11 @@
""" Generic two-dimensional array type """
from persistent import Persistent
-from persistent.dict import PersistentDict
-from zope.interface import implements
-from zope.app.securitypolicy.interfaces import ISecurityMap
+from zope.app.annotation import IAnnotations
+from zope.security.management import queryInteraction
class SecurityMap(object):
- implements(ISecurityMap)
-
def __init__(self):
self._clear()
@@ -29,73 +26,133 @@
self._byrow = {}
self._bycol = {}
- def _empty_mapping(self):
- return {}
+ def __nonzero__(self):
+ return bool(self._byrow)
def addCell(self, rowentry, colentry, value):
# setdefault may get expensive if an empty mapping is
# expensive to create, for PersistentDict for instance.
- row = self._byrow.setdefault(rowentry, self._empty_mapping())
+ row = self._byrow.get(rowentry)
+ if row:
+ if row.get(colentry) is value:
+ return False
+ else:
+ row = self._byrow[rowentry] = {}
+
+ col = self._bycol.get(colentry)
+ if not col:
+ col = self._bycol[colentry] = {}
+
row[colentry] = value
-
- col = self._bycol.setdefault(colentry, self._empty_mapping())
col[rowentry] = value
- try:
- del self._v_cells
- except AttributeError:
- pass
+ self._invalidated_interaction_cache()
+
+ return True
+
+ def _invalidated_interaction_cache(self):
+ # Invalidate this threads interaction cache
+ interaction = queryInteraction()
+ if interaction is not None:
+ try:
+ invalidate_cache = interaction.invalidate_cache
+ except AttributeError:
+ pass
+ else:
+ invalidate_cache()
+
def delCell(self, rowentry, colentry):
row = self._byrow.get(rowentry)
if row and (colentry in row):
- del self._byrow[rowentry][colentry]
- del self._bycol[colentry][rowentry]
- try:
- del self._v_cells
- except AttributeError:
- pass
+ del row[colentry]
+ if not row:
+ del self._byrow[rowentry]
+ col = self._bycol[colentry]
+ del col[rowentry]
+ if not col:
+ del self._bycol[colentry]
- def getCell(self, rowentry, colentry, default=None):
- " return the value of a cell by row, entry "
+ self._invalidated_interaction_cache()
+
+ return True
+
+ return False
+
+ def queryCell(self, rowentry, colentry, default=None):
row = self._byrow.get(rowentry)
- if row: return row.get(colentry, default)
- else: return default
+ if row:
+ return row.get(colentry, default)
+ else:
+ return default
+ def getCell(self, rowentry, colentry):
+ marker = object()
+ cell = self.queryCell(rowentry, colentry, marker)
+ if cell is marker:
+ raise KeyError('Not a valid row and column pair.')
+ return cell
+
def getRow(self, rowentry):
- " return a list of (colentry, value) tuples from a row "
row = self._byrow.get(rowentry)
if row:
return row.items()
- else: return []
+ else:
+ return []
def getCol(self, colentry):
- " return a list of (rowentry, value) tuples from a col "
col = self._bycol.get(colentry)
if col:
return col.items()
- else: return []
+ else:
+ return []
def getAllCells(self):
- " return a list of (rowentry, colentry, value) "
- try:
- return self._v_cells
- except AttributeError:
- pass
res = []
for r in self._byrow.keys():
for c in self._byrow[r].items():
res.append((r,) + c)
- self._v_cells = res
return res
-
class PersistentSecurityMap(SecurityMap, Persistent):
- implements(ISecurityMap)
+ def addCell(self, rowentry, colentry, value):
+ if SecurityMap.addCell(self, rowentry, colentry, value):
+ self._p_changed = 1
- def _clear(self):
- self._byrow = PersistentDict()
- self._bycol = PersistentDict()
+ def delCell(self, rowentry, colentry):
+ if SecurityMap.delCell(self, rowentry, colentry):
+ self._p_changed = 1
- def _empty_mapping(self):
- return PersistentDict()
+class AnnotationSecurityMap(SecurityMap):
+
+ def __init__(self, context):
+ self._context = context
+ annotations = IAnnotations(self._context)
+ map = annotations.get(self.key)
+ if map is None:
+ self._byrow = {}
+ self._bycol = {}
+ else:
+ self._byrow = map._byrow
+ self._bycol = map._bycol
+ self.map = map
+
+ def _changed(self):
+ map = self.map
+ if isinstance(map, PersistentSecurityMap):
+ map._p_changed
+ else:
+ map = PersistentSecurityMap()
+ map._byrow = self._byrow
+ map._bycol = self._bycol
+ annotations = IAnnotations(self._context)
+ annotations[self.key] = map
+
+ def addCell(self, rowentry, colentry, value):
+ if SecurityMap.addCell(self, rowentry, colentry, value):
+ self._changed()
+
+ def delCell(self, rowentry, colentry):
+ if SecurityMap.delCell(self, rowentry, colentry):
+ self._changed()
+
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_securitymap.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_securitymap.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_securitymap.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -11,30 +11,156 @@
# FOR A PARTICULAR PURPOSE.
#
#############################################################################
-"""
+"""Test SecurityMap implementations
+
$Id$
"""
import unittest
from zope.interface.verify import verifyClass
-from zope.app.securitypolicy.interfaces import ISecurityMap
from zope.app.securitypolicy.securitymap import SecurityMap
from zope.app.securitypolicy.securitymap import PersistentSecurityMap
+from zope.security.management import setSecurityPolicy, getInteraction
+from zope.security.management import newInteraction, endInteraction
+class InteractionStub:
+ invalidated = 0
+ def invalidate_cache(self):
+ self.invalidated += 1
+
+
class TestSecurityMap(unittest.TestCase):
- def testInterface(self):
- verifyClass(ISecurityMap, SecurityMap)
+ def setUp(self):
+ self.oldpolicy = setSecurityPolicy(InteractionStub)
+ newInteraction()
- # XXX Test the map. Grrrrr.
+ def tearDown(self):
+ endInteraction()
+ setSecurityPolicy(self.oldpolicy)
-class TestPersistentSecurityMap(TestSecurityMap):
+ def _getSecurityMap(self):
+ return SecurityMap()
- def testInterface(self):
- verifyClass(ISecurityMap, PersistentSecurityMap)
+ def test_addCell(self):
+ map = self._getSecurityMap()
+ self.assertEqual(getInteraction().invalidated, 0)
+ map.addCell(0, 0, 'aa')
+ self.assertEqual(getInteraction().invalidated, 1)
+ self.assertEqual(map._byrow[0][0], 'aa')
+ self.assertEqual(map._bycol[0][0], 'aa')
- # XXX test persistence...
+ map.addCell(1, 0, 'ba')
+ self.assertEqual(getInteraction().invalidated, 2)
+ self.assertEqual(map._byrow[1][0], 'ba')
+ self.assertEqual(map._bycol[0][1], 'ba')
+ map.addCell(5, 3, 'fd')
+ self.assertEqual(getInteraction().invalidated, 3)
+ self.assertEqual(map._byrow[5][3], 'fd')
+ self.assertEqual(map._bycol[3][5], 'fd')
+ def test_addCell_noninteger(self):
+ map = self._getSecurityMap()
+ map.addCell(0.3, 0.4, 'entry')
+ self.assertEqual(map._byrow[0.3][0.4], 'entry')
+ self.assertEqual(map._bycol[0.4][0.3], 'entry')
+
+ marker = object()
+ map.addCell('a', 'b', marker)
+ self.assertEqual(map._byrow['a']['b'], marker)
+ self.assertEqual(map._bycol['b']['a'], marker)
+
+ def test_delCell(self):
+ map = self._getSecurityMap()
+ self.assertEqual(getInteraction().invalidated, 0)
+ map._byrow[0] = {}
+ map._bycol[1] = {}
+ map._byrow[0][1] = 'aa'
+ map._bycol[1][0] = 'aa'
+ map.delCell(0, 1)
+ self.assertEqual(getInteraction().invalidated, 1)
+ self.assertEqual(map._byrow.get(0), None)
+ self.assertEqual(map._bycol.get(1), None)
+
+ def test_queryCell(self):
+ map = self._getSecurityMap()
+ map._byrow[0] = {}
+ map._bycol[1] = {}
+ map._byrow[0][1] = 'aa'
+ map._bycol[1][0] = 'aa'
+
+ marker = object()
+ self.assertEqual(map.queryCell(0, 1), 'aa')
+ self.assertEqual(map.queryCell(1, 0), None)
+ self.assertEqual(map.queryCell(1, 0, marker), marker)
+
+ def test_getCell(self):
+ map = self._getSecurityMap()
+ map._byrow[0] = {}
+ map._bycol[1] = {}
+ map._byrow[0][1] = 'aa'
+ map._bycol[1][0] = 'aa'
+
+ self.assertEqual(map.getCell(0, 1), 'aa')
+ self.assertRaises(KeyError, map.getCell, 1, 0)
+
+ def test_getRow(self):
+ map = self._getSecurityMap()
+ map._byrow[0] = {}
+ map._byrow[0][1] = 'ab'
+ map._byrow[0][2] = 'ac'
+ map._byrow[1] = {}
+ map._byrow[1][1] = 'bb'
+ map._bycol[1] = {}
+ map._bycol[1][0] = 'ab'
+ map._bycol[1][1] = 'bb'
+ map._bycol[2] = {}
+ map._bycol[2][0] = 'ac'
+
+ self.assertEqual(map.getRow(0), [(1, 'ab'), (2, 'ac')])
+ self.assertEqual(map.getRow(1), [(1, 'bb')])
+ self.assertEqual(map.getRow(2), [])
+
+ def test_getCol(self):
+ map = self._getSecurityMap()
+ map._byrow[0] = {}
+ map._byrow[0][1] = 'ab'
+ map._byrow[0][2] = 'ac'
+ map._byrow[1] = {}
+ map._byrow[1][1] = 'bb'
+ map._bycol[1] = {}
+ map._bycol[1][0] = 'ab'
+ map._bycol[1][1] = 'bb'
+ map._bycol[2] = {}
+ map._bycol[2][0] = 'ac'
+
+ self.assertEqual(map.getCol(1), [(0, 'ab'), (1, 'bb')])
+ self.assertEqual(map.getCol(2), [(0, 'ac')])
+ self.assertEqual(map.getCol(0), [])
+
+ def test_getAllCells(self):
+ map = self._getSecurityMap()
+ map._byrow[0] = {}
+ map._byrow[0][1] = 'ab'
+ map._byrow[0][2] = 'ac'
+ map._byrow[1] = {}
+ map._byrow[1][1] = 'bb'
+ map._bycol[1] = {}
+ map._bycol[1][0] = 'ab'
+ map._bycol[1][1] = 'bb'
+ map._bycol[2] = {}
+ map._bycol[2][0] = 'ac'
+
+ self.assertEqual(map.getCol(1), [(0, 'ab'), (1, 'bb')])
+ self.assertEqual(map.getCol(2), [(0, 'ac')])
+ self.assertEqual(map.getCol(0), [])
+
+
+class TestPersistentSecurityMap(TestSecurityMap):
+
+ def _getSecurityMap(self):
+ return PersistentSecurityMap()
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestSecurityMap),
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_zopepolicy.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_zopepolicy.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/tests/test_zopepolicy.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -1,4 +1,4 @@
-##############################################################################
+#############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
@@ -11,364 +11,60 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Tests the standard zope policy.
+"""Tests the zope policy.
$Id$
"""
-import unittest
-from zope.interface import implements
-from zope.interface.verify import verifyObject
-from zope.app import zapi
+import unittest
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.tests import placelesssetup, ztapi
+from zope.app.annotation.interfaces import IAnnotatable
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.annotation.interfaces import IAnnotations
from zope.app.annotation.attribute import AttributeAnnotations
-from zope.app.annotation.interfaces import IAttributeAnnotatable, IAnnotations
-from zope.app.security.principalregistry import principalRegistry, PrincipalBase
-from zope.app.security.interfaces import IPermission, IAuthenticationService
-from zope.app.security.permission import Permission
-from zope.app.servicenames import Authentication
-from zope.app.site.tests.placefulsetup import PlacefulSetup
-from zope.app.tests import ztapi
-
-from zope.app.securitypolicy.interfaces import IRole
-from zope.app.securitypolicy.interfaces import IRolePermissionManager
+from zope.app.securitypolicy.interfaces import IGrantInfo
from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
-
-from zope.app.securitypolicy.role import Role
-from zope.app.securitypolicy.zopepolicy import permissionsOfPrincipal
-from zope.app.securitypolicy.principalpermission \
- import principalPermissionManager
-from zope.app.securitypolicy.rolepermission import rolePermissionManager
-from zope.app.securitypolicy.principalrole import principalRoleManager
-from zope.app.securitypolicy.principalpermission \
- import AnnotationPrincipalPermissionManager
from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager
+from zope.app.securitypolicy.interfaces import IRolePermissionManager
+from zope.app.securitypolicy.principalpermission \
+ import AnnotationPrincipalPermissionManager
from zope.app.securitypolicy.principalrole \
import AnnotationPrincipalRoleManager
from zope.app.securitypolicy.rolepermission \
- import AnnotationRolePermissionManager
+ import AnnotationRolePermissionManager
+from zope.app.securitypolicy.grantinfo \
+ import AnnotationGrantInfo
+from zope.security.management import endInteraction
+def setUp():
+ placelesssetup.setUp()
+ endInteraction()
+ ztapi.provideAdapter(
+ IAttributeAnnotatable, IAnnotations,
+ AttributeAnnotations)
+ ztapi.provideAdapter(
+ IAnnotatable, IPrincipalPermissionManager,
+ AnnotationPrincipalPermissionManager)
+ ztapi.provideAdapter(
+ IAnnotatable, IPrincipalRoleManager,
+ AnnotationPrincipalRoleManager)
+ ztapi.provideAdapter(
+ IAnnotatable, IRolePermissionManager,
+ AnnotationRolePermissionManager)
+ ztapi.provideAdapter(
+ IAnnotatable, IGrantInfo,
+ AnnotationGrantInfo)
-class RequestStub:
- def __init__(self, principal, interaction=None):
- self.principal = principal
- self.interaction = interaction
+def tearDown():
+ placelesssetup.tearDown()
-class Interaction:
- def __init__(self, user):
- self.participations = [RequestStub(user, self)]
-
-class Unprotected:
- pass
-
-class Principal(PrincipalBase):
- pass
-
-
-def defineRole(id, title=None, description=None):
- role = Role(id, title, description)
- ztapi.provideUtility(IRole, role, name=role.id)
- return role
-
-def definePermission(id, title=None, description=None):
- perm = Permission(id, title, description)
- ztapi.provideUtility(IPermission, perm, name=perm.id)
- return perm
-
-
-class Test(PlacefulSetup, unittest.TestCase):
-
- def setUp(self):
- PlacefulSetup.setUp(self)
- services = zapi.getGlobalServices()
-
- services.defineService(Authentication, IAuthenticationService)
- services.provideService(Authentication, principalRegistry)
-
- ztapi.provideAdapter(
- IAttributeAnnotatable, IAnnotations,
- AttributeAnnotations)
-
- # set up some principals
- self.jim = principalRegistry.definePrincipal(
- 'jim', 'Jim', 'Jim Fulton',
- 'jim', '123')
-
- self.tim = principalRegistry.definePrincipal(
- 'tim', 'Tim', 'Tim Peters',
- 'tim', '456')
-
- self.unknown = principalRegistry.defineDefaultPrincipal('unknown',
- 'Unknown', 'Nothing is known about this principal')
-
- # set up some permissions
- self.read = definePermission('read', 'Read', 'Read something').id
-
- self.write = definePermission('write', 'Write', 'Write something').id
-
- self.create = definePermission('create', 'Create',
- 'Create something').id
-
- self.update = definePermission('update', 'Update',
- 'Update something').id
-
- # ... and some roles...
- defineRole("zope.Anonymous", "Everybody",
- "All users have this role implicitly")
-
- self.peon = defineRole('Peon', 'Site Peon').id
-
- self.manager = defineRole('Manager', 'Site Manager').id
-
- self.arole = defineRole('Another', 'Another Role').id
-
- # grant and deny some permissions to a principal
- principalPermissionManager.grantPermissionToPrincipal(
- self.create, self.jim.id)
- principalPermissionManager.denyPermissionToPrincipal(
- self.update, self.jim.id)
-
- # grant and deny some permissions to the roles
- rolePermissionManager.grantPermissionToRole(self.read, self.peon)
-
- rolePermissionManager.grantPermissionToRole(self.read, self.manager)
- rolePermissionManager.grantPermissionToRole(self.write, self.manager)
-
- # ... and assign roles to principals
- principalRoleManager.assignRoleToPrincipal(self.peon, self.jim.id)
- principalRoleManager.assignRoleToPrincipal(self.manager, self.tim.id)
-
- self.interaction = self._makeInteraction()
-
-
- def _makeInteraction(self):
- from zope.app.securitypolicy.zopepolicy import ZopeSecurityPolicy
- return ZopeSecurityPolicy()
-
-
- def __assertPermissions(self, user, expected, object=None):
- permissions = list(permissionsOfPrincipal(user, object))
- permissions.sort()
- self.assertEqual(permissions, expected)
-
- def testImport(self):
- from zope.app.securitypolicy.zopepolicy import ZopeSecurityPolicy
-
- def testInterfaces(self):
- from zope.security.interfaces import ISecurityPolicy
- from zope.app.securitypolicy.zopepolicy import ZopeSecurityPolicy
- verifyObject(ISecurityPolicy, ZopeSecurityPolicy)
-
- def testCreateInteraction(self):
- from zope.security.interfaces import IInteraction
- from zope.app.securitypolicy.zopepolicy import ZopeSecurityPolicy
- i1 = ZopeSecurityPolicy()
- verifyObject(IInteraction, i1)
- self.assertEquals(list(i1.participations), [])
-
- user = object()
- rq = RequestStub(user)
- i2 = ZopeSecurityPolicy(rq)
- verifyObject(IInteraction, i2)
- self.assertEquals(list(i2.participations), [rq])
-
- def testCheckerPublic(self):
- from zope.security.checker import CheckerPublic
- self.failUnless(self.interaction.checkPermission(CheckerPublic, None))
-
- def testGlobalCheckPermission(self):
- r = RequestStub(self.jim)
- self.interaction.add(r)
- self.failUnless(self.interaction.checkPermission(self.read, None))
- self.interaction.remove(r)
-
- r = RequestStub(self.tim)
- self.interaction.add(r)
- self.failUnless(self.interaction.checkPermission(self.read, None))
- self.failUnless(self.interaction.checkPermission(self.write, None))
- self.interaction.remove(r)
-
- r = RequestStub(self.unknown)
- self.interaction.add(r)
- self.failIf(self.interaction.checkPermission(self.read, None))
- self.failIf(self.interaction.checkPermission(self.write, None))
-
- self.failIf(self.interaction.checkPermission(self.read, None))
-
- self.__assertPermissions(self.jim, ['create', 'read'])
- self.__assertPermissions(self.tim, ['read', 'write'])
- self.__assertPermissions(self.unknown, [])
-
- rolePermissionManager.grantPermissionToRole(
- self.read, 'zope.Anonymous')
-
- self.failUnless(self.interaction.checkPermission(self.read, None))
- self.interaction.remove(r)
-
- self.__assertPermissions(self.unknown, ['read'])
-
- principalPermissionManager.grantPermissionToPrincipal(
- self.write, self.jim.id)
- r = RequestStub(self.jim)
- self.interaction.add(r)
- self.failUnless(self.interaction.checkPermission(self.write, None))
-
- self.__assertPermissions(self.jim, ['create', 'read', 'write'])
-
- def testPlaylessPrincipalRole(self):
- r = RequestStub(self.jim)
- self.interaction.add(r)
- self.failIf(self.interaction.checkPermission(self.write, None))
- principalRoleManager.assignRoleToPrincipal(
- self.manager, self.jim.id)
- self.failUnless(self.interaction.checkPermission(self.write, None))
- principalRoleManager.removeRoleFromPrincipal(
- self.manager, self.jim.id)
- self.failIf(self.interaction.checkPermission(self.write, None))
-
- def testPlayfulPrincipalRole(self):
- ztapi.provideAdapter(
- ITest,
- IPrincipalRoleManager, AnnotationPrincipalRoleManager)
-
- ob1 = TestClass()
- ob2 = TestClass(); ob2.__parent__ = ob1
- ob3 = TestClass(); ob3.__parent__ = ob2
-
- r = RequestStub(self.jim)
- self.interaction.add(r)
- self.failIf(self.interaction.checkPermission(self.write, ob3))
- AnnotationPrincipalRoleManager(ob3).assignRoleToPrincipal(
- self.manager, self.jim.id)
- self.failUnless(self.interaction.checkPermission(self.write, ob3))
- AnnotationPrincipalRoleManager(ob3).removeRoleFromPrincipal(
- self.manager, self.jim.id)
- self.failIf(self.interaction.checkPermission(self.write, ob3))
-
- def testPlayfulRolePermissions(self):
-
- ARPM = AnnotationRolePermissionManager
- ztapi.provideAdapter(ITest,
- IRolePermissionManager, ARPM)
- test = definePermission('test', 'Test', '')
- test = test.id
-
- ob1 = TestClass()
- ob2 = TestClass(); ob2.__parent__ = ob1
- ob3 = TestClass(); ob3.__parent__ = ob2
-
- r = RequestStub(self.tim)
- self.interaction.add(r)
- self.failIf(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.tim, ['read', 'write'], ob3)
-
- ARPM(ob2).grantPermissionToRole(test, self.manager)
- self.failUnless(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.tim, ['read', 'test', 'write'], ob3)
- self.interaction.remove(r)
-
- r = RequestStub(self.jim)
- self.interaction.add(r)
- self.failIf(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.jim, ['create', 'read'], ob3)
-
-
- ARPM(ob3).grantPermissionToRole(test, self.peon)
- self.failUnless(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.jim, ['create', 'read', 'test'], ob3)
-
-
-
- principalPermissionManager.denyPermissionToPrincipal(
- test, self.jim.id)
- self.failIf(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.jim, ['create', 'read'], ob3)
- self.interaction.remove(r)
-
- principalPermissionManager.unsetPermissionForPrincipal(
- test, self.jim.id)
-
- # Make sure multiple conflicting role permissions resolve correctly
- ARPM(ob2).grantPermissionToRole(test, 'zope.Anonymous')
- ARPM(ob2).grantPermissionToRole(test, self.arole)
- ARPM(ob3).denyPermissionToRole(test, self.peon)
-
- new = principalRegistry.definePrincipal('new', 'Newbie',
- 'Newbie User', 'new', '098')
- principalRoleManager.assignRoleToPrincipal(self.arole, new.id)
- r = RequestStub(new)
- self.interaction.add(r)
- self.failUnless(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(new, ['test'], ob3)
-
- principalRoleManager.assignRoleToPrincipal(self.peon, new.id)
- self.failIf(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(new, ['read'], ob3)
-
- def testPlayfulPrinciplePermissions(self):
- APPM = AnnotationPrincipalPermissionManager
- ztapi.provideAdapter(ITest,
- IPrincipalPermissionManager, APPM)
-
- ob1 = TestClass()
- ob2 = TestClass(); ob2.__parent__ = ob1
- ob3 = TestClass(); ob3.__parent__ = ob2
-
- test = definePermission('test', 'Test', '').id
-
- r = RequestStub(self.tim)
- self.interaction.add(r)
- self.failIf(self.interaction.checkPermission(test, ob3))
-
- self.__assertPermissions(self.tim, ['read', 'write'], ob3)
-
- APPM(ob2).grantPermissionToPrincipal(test, self.tim.id)
- self.failUnless(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.tim, ['read', 'test', 'write'], ob3)
-
- APPM(ob3).denyPermissionToPrincipal(test, self.tim.id)
- self.failIf(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.tim, ['read', 'write'], ob3)
- self.interaction.remove(r)
-
- r = RequestStub(self.jim)
- self.interaction.add(r)
- APPM(ob1).denyPermissionToPrincipal(test, self.jim.id)
- APPM(ob3).grantPermissionToPrincipal(test, self.jim.id)
- self.failUnless(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.jim, ['create', 'read', 'test'], ob3)
-
-
- APPM(ob3).unsetPermissionForPrincipal(test, self.jim.id)
- self.failIf(self.interaction.checkPermission(test, ob3))
- self.__assertPermissions(self.jim, ['create', 'read'], ob3)
- self.interaction.remove(r)
-
- # make sure placeless principal permissions override placeful ones
- r = RequestStub(self.tim)
- self.interaction.add(r)
- APPM(ob3).grantPermissionToPrincipal(test, self.tim.id)
- principalPermissionManager.denyPermissionToPrincipal(
- test, self.tim.id)
- self.failIf(self.interaction.checkPermission(test, ob3))
-
- self.__assertPermissions(self.tim, ['read', 'write'], ob3)
-
-
-class ITest(IAttributeAnnotatable):
- pass
-
-class TestClass:
- implements(ITest)
-
- __parent__ = None
-
- def __init__(self):
- self._roles = { 'test' : {} }
- self._permissions = { 'Manager' : {} , 'Peon' : {} }
-
def test_suite():
- loader=unittest.TestLoader()
- return loader.loadTestsFromTestCase(Test)
+ return unittest.TestSuite((
+ DocFileSuite('zopepolicy.txt',
+ package='zope.app.securitypolicy',
+ setUp=setUp, tearDown=tearDown),
+ ))
-if __name__=='__main__':
- unittest.TextTestRunner().run(test_suite())
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.py 2004-07-23 18:31:57 UTC (rev 26713)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.py 2004-07-23 18:42:15 UTC (rev 26714)
@@ -15,249 +15,268 @@
$Id$
"""
-from zope.security.checker import CheckerPublic
+
+import zope.interface
+
from zope.security.management import system_user
-import zope.security.simplepolicies
+from zope.security.simplepolicies import ParanoidSecurityPolicy
from zope.security.interfaces import ISecurityPolicy
+from zope.security.proxy import getProxiedObject
-from zope.app.location import LocationIterator
from zope.app.security.settings import Allow, Deny
-from zope.app.securitypolicy.interfaces import \
- IRolePermissionMap, IPrincipalPermissionMap, IPrincipalRoleMap
+
from zope.app.securitypolicy.principalpermission \
import principalPermissionManager
+globalPrincipalPermissionSetting = principalPermissionManager.getSetting
+
from zope.app.securitypolicy.rolepermission import rolePermissionManager
+globalRolesForPermission = rolePermissionManager.getRolesForPermission
+
from zope.app.securitypolicy.principalrole import principalRoleManager
+globalRolesForPrincipal = principalRoleManager.getRolesForPrincipal
-getPermissionsForPrincipal = \
- principalPermissionManager.getPermissionsForPrincipal
-getPermissionsForRole = rolePermissionManager.getPermissionsForRole
-getRolesForPrincipal = principalRoleManager.getRolesForPrincipal
+from zope.app.securitypolicy.interfaces import IRolePermissionMap
+from zope.app.securitypolicy.interfaces import IPrincipalPermissionMap
+from zope.app.securitypolicy.interfaces import IPrincipalRoleMap
+from zope.app.securitypolicy.interfaces import IGrantInfo
-globalContext = object()
+class CacheEntry:
+ pass
+
+class ZopeSecurityPolicy(ParanoidSecurityPolicy):
+ zope.interface.classProvides(ISecurityPolicy)
+ def __init__(self, *args, **kw):
+ ParanoidSecurityPolicy.__init__(self, *args, **kw)
+ self._cache = {}
-class ZopeSecurityPolicy(zope.security.simplepolicies.ParanoidSecurityPolicy):
- zope.interface.classProvides(ISecurityPolicy)
+ def invalidate_cache(self):
+ self._cache = {}
- def checkPermission(self, permission, object):
- if permission is CheckerPublic:
- return True
- # XXX We aren't really handling multiple principals yet
- assert len(self.participations) == 1 # XXX
- user = self.participations[0].principal
+ def cache(self, parent):
+ cache = self._cache.get(id(parent))
+ if cache:
+ cache = cache[0]
+ else:
+ cache = CacheEntry()
+ self._cache[id(parent)] = cache, parent
+ return cache
+
+ def cached_decision(self, parent, principal, permission):
+ cache = self.cache(parent)
+ try:
+ cache_decision = cache.decision
+ except AttributeError:
+ cache_decision = cache.decision = {}
- # mapping from principal to set of roles
- if user is system_user:
- return True
+ cache_decision_prin = cache_decision.get(principal)
+ if not cache_decision_prin:
+ cache_decision_prin = cache_decision[principal] = {}
+
+ try:
+ return cache_decision_prin[permission]
+ except KeyError:
+ pass
+
+ decision = self.cached_prinper(parent, principal, permission)
+ if decision is not None:
+ cache_decision_prin[permission] = decision
+ return decision
- roledict = {'zope.Anonymous': Allow}
- principals = {user.id : roledict}
+ roles = self.cached_roles(parent, permission)
+ if roles:
+ for role in self.cached_principal_roles(parent, principal):
+ if role in roles:
+ cache_decision_prin[permission] = decision = True
+ return decision
- role_permissions = {}
- remove = {}
+ cache_decision_prin[permission] = decision = False
+ return decision
+
+ def cached_prinper(self, parent, principal, permission):
+ cache = self.cache(parent)
+ try:
+ cache_prin = cache.prin
+ except AttributeError:
+ cache_prin = cache.prin = {}
- # Look for placeless grants first.
+ cache_prin_per = cache_prin.get(principal)
+ if not cache_prin_per:
+ cache_prin_per = cache_prin[principal] = {}
- # get placeless principal permissions
- for principal in principals:
- for principal_permission, setting in (
- getPermissionsForPrincipal(principal)):
- if principal_permission == permission:
- if setting is Deny:
- return False
- assert setting is Allow
- remove[principal] = True
+ try:
+ return cache_prin_per[permission]
+ except KeyError:
+ pass
- # Clean out removed principals
- if remove:
- for principal in remove:
- del principals[principal]
- if principals:
- # not done yet
- remove.clear()
- else:
- # we've eliminated all the principals
- return True
+ if parent is None:
+ prinper = globalPrincipalPermissionSetting(
+ permission, principal, None)
+ if prinper is not None:
+ prinper = prinper is Allow
+ cache_prin_per[permission] = prinper
+ return prinper
- # get placeless principal roles
- for principal in principals:
- roles = principals[principal]
- for role, setting in getRolesForPrincipal(principal):
- assert setting in (Allow, Deny)
- if role not in roles:
- roles[role] = setting
+ prinper = IPrincipalPermissionMap(parent, None)
+ if prinper is not None:
+ prinper = prinper.getSetting(permission, principal, None)
+ if prinper is not None:
+ prinper = prinper is Allow
+ cache_prin_per[permission] = prinper
+ return prinper
- for perm, role, setting in (
- rolePermissionManager.getRolesAndPermissions()):
- assert setting in (Allow, Deny)
- if role not in role_permissions:
- role_permissions[role] = {perm: setting}
- else:
- if perm not in role_permissions[role]:
- role_permissions[role][perm] = setting
+ parent = getProxiedObject(getattr(parent, '__parent__', None))
+ prinper = self.cached_prinper(parent, principal, permission)
+ cache_prin_per[permission] = prinper
+ return prinper
+
+ def cached_roles(self, parent, permission):
+ cache = self.cache(parent)
+ try:
+ cache_roles = cache.roles
+ except AttributeError:
+ cache_roles = cache.roles = {}
+ try:
+ return cache_roles[permission]
+ except KeyError:
+ pass
+
+ if parent is None:
+ roles = dict(
+ [(role, 1)
+ for (role, setting) in globalRolesForPermission(permission)
+ if setting is Allow
+ ]
+ )
+ cache_roles[permission] = roles
+ return roles
- # Get principal permissions based on roles
- for principal in principals:
- roles = principals[principal]
- for role, role_setting in roles.items():
- if role_setting is Deny:
- return False
- if role in role_permissions:
- if permission in role_permissions[role]:
- setting = role_permissions[role][permission]
- if setting is Deny:
- return False
- remove[principal] = True
+ roles = self.cached_roles(
+ getProxiedObject(getattr(parent, '__parent__', None)),
+ permission)
+ roleper = IRolePermissionMap(parent, None)
+ if roleper:
+ roles = roles.copy()
+ for role, setting in roleper.getRolesForPermission(permission):
+ if setting is Allow:
+ roles[role] = 1
+ elif role in roles:
+ del roles[role]
+ cache_roles[permission] = roles
+ return roles
- # Clean out removed principals
- if remove:
- for principal in remove:
- del principals[principal]
- if principals:
- # not done yet
- remove.clear()
- else:
- # we've eliminated all the principals
- return True
+ def cached_principal_roles(self, parent, principal):
+ cache = self.cache(parent)
+ try:
+ cache_principal_roles = cache.principal_roles
+ except AttributeError:
+ cache_principal_roles = cache.principal_roles = {}
+ try:
+ return cache_principal_roles[principal]
+ except KeyError:
+ pass
- # Look for placeful grants
- for place in LocationIterator(object):
+ if parent is None:
+ roles = dict(
+ [(role, 1)
+ for (role, setting) in globalRolesForPrincipal(principal)
+ if setting is Allow
+ ]
+ )
+ roles['zope.Anonymous'] = 1 # Everybody has Anonymous
+ cache_principal_roles[principal] = roles
+ return roles
+
+ roles = self.cached_principal_roles(
+ getProxiedObject(getattr(parent, '__parent__', None)),
+ principal)
+ prinrole = IPrincipalRoleMap(parent, None)
+ if prinrole:
+ roles = roles.copy()
+ for role, setting in prinrole.getRolesForPrincipal(principal):
+ if setting is Allow:
+ roles[role] = 1
+ elif role in roles:
+ del roles[role]
- # Copy specific principal permissions
- prinper = IPrincipalPermissionMap(place, None)
- if prinper is not None:
- for principal in principals:
- for principal_permission, setting in (
- prinper.getPermissionsForPrincipal(principal)):
- if principal_permission == permission:
- if setting is Deny:
- return False
+ cache_principal_roles[principal] = roles
+ return roles
+
- assert setting is Allow
- remove[principal] = True
+ def checkPermission(self, permission, object):
+ principals = {}
+ for participation in self.participations:
+ principal = participation.principal
+ if principal is system_user:
+ continue # always allow system_user
+ principals[principal.id] = 1
- # Clean out removed principals
- if remove:
- for principal in remove:
- del principals[principal]
- if principals:
- # not done yet
- remove.clear()
- else:
- # we've eliminated all the principals
- return True
+ if not principals:
+ return True
- # Collect principal roles
- prinrole = IPrincipalRoleMap(place, None)
- if prinrole is not None:
- for principal in principals:
- roles = principals[principal]
- for role, setting in (
- prinrole.getRolesForPrincipal(principal)):
- assert setting in (Allow, Deny)
- if role not in roles:
- roles[role] = setting
+ object = getProxiedObject(object)
+ parent = getProxiedObject(getattr(object, '__parent__', None))
- # Collect role permissions
- roleper = IRolePermissionMap(place, None)
- if roleper is not None:
- for perm, role, setting in roleper.getRolesAndPermissions():
- assert setting in (Allow, Deny)
- if role not in role_permissions:
- role_permissions[role] = {perm: setting}
- else:
- if perm not in role_permissions[role]:
- role_permissions[role][perm] = setting
-
- # Get principal permissions based on roles
+ grant_info = IGrantInfo(object, None)
+ if not grant_info:
+ # No local grants; just use cached decision for parent
for principal in principals:
- roles = principals[principal]
- for role, role_setting in roles.items():
- if role_setting is Deny:
- return False
- if role in role_permissions:
- if permission in role_permissions[role]:
- setting = role_permissions[role][permission]
- if setting is Deny:
- return False
- remove[principal] = True
+ if not self.cached_decision(parent, principal, permission):
+ return False
+ return True
- # Clean out removed principals
- if remove:
- for principal in remove:
+ # We need to combine local and parent info
+
+ # First, look for principal grants
+ for principal in principals.keys():
+ setting = grant_info.principalPermissionGrant(
+ principal, permission)
+ if setting is Deny:
+ return False
+ elif setting is Allow: # setting could be None
+ del principals[principal]
+ if not principals:
+ return True
+ continue
+
+ decision = self.cached_prinper(parent, principal, permission)
+ if decision is not None:
+ if decision:
del principals[principal]
- if principals:
- # not done yet
- remove.clear()
+ if not principals:
+ return True
else:
- # we've eliminated all the principals
- return True
+ return decision # False
- return False # deny by default
+ roles = self.cached_roles(parent, permission)
+ local_roles = grant_info.getRolesForPermission(permission)
+ if local_roles:
+ roles = roles.copy()
+ for role, setting in local_roles:
+ if setting is Allow:
+ roles[role] = 1
+ elif role in roles:
+ del roles[role]
+ for principal in principals.keys():
+ proles = self.cached_principal_roles(parent, principal).copy()
+ for role, setting in grant_info.getRolesForPrincipal(principal):
+ if setting is Allow:
+ if role in roles:
+ del principals[principal]
+ if not principals:
+ return True
+ break
+ elif role in proles:
+ del proles[role]
+ else:
+ for role in proles:
+ if role in roles:
+ del principals[principal]
+ if not principals:
+ return True
+ break
+
+ return False
-def permissionsOfPrincipal(principal, object):
- permissions = {}
-
- roles = {'zope.Anonymous': Allow}
- principalid = principal.id
-
- # Make two passes.
-
- # First, collect what we know about the principal:
-
-
- # get placeless principal permissions
- for permission, setting in getPermissionsForPrincipal(principalid):
- if permission not in permissions:
- permissions[permission] = setting
-
- # get placeless principal roles
- for role, setting in getRolesForPrincipal(principalid):
- if role not in roles:
- roles[role] = setting
-
- # get placeful principal permissions and roles
- for place in LocationIterator(object):
-
- # Copy specific principal permissions
- prinper = IPrincipalPermissionMap(place, None)
- if prinper is not None:
- for permission, setting in prinper.getPermissionsForPrincipal(
- principalid):
- if permission not in permissions:
- permissions[permission] = setting
-
- # Collect principal roles
- prinrole = IPrincipalRoleMap(place, None)
- if prinrole is not None:
- for role, setting in prinrole.getRolesForPrincipal(principalid):
- if role not in roles:
- roles[role] = setting
-
- # Second, update permissions using principal
-
- for perm, role, setting in (
- rolePermissionManager.getRolesAndPermissions()):
- if role in roles and perm not in permissions:
- permissions[perm] = setting
-
- for place in LocationIterator(object):
-
- # Collect role permissions
- roleper = IRolePermissionMap(place, None)
- if roleper is not None:
- for perm, role, setting in roleper.getRolesAndPermissions():
- if role in roles and perm not in permissions:
- permissions[perm] = setting
-
-
-
- result = [permission
- for permission in permissions
- if permissions[permission] is Allow]
-
- return result
-
Copied: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.txt (from rev 26668, Zope3/trunk/src/zope/app/securitypolicy/zopepolicy.txt)
Property changes on: Zope3/branches/ZopeX3-3.0/src/zope/app/securitypolicy/zopepolicy.txt
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Zope3-Checkins
mailing list