[Checkins] SVN: z3ext.security/tags/1.2.0/ egg 1.2.0

Nikolay Kim fafhrd at datacom.kz
Fri Mar 21 02:11:54 EDT 2008


Log message for revision 84813:
  egg 1.2.0

Changed:
  A   z3ext.security/tags/1.2.0/
  D   z3ext.security/tags/1.2.0/src/
  A   z3ext.security/tags/1.2.0/src/
  A   z3ext.security/tags/1.2.0/src/z3ext/security/README.txt
  A   z3ext.security/tags/1.2.0/src/z3ext/security/__init__.py
  A   z3ext.security/tags/1.2.0/src/z3ext/security/configure.zcml
  A   z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.py
  A   z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.txt
  A   z3ext.security/tags/1.2.0/src/z3ext/security/groups.py
  A   z3ext.security/tags/1.2.0/src/z3ext/security/interfaces.py
  A   z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.py
  A   z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.txt
  A   z3ext.security/tags/1.2.0/src/z3ext/security/tests.py
  A   z3ext.security/tags/1.2.0/src/z3ext/security/utils.py

-=-
Copied: z3ext.security/tags/1.2.0 (from rev 84812, z3ext.security/trunk)

Copied: z3ext.security/tags/1.2.0/src (from rev 84811, z3ext.security/trunk/src)

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/README.txt (from rev 84812, z3ext.security/trunk/src/z3ext/security/README.txt)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/README.txt	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/README.txt	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,11 @@
+==============
+z3ext.security
+==============
+
+This package provides security related features
+
+ - Extended Security Policy: securitypolicy.txt
+
+ - Extended Grant Information: grantinfo.txt
+
+ - Principal Groups infomration: groups.txt

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/__init__.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/__init__.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/__init__.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/__init__.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1 @@
+# This file is necessary to make this directory a package.

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/configure.zcml (from rev 84812, z3ext.security/trunk/src/z3ext/security/configure.zcml)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/configure.zcml	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/configure.zcml	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,35 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <!-- IPrincipalGroups adapter -->
+  <adapter
+     for="zope.security.interfaces.IPrincipal"
+     provides=".interfaces.IPrincipalGroups"
+     factory=".groups.PrincipalGroups" />
+
+  <!-- extended grant info -->
+  <adapter factory="z3ext.security.grantinfo.ExtendedGrantInfo" />
+
+  <class class=".grantinfo.ExtendedGrantInfo">
+    <allow interface=".interfaces.IExtendedGrantInfo" />
+  </class>
+
+  <!-- add security declaration for anonymous -->
+  <class class="zope.app.security.principalregistry.UnauthenticatedPrincipal">
+    <require
+       permission="zope.Public"
+       interface="zope.security.interfaces.IPrincipal" />
+  </class>
+
+  <!-- Registering documentation with API doc -->
+  <configure
+     xmlns:apidoc="http://namespaces.zope.org/apidoc"
+     xmlns:zcml="http://namespaces.zope.org/zcml"
+     zcml:condition="have apidoc">
+
+    <apidoc:bookchapter
+       id="z3ext"
+       title="z3ext packages" />
+
+  </configure>
+
+</configure>

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/grantinfo.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,104 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+""" IExtendedGrantInfo implmentation, extended version of IGrantInfo
+
+$Id$
+"""
+
+from zope import interface, component
+from zope.component import getAdapters
+from zope.security.proxy import removeSecurityProxy
+
+from zope.securitypolicy.interfaces import IPrincipalRoleMap
+from zope.securitypolicy.interfaces import IRolePermissionMap
+
+from zope.securitypolicy.principalrole import principalRoleManager
+globalPrincipalsForRole = principalRoleManager.getPrincipalsForRole
+
+from interfaces import IExtendedGrantInfo
+from securitypolicy import globalRolesForPrincipal, globalRolesForPermission
+
+
+class ExtendedGrantInfo(object):
+    component.adapts(interface.Interface)
+    interface.implements(IExtendedGrantInfo)
+
+    def __init__(self, context):
+        self.context = context
+
+    def getRolesForPermission(self, permission):
+        context = removeSecurityProxy(self.context)
+
+        roles = {}
+        for name, roleperm in getAdapters((context,), IRolePermissionMap):
+            for role, setting in roleperm.getRolesForPermission(permission):
+                if role not in roles:
+                    roles[role] = setting
+
+        parent = getattr(context, '__parent__', None)
+        if parent is None:
+            for name, setting in globalRolesForPermission(permission):
+                if name not in roles:
+                    roles[name] = setting
+        else:
+            info = IExtendedGrantInfo(parent)
+            for role, setting in info.getRolesForPermission(permission):
+                if role not in roles:
+                    roles[role] = setting
+
+        return roles.items()
+
+    def getRolesForPrincipal(self, principal):
+        context = removeSecurityProxy(self.context)
+
+        roles = {}
+        for name, prinrole in getAdapters((context,), IPrincipalRoleMap):
+            for role, setting in prinrole.getRolesForPrincipal(principal):
+                if role not in roles:
+                    roles[role] = setting
+
+        parent = getattr(context, '__parent__', None)
+        if parent is None:
+            for role, setting in globalRolesForPrincipal(principal):
+                if role not in roles:
+                    roles[role] = setting
+        else:
+            info = IExtendedGrantInfo(parent)
+            for role, setting in info.getRolesForPrincipal(principal):
+                if role not in roles:
+                    roles[role] = setting
+
+        return roles.items()
+
+    def getPrincipalsForRole(self, role):
+        context = removeSecurityProxy(self.context)
+
+        principals = {}
+        for name, prinrole in getAdapters((context,), IPrincipalRoleMap):
+            for principal, setting in prinrole.getPrincipalsForRole(role):
+                if principal not in principals:
+                    principals[principal] = setting
+
+        parent = getattr(context, '__parent__', None)
+        if parent is None:
+            for principal, setting in globalPrincipalsForRole(role):
+                if principal not in principals:
+                    principal[role] = setting
+        else:
+            info = IExtendedGrantInfo(parent)
+            for principal, setting in info.getPrincipalsForRole(role):
+                if principal not in principals:
+                    principals[principal] = setting
+
+        return principals.items()

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.txt (from rev 84812, z3ext.security/trunk/src/z3ext/security/grantinfo.txt)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.txt	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/grantinfo.txt	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,141 @@
+==================
+IExtendedGrantInfo
+==================
+
+IExtendedGrantInfo interface is extended version of IGrantInfo
+from zope/securitypolicy but it runs for each parent and
+uses all available IRolePermissionMap and IPrincipalRoleMap adapters
+for object.
+
+initialization:
+
+   >>> from zope import interface
+   >>> from zope.component import provideAdapter
+   >>> from zope.securitypolicy import interfaces
+   >>> from z3ext.security.grantinfo import ExtendedGrantInfo
+   >>> from z3ext.security.interfaces import IExtendedGrantInfo
+
+   >>> provideAdapter(ExtendedGrantInfo, (interface.Interface,), IExtendedGrantInfo)
+
+   >>> import zope.interface
+   >>> from zope.annotation.interfaces import IAttributeAnnotatable
+
+   >>> class IMyObject(zope.interface.Interface):
+   ...   pass
+
+   >>> class Ob:
+   ...    __parent__ = None
+   ...    zope.interface.implements(IAttributeAnnotatable, IMyObject)
+
+   >>> ob1 = Ob()
+   >>> ob2 = Ob()
+   >>> ob3 = Ob()
+   >>> ob4 = Ob()
+
+Let's build parents dependencies: ob1->ob2->ob3, ob1->ob4
+
+   >>> ob2.__parent__ = ob1
+   >>> ob3.__parent__ = ob2
+   >>> ob4.__parent__ = ob1
+
+   >>> grantinfo = IExtendedGrantInfo(ob3)
+   >>> IExtendedGrantInfo.providedBy(grantinfo)
+   True
+
+   >>> grantinfo.getRolesForPermission('P1')
+   []
+
+This is standard behaviour:
+
+   >>> roleper  = interfaces.IRolePermissionManager(ob3)
+   >>> roleper.grantPermissionToRole('P1', 'role1')
+
+   >>> grantinfo.getRolesForPermission('P1')
+   [('role1', PermissionSetting: Allow)]
+
+Now let's set permission in parent:
+
+   >>> roleper  = interfaces.IRolePermissionManager(ob2)
+   >>> roleper.grantPermissionToRole('P1', 'role2')
+
+   >>> grantinfo.getRolesForPermission('P1')
+   [('role1', PermissionSetting: Allow), ('role2', PermissionSetting: Allow)]
+
+   >>> roleper  = interfaces.IRolePermissionManager(ob1)
+   >>> roleper.grantPermissionToRole('P1', 'role3')
+
+   >>> grantinfo.getRolesForPermission('P1')
+   [('role1', PermissionSetting: Allow), ('role3', PermissionSetting: Allow), ('role2', PermissionSetting: Allow)]
+
+   >>> roleper.denyPermissionToRole('P1', 'role3')
+
+   >>> grantinfo.getRolesForPermission('P1')
+   [('role1', PermissionSetting: Allow), ('role3', PermissionSetting: Deny), ('role2', PermissionSetting: Allow)]
+
+But lower object permissions/role has more weight, now we 
+have role3 denied for P1 permission on ob1, we can allow permission 
+on ob2 so ob3 should have allow for P1 permission on role role3
+
+   >>> roleper  = interfaces.IRolePermissionManager(ob2)
+   >>> roleper.grantPermissionToRole('P1', 'role3')
+
+   >>> grantinfo.getRolesForPermission('P1')
+   [('role1', PermissionSetting: Allow), ('role3', PermissionSetting: Allow), ('role2', PermissionSetting: Allow)]
+
+   >>> grantinfo = IExtendedGrantInfo(ob4)
+   >>> grantinfo.getRolesForPermission('P1')
+   [('role3', PermissionSetting: Deny)]
+
+
+getRolesForPrincipal
+--------------------
+
+   >>> grantinfo = IExtendedGrantInfo(ob3)
+   >>> grantinfo.getRolesForPrincipal('bob')
+   []
+
+   >>> prinrole  = interfaces.IPrincipalRoleManager(ob3)
+   >>> prinrole.assignRoleToPrincipal('role1', 'bob')
+
+   >>> grantinfo.getRolesForPrincipal('bob')
+   [('role1', PermissionSetting: Allow)]
+
+   >>> prinrole  = interfaces.IPrincipalRoleManager(ob2)
+   >>> prinrole.assignRoleToPrincipal('role2', 'bob')
+
+   >>> grantinfo.getRolesForPrincipal('bob')
+   [('role1', PermissionSetting: Allow), ('role2', PermissionSetting: Allow)]
+
+   >>> prinrole  = interfaces.IPrincipalRoleManager(ob1)
+   >>> prinrole.assignRoleToPrincipal('role3', 'bob')
+
+   >>> grantinfo.getRolesForPrincipal('bob')
+   [('role1', PermissionSetting: Allow), ('role3', PermissionSetting: Allow), ('role2', PermissionSetting: Allow)]
+
+role3 role allowed for principal 'bob' on ob1, we can deny this role on object ob2
+and on ob3 role3 should be denied
+
+   >>> prinrole  = interfaces.IPrincipalRoleManager(ob2)
+   >>> prinrole.removeRoleFromPrincipal('role3', 'bob')
+
+   >>> grantinfo.getRolesForPrincipal('bob')
+   [('role1', PermissionSetting: Allow), ('role3', PermissionSetting: Deny), ('role2', PermissionSetting: Allow)]
+
+
+getPrincipalsForRole
+--------------------
+
+This is new method in extended version, it usefull when we need get all
+principals that have role, for example for cataloging.
+
+   >>> grantinfo = IExtendedGrantInfo(ob3)
+   >>> grantinfo.getPrincipalsForRole('role1')
+   [('bob', PermissionSetting: Allow)]
+
+We can get info about other principals with same role
+
+   >>> prinrole  = interfaces.IPrincipalRoleManager(ob1)
+   >>> prinrole.assignRoleToPrincipal('role1', 'bob1')
+
+   >>> grantinfo.getPrincipalsForRole('role1')
+   [('bob', PermissionSetting: Allow), ('bob1', PermissionSetting: Allow)]

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/groups.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/groups.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/groups.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/groups.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,64 @@
+##############################################################################
+#
+# Copyright (c) 2007 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 import interface
+from zope.component import getUtility
+from zope.security.proxy import removeSecurityProxy
+from zope.security.interfaces import IPrincipal, IGroup, IGroupAwarePrincipal
+from zope.app.security.interfaces import IAuthentication
+
+from interfaces import IPrincipalGroups
+
+
+class PrincipalGroups(object):
+    interface.implements(IPrincipalGroups)
+
+    _cached = None
+
+    def __init__(self, principal):
+        self.principal = removeSecurityProxy(principal)
+
+    def getGroups(self, type=None):
+        if type is None:
+            type = IPrincipal
+
+        principal = self.principal
+
+        if IGroupAwarePrincipal.providedBy(principal):
+            if principal.groups:
+                seen = set()
+                principals = getUtility(IAuthentication)
+
+                stack = [iter(principal.groups)]
+
+                if IGroup.providedBy(principal):
+                    stack.append(iter([principal.id]))
+
+                while stack:
+                    try:
+                        group_id = stack[-1].next()
+                    except StopIteration:
+                        stack.pop()
+                    else:
+                        if group_id not in seen:
+                            group = principals.getPrincipal(group_id)
+
+                            seen.add(group_id)
+                            stack.append(iter(group.groups))
+
+                            if type.providedBy(group):
+                                yield group

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/interfaces.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/interfaces.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/interfaces.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/interfaces.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,40 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+""" z3ext.security interfaces
+
+$Id$
+"""
+from zope import interface
+
+
+class IPrincipalGroups(interface.Interface):
+    """ principal groups """
+
+    principal = interface.Attribute('Principal')
+
+    def getGroups(type=None):
+        """ get principal groups """
+
+
+class IExtendedGrantInfo(interface.Interface):
+    """ similar to IGrantInfo but recursive """
+
+    def getRolesForPermission(permission):
+        """ roles with permission """
+
+    def getRolesForPrincipal(principal):
+        """ principal roles """
+
+    def getPrincipalsForRole(role_id):
+        """ Get the principals that have been granted a role. """

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/securitypolicy.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,202 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.component import getAdapters
+from zope.security.proxy import removeSecurityProxy
+from zope.app.security.settings import Allow
+
+from zope.securitypolicy.interfaces import IPrincipalRoleMap
+from zope.securitypolicy.interfaces import IRolePermissionMap
+from zope.securitypolicy.interfaces import IPrincipalPermissionMap
+
+from zope.securitypolicy.zopepolicy import ZopeSecurityPolicy
+
+from zope.securitypolicy.zopepolicy import SettingAsBoolean
+from zope.securitypolicy.zopepolicy import globalRolesForPrincipal
+from zope.securitypolicy.zopepolicy import globalRolesForPermission
+from zope.securitypolicy.zopepolicy import globalPrincipalPermissionSetting
+
+
+class CacheEntry(object):
+
+    prinper = None
+    roles_adapters = None
+    principal_roles_adapters = None
+
+    def __init__(self):
+        self.prin = {}
+        self.decision = {}
+        self.roles = {}
+        self.principal_roles = {}
+
+
+class SecurityPolicy(ZopeSecurityPolicy):
+
+    def cache(self, parent):
+        cache = self._cache
+
+        if parent in cache:
+            return cache[parent]
+        else:
+            cacheEntry = CacheEntry()
+            cache[parent] = cacheEntry
+            return cacheEntry
+
+    def cached_roles(self, parent, permission, _allow=Allow):
+        cache = self.cache(parent)
+        cache_roles = cache.roles
+        if permission in cache_roles:
+            return cache_roles[permission]
+
+        if parent is None:
+            roles = dict(
+                [(role, 1) for (role, setting) in globalRolesForPermission(permission)
+                 if setting is _allow])
+            cache_roles[permission] = roles
+            return roles
+
+        roles = self.cached_roles(
+            removeSecurityProxy(getattr(parent, '__parent__', None)), permission)
+
+        # cache adaters
+        rolepers = cache.roles_adapters
+        if rolepers is None:
+            rolepers = tuple(getAdapters((parent,), IRolePermissionMap))
+            cache.roles_adapters = rolepers
+
+        if rolepers:
+            roles = roles.copy()
+            for name, roleper in rolepers:
+                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
+
+    def cached_principal_roles(self, parent, principal, 
+                               SettingAsBoolean=SettingAsBoolean):
+        cache = self.cache(parent)
+        cache_principal_roles = cache.principal_roles
+        if principal in cache_principal_roles:
+            return cache_principal_roles[principal]
+
+        if parent is None:
+            roles = dict(
+                [(role, SettingAsBoolean[setting])
+                 for (role, setting) in globalRolesForPrincipal(principal)]
+                 )
+            roles['zope.Anonymous'] = True # Everybody has Anonymous
+            cache_principal_roles[principal] = roles
+            return roles
+
+        roles = self.cached_principal_roles(
+            removeSecurityProxy(getattr(parent, '__parent__', None)), principal)
+
+        roles = roles.copy()
+
+        # cache adaters
+        adapters = cache.principal_roles_adapters
+        if adapters is None:
+            adapters = tuple(getAdapters((parent,), IPrincipalRoleMap))
+            cache.principal_roles_adapters = adapters
+
+        for name, prinrole in adapters:
+            for role, setting in prinrole.getRolesForPrincipal(principal):
+                roles[role] = SettingAsBoolean[setting]
+
+        cache_principal_roles[principal] = roles
+        return roles
+
+        
+    def cached_prinper(self, parent, principal, groups, permission):
+        # Compute the permission, if any, for the principal.
+        cache = self.cache(parent)
+        cache_prin = cache.prin
+
+        if principal in cache_prin:
+            cache_prin_per = cache_prin[principal]
+        else:
+            cache_prin_per = cache_prin[principal] = {}
+        
+        if permission in cache_prin_per:
+            return cache_prin_per[permission]
+
+        if parent is None:
+            prinper = SettingAsBoolean[
+                globalPrincipalPermissionSetting(permission, principal, None)
+                ]
+            cache_prin_per[permission] = prinper
+            return prinper
+
+        prinper = cache.prinper
+        if prinper is None:
+            cache.prinper = prinper = IPrincipalPermissionMap(parent, None)
+
+        if prinper is not None:
+            prinper = SettingAsBoolean[
+                prinper.getSetting(permission, principal, None)
+                ]
+            if prinper is not None:
+                cache_prin_per[permission] = prinper
+                return prinper
+
+        parent = removeSecurityProxy(getattr(parent, '__parent__', None))
+        prinper = self.cached_prinper(parent, principal, groups, permission)
+        cache_prin_per[permission] = prinper
+        return prinper
+
+    def cached_decision(self, parent, principal, groups, permission):
+        # Return the decision for a principal and permission
+        cache = self.cache(parent)
+        cache_decision = cache.decision
+
+        if principal in cache_decision:
+            cache_decision_prin = cache_decision[principal]
+        else:
+            cache_decision_prin = cache_decision[principal] = {}
+
+        if permission in cache_decision_prin:
+            return cache_decision_prin[permission]
+
+        # cache_decision_prin[permission] is the cached decision for a
+        # principal and permission.
+            
+        decision = self.cached_prinper(parent, principal, groups, permission)
+        if (decision is None) and groups:
+            decision = self._group_based_cashed_prinper(
+                parent, principal, groups, permission)
+
+        if decision is not None:
+            cache_decision_prin[permission] = decision
+            return decision
+
+        roles = self.cached_roles(parent, permission)
+        if roles:
+            prin_roles = self.cached_principal_roles(parent, principal)
+            if groups:
+                prin_roles = self.cached_principal_roles_w_groups(
+                    parent, principal, groups, prin_roles)
+            for role, setting in prin_roles.items():
+                if setting and (role in roles):
+                    cache_decision_prin[permission] = decision = True
+                    return decision
+
+        cache_decision_prin[permission] = decision = False
+        return decision

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.txt (from rev 84812, z3ext.security/trunk/src/z3ext/security/securitypolicy.txt)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.txt	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/securitypolicy.txt	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,149 @@
+=============================
+Extended Zope Security Policy
+=============================
+
+This package implements a extended version of zope.securitypolicy.
+Main difference:
+
+  - for permissions to roles mapping we use IRolePermissionManager interface
+
+  - for roles to permissions mapping we try find all IPrincipalRoleMap 
+    adapters, including named adapters, extended security policy 
+    allow dynmiclly calculate roles for principal
+
+Everything else is standard zope3 implementation. For standard security policy
+documentation check zope/securitypolicy/zopepolicy.txt file.
+Most of this code from zopepolicy.txt file because in general this security
+policy only extended version of standard version.
+
+
+   >>> import zope.interface
+   >>> from zope.annotation.interfaces import IAttributeAnnotatable
+
+   >>> class IMyObject(zope.interface.Interface):
+   ...   pass
+
+   >>> class Ob:
+   ...    __parent__ = None
+   ...    zope.interface.implements(IAttributeAnnotatable, IMyObject)
+
+   >>> ob = Ob()
+
+   >>> class Principal:
+   ...     def __init__(self, id):
+   ...         self.id = id
+   ...         self.groups = []
+
+   >>> principal = Principal('bob')
+
+   >>> class Participation:
+   ...     interaction = None
+
+   >>> from z3ext.security.securitypolicy import SecurityPolicy
+
+   >>> import zope.security.management
+   >>> oldpolicy = zope.security.management.setSecurityPolicy(SecurityPolicy)
+
+Let's create interaction:
+
+   >>> participation = Participation()
+   >>> participation.principal = principal
+   >>> zope.security.management.endInteraction()
+   >>> zope.security.management.newInteraction(participation)
+   >>> interaction = zope.security.management.getInteraction()
+
+   >>> interaction.checkPermission('P1', ob)
+   False
+
+Let's work with roles
+
+   >>> from zope.securitypolicy import interfaces
+
+   >>> interaction.checkPermission('P1', ob)
+   False
+
+We will use 'content.Owner' role, we need give permission to role:
+
+   >>> roleper  = interfaces.IRolePermissionManager(ob)
+   >>> roleper.grantPermissionToRole('P1', 'content.Owner')
+   
+Right now 'bob' principal doesn't have 'content.Owner' role on 'ob' object 
+with standard policy we should use IPrincipalRoleManager adapter to
+give ''content.Owner' role to principal. With extended version we can define
+named adapter. Here example that implemen owner roles that doesn't 
+depends on object annotations:
+
+Let's use 'ob' object attribute to define owner of object:
+
+   >>> ob.owner = 'bob'
+
+Now we need custom IPrincipalRoleMap:
+
+   >>> from zope.app.security.settings import Allow, Deny
+
+   >>> class OwnerRolesMap(object):
+   ...   zope.interface.implements(interfaces.IPrincipalRoleMap)
+   ...
+   ...   def __init__(self, context):
+   ...      self.context = context
+   ...
+   ...   def getRolesForPrincipal(self, principal_id):
+   ...      if getattr(self.context, 'owner', '') == principal_id:
+   ...         return (('content.Owner', Allow),)
+   ...      return (('content.Owner', Deny),)
+
+For testing implemented only getRolesForPrincipal method, but in many cases we 
+need implement all methods.
+
+Now we need register named adapter 
+
+   >>> from zope.component import provideAdapter
+   >>> provideAdapter(OwnerRolesMap, (IMyObject,), \
+   ...      interfaces.IPrincipalRoleMap, name='ownership')
+   >>> interaction.invalidate_cache()
+
+So 'bob' principal should get 'content.Owner' role on 'ob'
+
+   >>> interaction.checkPermission('P1', ob)
+   True
+
+For better 'Ownership' implementation check z3ext.ownership package. 
+
+For futher testing remove permission from role:
+
+   >>> roleper.unsetPermissionFromRole('P1', 'content.Owner')
+
+   >>> interaction.checkPermission('P1', ob)
+   False
+
+With extended security policy we can supply custom IRolePermissionManager 
+implementation for object:
+
+   >>> class RolePermissionMap(object):
+   ...   zope.interface.implements(interfaces.IRolePermissionMap)
+   ...
+   ...   def __init__(self, context):
+   ...      self.context = context
+   ...   
+   ...   def getRolesForPermission(self, permission_id):
+   ...     if permission_id == 'P2':
+   ...        return (('content.Owner', Allow), ('content.Owner1', Deny))
+   ...     elif permission_id == 'P3':
+   ...        return (('content.Owner1', Allow), ('content.Owner', Deny))
+   ...     return ()
+
+   >>> provideAdapter(RolePermissionMap, (IMyObject,), \
+   ...      interfaces.IRolePermissionMap, name='custom')
+   >>> interaction.invalidate_cache()
+
+   >>> interaction.checkPermission('P2', ob)
+   True
+
+   >>> interaction.checkPermission('P3', ob)
+   False
+
+   >>> prinrole = interfaces.IPrincipalRoleManager(ob)
+   >>> prinrole.assignRoleToPrincipal('content.Owner1', 'bob')
+
+   >>> interaction.checkPermission('P3', ob)
+   True

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/tests.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/tests.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/tests.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/tests.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,43 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.
+#
+##############################################################################
+""" z3ext.security tests
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import unittest, doctest
+from zope import interface, schema
+from zope.app.testing import setup, ztapi
+from zope.security.management import endInteraction
+from zope.securitypolicy.tests import test_zopepolicy
+from z3ext.security.grantinfo import ExtendedGrantInfo
+from z3ext.security.interfaces import IExtendedGrantInfo
+
+
+def setUp(test):
+    test_zopepolicy.setUp(test)
+    ztapi.provideAdapter(interface.Interface, IExtendedGrantInfo, ExtendedGrantInfo)
+
+def tearDown(test):
+    setup.placelessTearDown()
+
+
+def test_suite():
+    return unittest.TestSuite((
+            doctest.DocFileSuite(
+                'grantinfo.txt',setUp=setUp, tearDown=tearDown),
+            doctest.DocFileSuite(
+                'securitypolicy.txt',setUp=setUp, tearDown=tearDown),
+            ))

Copied: z3ext.security/tags/1.2.0/src/z3ext/security/utils.py (from rev 84812, z3ext.security/trunk/src/z3ext/security/utils.py)
===================================================================
--- z3ext.security/tags/1.2.0/src/z3ext/security/utils.py	                        (rev 0)
+++ z3ext.security/tags/1.2.0/src/z3ext/security/utils.py	2008-03-21 06:11:53 UTC (rev 84813)
@@ -0,0 +1,36 @@
+##############################################################################
+#
+# Copyright (c) 2007 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.component import getUtility
+from zope.security.management import queryInteraction
+from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
+
+
+def getPrincipal(id=None):
+    """ get current interaction principal """
+    if id is None:
+        interaction = queryInteraction()
+
+        if interaction is not None:
+            for participation in interaction.participations:
+                if participation.principal is not None:
+                    return participation.principal
+    else:
+        try:
+            return getUtility(IAuthentication).getPrincipal(id)
+        except PrincipalLookupError:
+            return None



More information about the Checkins mailing list