[Zope3-checkins] CVS: Zope3/src/zope/app/securitypolicy - __init__.py:1.1 configure.zcml:1.1 interfaces.py:1.1 meta.zcml:1.1 metaconfigure.py:1.1 metadirectives.py:1.1 permissionroles.py:1.1 principalpermission.py:1.1 principalrole.py:1.1 role.py:1.1 rolepermission.py:1.1 roleregistry.py:1.1 securitymap.py:1.1 zopepolicy.py:1.1

Philipp von Weitershausen philikon at philikon.de
Fri Feb 27 07:46:32 EST 2004


Update of /cvs-repository/Zope3/src/zope/app/securitypolicy
In directory cvs.zope.org:/tmp/cvs-serv6059/app/securitypolicy

Added Files:
	__init__.py configure.zcml interfaces.py meta.zcml 
	metaconfigure.py metadirectives.py permissionroles.py 
	principalpermission.py principalrole.py role.py 
	rolepermission.py roleregistry.py securitymap.py zopepolicy.py 
Log Message:
Moved the securitypolicy package from zope.products to zope.app.


=== Added File Zope3/src/zope/app/securitypolicy/__init__.py ===
#
# This file is necessary to make this directory a package.


=== Added File Zope3/src/zope/app/securitypolicy/configure.zcml ===
<configure xmlns="http://namespaces.zope.org/zope">

  <!-- Module aliases for users of persistent objects moved during
       the course of refactoring -->

  <modulealias module=".securitymap"
               alias="zope.app.security.grants.securitymap"/>

  <modulealias module=".role"
               alias="zope.app.services.role" />

  <modulealias module="zope.app.securitypolicy"
               alias="zope.products.securitypolicy" />




  <include file="meta.zcml"/>

  <content class=".permissionroles.PermissionRoles">
    <require permission="zope.Security"
             attributes="roles rolesInfo"
             interface=".interfaces.IRegisteredObject" />
  </content>

  <content class=".rolepermission.RolePermissions">
    <require permission="zope.Security"
             attributes="permissions permissionsInfo"
             interface=".interfaces.IRegisteredObject" />
  </content>

  <adapter factory=".rolepermission.AnnotationRolePermissionManager"
           provides=".interfaces.IRolePermissionManager"
           for="zope.app.interfaces.annotation.IAnnotatable" />

  <adapter factory=".principalrole.AnnotationPrincipalRoleManager"
           provides=".interfaces.IPrincipalRoleManager"
           for="zope.app.interfaces.annotation.IAnnotatable" />

  <adapter factory=".principalpermission.AnnotationPrincipalPermissionManager"
           provides=".interfaces.IPrincipalPermissionManager"
           for="zope.app.interfaces.annotation.IAnnotatable" />

  <serviceType id="Roles"
               interface=".interfaces.IRoleService" />

  <service serviceType="Roles"
           component=".roleregistry.roleRegistry" />

  <!-- protect Roles and Permissions -->
  <content class=".roleregistry.Role">
    <allow interface=".interfaces.IRegisteredObject" />
  </content>

  <!-- XXX (this came out of services/configure.zcml) Role Templates -->

  <content class=".role.RoleService">
    <factory id="RoleService"
             permission="zope.ManageServices"
             />
    <require permission="zope.Security"
             interface=".interfaces.IRoleService"
             />
    <require permission="zope.ManageServices"
             interface="zope.app.interfaces.container.IContainer"
             />
  </content>

  <content class=".role.Role">
    <factory />
    <require permission="zope.Security"
             interface=".interfaces.IRole"
             />
  </content>


  <securityPolicy component=".zopepolicy.zopeSecurityPolicy"
                  />

  <include package=".browser"/>


  <configure i18n_domain="zope">
    <role id="zope.Manager" title="Site Manager" />
    <role id="zope.Member" title="Site Member" />
  </configure>

  <!-- Remove the following directive if you don't want public access -->
  <grant permission="zope.View" role="zope.Anonymous" />

  <grant permission="zope.View"              role="zope.Manager" />
  <grant permission="zope.ManageContent"     role="zope.Manager" />
  <grant permission="zope.Security"          role="zope.Manager" />
  <grant permission="zope.ManageCode"        role="zope.Manager" />
  <grant permission="zope.ManageServices"    role="zope.Manager" />
  <grant permission="zope.ManageApplication" role="zope.Manager" />
  <grant permission="zope.ManageBindings"    role="zope.Manager" />
  <grant permission="zope.SendMail"          role="zope.Manager" />

  <!-- Grant Manager all necessary Permissions for using Workflows -->
  <grant permission="zope.workflow.ManageProcessDefinitions"
         role="zope.Manager" />
  <grant permission="zope.workflow.CreateProcessInstances"
         role="zope.Manager" />
  <grant permission="zope.workflow.UseProcessInstances"
         role="zope.Manager" />

</configure>



=== Added File Zope3/src/zope/app/securitypolicy/interfaces.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
"""Security map to hold matrix-like relationships.

$Id: interfaces.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""
from zope.interface import Interface
from zope.app.interfaces.security import IRegisteredObject

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(IRegisteredObject):
    """A role object."""

class IRoleService(Interface):
    """Define roles

     'IRoleService' objects are used to implement role-definition
     services. Because they implement services, they are expected to
     collaborate with services in other contexts. Client code doesn't
     sarch a context and call multiple services. Instead, client code
     will call the most specific service in a place and rely on the
     service to delegate to other services as necessary.

     The interface doesn't include methods for data
     management. Services may use external data and not allow
     management in Zope. Simularly, the data to be managed may vary
     with different implementations of a service.
     """

    def getRole(rid):
        """Return an 'IRole' object for the given role id."""


    def getRoles():
        """Return a sequence of the roles (IRole objects)
        defined in the place containing the service."""




class IPrincipalRoleMap(Interface):
    """Mappings between principals and roles."""

    def getPrincipalsForRole(role_id):
        """Get the principals that have been granted a role.

        Return the list of (principal id, setting) who have been assigned or
        removed from a role.

        If no principals have been assigned this role,
        then the empty list is returned.
        """

    def getRolesForPrincipal(principal_id):
        """Get the roles granted to a principal.

        Return the list of (role id, setting) assigned or removed from
        this principal.

        If no roles have been assigned to
        this principal, then the empty list is returned.
        """

    def getSetting(role_id, principal_id):
        """Return the setting for this principal, role combination
        """

    def getPrincipalsAndRoles():
        """Get all settings.

        Return all the principal/role combinations along with the
        setting for each combination as a sequence of tuples with the
        role id, principal id, and setting, in that order.
        """


class IPrincipalRoleManager(IPrincipalRoleMap):
    """Management interface for mappings between principals and roles."""

    def assignRoleToPrincipal(role_id, principal_id):
        """Assign the role to the principal."""

    def removeRoleFromPrincipal(role_id, principal_id):
        """Remove a role from the principal."""

    def unsetRoleForPrincipal(role_id, principal_id):
        """Unset the role for the principal."""


class IRolePermissionMap(Interface):
    """Mappings between roles and permissions."""

    def getPermissionsForRole(role_id):
        """Get the premissions granted to a role.

        Return a sequence of (permission id, setting) tuples for the given
        role.

        If no permissions have been granted to this
        role, then the empty list is returned.
        """

    def getRolesForPermission(permission_id):
        """Get the roles that have a permission.

        Return a sequence of (role id, setting) tuples for the given
        permission.

        If no roles have been granted this permission, then the empty list is
        returned.
        """

    def getSetting(permission_id, role_id):
        """Return the setting for the given permission id and role id

        If there is no setting, Unset is returned
        """

    def getRolesAndPermissions():
        """Return a sequence of (permission_id, role_id, setting) here.

        The settings are returned as a sequence of permission, role,
        setting tuples.

        If no principal/role assertions have been made here, then the empty
        list is returned.
        """


class IRolePermissionManager(IRolePermissionMap):
    """Management interface for mappings between roles and permissions."""

    def grantPermissionToRole(permission_id, role_id):
        """Bind the permission to the role.
        """

    def denyPermissionToRole(permission_id, role_id):
        """Deny the permission to the role
        """

    def unsetPermissionFromRole(permission_id, role_id):
        """Clear the setting of the permission to the role.
        """


class IPrincipalPermissionMap(Interface):
    """Mappings between principals and permissions."""

    def getPrincipalsForPermission(permission_id):
        """Get the principas that have a permission.

        Return the list of (principal_id, setting) tuples that describe
        security assertions for this permission.

        If no principals have been set for this permission, then the empty
        list is returned.
        """

    def getPermissionsForPrincipal(principal_id):
        """Get the permissions granted to a principal.

        Return the list of (permission, setting) tuples that describe
        security assertions for this principal.

        If no permissions have been set for this principal, then the empty
        list is returned.
        """

    def getSetting(permission_id, principal_id):
        """Get the setting for a permission and principal.

        Get the setting (Allow/Deny/Unset) for a given permission and
        principal.
        """

    def getPrincipalsAndPermissions():
        """Get all principal permission settings.

        Get the principal security assertions here in the form
        of a list of three tuple containing
        (permission id, principal id, setting)
        """


class IPrincipalPermissionManager(IPrincipalPermissionMap):
    """Management interface for mappings between principals and permissions."""

    def grantPermissionToPrincipal(permission_id, principal_id):
        """Assert that the permission is allowed for the principal.
        """

    def denyPermissionToPrincipal(permission_id, principal_id):
        """Assert that the permission is denied to the principal.
        """

    def unsetPermissionForPrincipal(permission_id, principal_id):
        """Remove the permission (either denied or allowed) from the
        principal.
        """


=== Added File Zope3/src/zope/app/securitypolicy/meta.zcml ===
<configure xmlns="http://namespaces.zope.org/zope"
           xmlns:meta="http://namespaces.zope.org/meta">

  <meta:directive namespace="http://namespaces.zope.org/zope"
                  name="grant"
                  schema=".metadirectives.IGrantDirective"
                  handler=".metaconfigure.grant" />

  <meta:directive namespace="http://namespaces.zope.org/zope"
                  name="role"
                  schema=".metadirectives.IDefineRoleDirective"
                  handler=".metaconfigure.defineRole" />

</configure>


=== Added File Zope3/src/zope/app/securitypolicy/metaconfigure.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
""" Register security related configuration directives.

$Id: metaconfigure.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""
from zope.configuration.exceptions import ConfigurationError

from zope.app.securitypolicy.roleregistry import roleRegistry as role_reg
from zope.app.securitypolicy.rolepermission \
     import rolePermissionManager as role_perm_mgr
from zope.app.securitypolicy.principalpermission \
     import principalPermissionManager as principal_perm_mgr
from zope.app.securitypolicy.principalrole \
     import principalRoleManager as principal_role_mgr


def grant(_context, principal=None, role=None, permission=None):
    if (  (principal is not None)
        + (role is not None)
        + (permission is not None)
          ) != 2:
        raise ConfigurationError(
            "Exactly two of the principal, role, and permission attributes "
            "must be specified")

    if principal:
        if role:
            _context.action(
                discriminator = ('grantRoleToPrincipal', role, principal),
                callable = principal_role_mgr.assignRoleToPrincipal,
                args = (role, principal) )

        if permission:
            _context.action(
                discriminator = ('grantPermissionToPrincipal',
                                 permission,
                                 principal),
                callable = principal_perm_mgr.grantPermissionToPrincipal,
                args = (permission, principal) )
    else:
        _context.action(
            discriminator = ('grantPermissionToRole', permission, role),
            callable = role_perm_mgr.grantPermissionToRole,
            args = (permission, role) )

def defineRole(_context, id, title, description=''):
    _context.action(
            discriminator = ('defineRole', id),
            callable = role_reg.defineRole,
            args = (id, title, description) )



=== Added File Zope3/src/zope/app/securitypolicy/metadirectives.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
"""Grant Directive Schema

$Id: metadirectives.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""
from zope.interface import Interface
from zope.schema import Id 
from zope.app.security.registries.metadirectives import IBaseDefineDirective

class IGrantDirective(Interface):
    """Grant Permissions to roles and principals and roles to principals."""

    principal = Id(
        title=u"Principal",
        description=u"Specifies the Principal to be mapped.",
        required=False)

    permission = Id(
        title=u"Permission",
        description=u"Specifies the Permission to be mapped.",
        required=False)

    role = Id(
        title=u"Role",
        description=u"Specifies the Role to be mapped.",
        required=False)

class IDefineRoleDirective(IBaseDefineDirective):
    """Define a new role."""



=== Added File Zope3/src/zope/app/securitypolicy/permissionroles.py ===
##############################################################################
#
# 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.0 (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: permissionroles.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""

from zope.component import getAdapter
from zope.interface import implements

from zope.app.interfaces.security import IPermission
from zope.app.security.settings import Unset
from zope.app.securitypolicy.interfaces import IRolePermissionManager

class PermissionRoles:

    implements(IPermission)

    def __init__(self, permission, context, roles):
        self._permission = permission
        self._context    = context
        self._roles      = roles

    def getId(self):
        return self._permission.getId()

    def getTitle(self):
        return self._permission.getTitle()

    def getDescription(self):
        return self._permission.getDescription()

    def roleSettings(self):
        """
        Returns the list of setting names of each role for this permission.
        """
        prm = getAdapter(self._context, IRolePermissionManager)
        proles = prm.getRolesForPermission(self._permission.getId())
        settings = {}
        for role, setting in proles:
            settings[role] = setting.getName()
        nosetting = Unset.getName()
        return [settings.get(role.getId(), nosetting) for role in self._roles]


=== Added File Zope3/src/zope/app/securitypolicy/principalpermission.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
"""Mappings between principals and permissions, stored in an object locally.

$Id: principalpermission.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""

from zope.component import getAdapter

from zope.interface import implements
from zope.app.interfaces.annotation import IAnnotations
from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager

from zope.app.security.settings import Allow, Deny, Unset
from zope.app.security.principal import checkPrincipal
from zope.app.security.permission import checkPermission

from zope.app.securitypolicy.securitymap import SecurityMap

annotation_key = 'zopel.app.security.AnnotationPrincipalPermissionManager'

class AnnotationPrincipalPermissionManager:
    """Mappings between principals and permissions."""

    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

    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

    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

    def getPrincipalsForPermission(self, permission_id):
        ''' See the interface IPrincipalPermissionManager '''
        pp = self._getPrincipalPermissions()
        if pp:
            return pp.getRow(permission_id)
        return []

    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 = getAdapter(context, IAnnotations)
        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."""

    implements(IPrincipalPermissionManager)

    def grantPermissionToPrincipal(self, permission_id, principal_id,
                                   check=True):
        ''' See the interface IPrincipalPermissionManager '''

        if check:
            checkPermission(None, permission_id)
            checkPrincipal(None, principal_id)

        self.addCell(permission_id, principal_id, Allow)

    def denyPermissionToPrincipal(self, permission_id, principal_id,
                                  check=True):
        ''' See the interface IPrincipalPermissionManager '''

        if check:
            checkPermission(None, permission_id)
            checkPrincipal(None, principal_id)

        self.addCell(permission_id, principal_id, Deny)

    def unsetPermissionForPrincipal(self, permission_id, principal_id):
        ''' See the interface IPrincipalPermissionManager '''

        # Don't check validity intentionally.
        # After all, we certianly want to unset invalid ids.

        self.delCell(permission_id, principal_id)

    def getPrincipalsForPermission(self, permission_id):
        ''' See the interface IPrincipalPermissionManager '''
        return self.getRow(permission_id)

    def getPermissionsForPrincipal(self, principal_id):
        ''' See the interface IPrincipalPermissionManager '''
        return self.getCol(principal_id)

    def getSetting(self, permission_id, principal_id):
        ''' See the interface IPrincipalPermissionManager '''
        return self.getCell(permission_id, principal_id, default=Unset)

    def getPrincipalsAndPermissions(self):
        ''' See the interface IPrincipalPermissionManager '''
        return self.getAllCells()


# Permissions are our rows, and principals are our columns
principalPermissionManager = PrincipalPermissionManager()


# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(principalPermissionManager._clear)
del addCleanUp


=== Added File Zope3/src/zope/app/securitypolicy/principalrole.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
"""Mappings between principals and roles, stored in an object locally."""

__metaclass__ = type

from zope.component import getAdapter
from zope.interface import implements
from zope.security.proxy import trustedRemoveSecurityProxy

from zope.app.interfaces.annotation 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.security.principal import checkPrincipal
from zope.app.securitypolicy.role import checkRole

annotation_key = 'zope.app.security.AnnotationPrincipalRoleManager'

class AnnotationPrincipalRoleManager:
    """Mappings between principals and roles."""

    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)

    def removeRoleFromPrincipal(self, role_id, principal_id):
        ''' See the interface IPrincipalRoleManager '''
        pp = self._getPrincipalRoles(create=1)
        pp.addCell(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 []

    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

    def getPrincipalsAndRoles(self):
        ''' See the interface IPrincipalRoleManager '''
        pp = self._getPrincipalRoles()
        if pp:
            return pp.getAllCells()
        return []

    # Implementation helpers

    def _getPrincipalRoles(self, create=0):
        """ Get the principal role map stored in the context, optionally
            creating one if necessary """
        annotations = getAdapter(self._context, IAnnotations)
        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)

    def assignRoleToPrincipal(self, role_id, principal_id, check=True):
        ''' See the interface IPrincipalRoleManager '''

        if check:
            checkPrincipal(None, principal_id)
            checkRole(None, role_id)

        self.addCell(role_id, principal_id, Allow)

    def removeRoleFromPrincipal(self, role_id, principal_id, check=True):
        ''' See the interface IPrincipalRoleManager '''

        if check:
            checkPrincipal(None, principal_id)
            checkRole(None, role_id)

        self.addCell(role_id, principal_id, Deny)

    def unsetRoleForPrincipal(self, role_id, principal_id):
        ''' See the interface IPrincipalRoleManager '''

        # Don't check validity intentionally.
        # After all, we certianly want to unset invalid ids.

        self.delCell(role_id, principal_id)

    def getPrincipalsForRole(self, role_id):
        ''' See the interface IPrincipalRoleMap '''
        return self.getRow(role_id)

    def getRolesForPrincipal(self, principal_id):
        ''' See the interface IPrincipalRoleMap '''
        return self.getCol(principal_id)

    def getSetting(self, role_id, principal_id):
        ''' See the interface IPrincipalRoleMap '''
        return self.getCell(role_id, principal_id, default=Unset)

    def getPrincipalsAndRoles(self):
        ''' See the interface IPrincipalRoleMap '''
        return self.getAllCells()

# Roles are our rows, and principals are our columns
principalRoleManager = PrincipalRoleManager()

# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(principalRoleManager._clear)
del addCleanUp


=== Added File Zope3/src/zope/app/securitypolicy/role.py ===
##############################################################################
#
# 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.0 (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: role.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""

from persistence import Persistent
from zope.interface import implements
from zope.component import getService

from zope.app.container.btree import BTreeContainer
from zope.app.interfaces.container import IContainer
from zope.app.component.nextservice import getNextService
from zope.app.interfaces.services.service import ISimpleService

from zope.app.securitypolicy.roleregistry import Role
from zope.app.securitypolicy.interfaces import IRoleService

class Role(Role, Persistent):
    "Persistent Role"

class ILocalRoleService(IRoleService, IContainer):
    """TTW manageable role service"""

class RoleService(BTreeContainer):

    implements(ILocalRoleService, ISimpleService)

    def getRole(wrapped_self, rid):
        '''See interface IRoleService'''
        try:
            return wrapped_self[rid]
        except KeyError:
            # We failed locally: delegate to a higher-level service.
            sv = getNextService(wrapped_self, 'Roles')
            if sv:
                return sv.getRole(rid)
            raise # will be original Key Error

    def getRoles(wrapped_self):
        '''See interface IRoleService'''
        roles = list(wrapped_self.values())
        roleserv = getNextService(wrapped_self, 'Roles')
        if roleserv:
            roles.extend(roleserv.getRoles())
        return roles

def checkRole(context, role_id):
    if not getService(context, 'Roles').getRole(role_id):
        raise ValueError("Undefined role id", role_id)


=== Added File Zope3/src/zope/app/securitypolicy/rolepermission.py ===
##############################################################################
#
# 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.0 (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: rolepermission.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""
from zope.component import getAdapter
from zope.interface import implements

from zope.app.interfaces.annotation import IAnnotations

from zope.app.security.settings import Allow, Deny, Unset
from zope.app.security.permission import checkPermission
from zope.app.securitypolicy.role import checkRole

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 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:
    """
    provide adapter that manages role permission data in an object attribute
    """

    implements(IRolePermissionManager, IRolePermissionMap)

    def __init__(self, context):
        self._context = context

    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

    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

    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

    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

    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 = getAdapter(context, IAnnotations)
        try:
            return annotations[annotation_key]
        except KeyError:
            if create:
                rp = annotations[annotation_key] = PersistentSecurityMap()
                return rp
        return None

class RolePermissions:

    implements(IRole)

    def __init__(self, role, context, permissions):
        self._role = role
        self._context = context
        self._permissions = permissions

    def getId(self):
        return self._role.getId()

    def getTitle(self):
        return self._role.getTitle()

    def getDescription(self):
        return self._role.getDescription()

    def permissionsInfo(self):
        prm = getAdapter(self._context, IRolePermissionManager)
        rperms = prm.getPermissionsForRole(self._role.getId())
        settings = {}
        for permission, setting in rperms:
            settings[permission] = setting.getName()
        nosetting = Unset.getName()
        return [{'id': permission.getId(),
                 'title': permission.getTitle(),
                 'setting': settings.get(permission.getId(), nosetting)}
                for permission in self._permissions]


class RolePermissionManager(SecurityMap):
    """Mappings between roles and permissions."""

    implements(IRolePermissionManager)

    def grantPermissionToRole(self, permission_id, role_id, check=True):
        '''See interface IRolePermissionMap'''

        if check:
            checkRole(None, role_id)
            checkPermission(None, permission_id)

        self.addCell(permission_id, role_id, Allow)

    def denyPermissionToRole(self, permission_id, role_id, check=True):
        '''See interface IRolePermissionMap'''

        if check:
            checkRole(None, role_id)
            checkPermission(None, permission_id)

        self.addCell(permission_id, role_id, Deny)

    def unsetPermissionFromRole(self, permission_id, role_id):
        '''See interface IRolePermissionMap'''

        # Don't check validity intentionally.
        # After all, we certianly want to unset invalid ids.

        self.delCell(permission_id, role_id)

    def getRolesForPermission(self, permission_id):
        '''See interface IRolePermissionMap'''
        return self.getRow(permission_id)

    def getPermissionsForRole(self, role_id):
        '''See interface IRolePermissionMap'''
        return self.getCol(role_id)

    def getSetting(self, permission_id, role_id):
        '''See interface IRolePermissionMap'''
        return self.getCell(permission_id, role_id)

    def getRolesAndPermissions(self):
        '''See interface IRolePermissionMap'''
        return self.getAllCells()

# Permissions are our rows, and roles are our columns
rolePermissionManager = RolePermissionManager()

# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(rolePermissionManager._clear)
del addCleanUp


=== Added File Zope3/src/zope/app/securitypolicy/roleregistry.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
"""Global role registry.

$Id: roleregistry.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""

PREFIX = 'Global Role'

from zope.interface import implements
from zope.app.security.registries.registeredobject import RegisteredObject
from zope.app.security.registries.registry import Registry
from zope.app.interfaces.services.service import ISimpleService
from zope.app.securitypolicy.interfaces import IRole
from zope.app.securitypolicy.interfaces import IRoleService

class Role(RegisteredObject):
    implements(IRole)


class RoleRegistry(Registry):
    implements(IRoleService, ISimpleService)

    def __init__(self, prefix=PREFIX):
        Registry.__init__(self, Role)
        self._prefix = prefix

    def _make_global_id(self, suffix):
        return self._prefix + '.' + suffix

    def defineRole(self, role, title, description=None):
        """Define a new role object, register, and return it.

        role is the role name.

        title is the role title, human readable.

        description (optional) is human readable
        """
        if description is None:
            description = ''
        id = role
        return self.register(id, title, description)

    def definedRole(self, id):
        """Return true if named role is registered, otherwise return false
        """
        return self.is_registered(id)

    def getRole(self, id):
        """Return role object registered as name.

        If no named role is registered KeyError is raised.
        """
        return self.getRegisteredObject(id)

    def getRoles(self):
        """Return all registered role objects.
        """
        return self.getRegisteredObjects()

    def _clear(self):
        # Standard roles
        Registry._clear(self)
        self.register("zope.Anonymous", "Everybody",
                      "All users have this role implicitly")

roleRegistry = RoleRegistry()


# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(roleRegistry._clear)
del addCleanUp


=== Added File Zope3/src/zope/app/securitypolicy/securitymap.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
""" Generic two-dimensional array type """

from persistence import Persistent
from persistence.dict import PersistentDict
from zope.interface import implements
from zope.app.securitypolicy.interfaces import ISecurityMap

class SecurityMap(object):

    implements(ISecurityMap)

    def __init__(self):
        self._clear()

    def _clear(self):
        self._byrow = {}
        self._bycol = {}

    def _empty_mapping(self):
        return {}

    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[colentry] = value

        col = self._bycol.setdefault(colentry, self._empty_mapping())
        col[rowentry] = value

    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]

    def getCell(self, rowentry, colentry, default=None):
        " return the value of a cell by row, entry "
        row = self._byrow.get(rowentry)
        if row: return row.get(colentry, default)
        else: return default

    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 []

    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 []

    def getAllCells(self):
        " return a list of (rowentry, colentry, value) "
        res = []
        for r in self._byrow.keys():
            for c in self._byrow[r].items():
                res.append((r,) + c)
        return res


class PersistentSecurityMap(SecurityMap, Persistent):

    implements(ISecurityMap)

    def _clear(self):
        self._byrow = PersistentDict()
        self._bycol = PersistentDict()

    def _empty_mapping(self):
        return PersistentDict()


=== Added File Zope3/src/zope/app/securitypolicy/zopepolicy.py ===
##############################################################################
#
# 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.0 (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.
#
##############################################################################
""" Define Zope\'s default security policy

$Id: zopepolicy.py,v 1.1 2004/02/27 12:46:31 philikon Exp $
"""
from zope.interface import implements
from zope.component import queryAdapter
from zope.security.interfaces import ISecurityPolicy
from zope.security.management import system_user

from zope.app.location import LocationIterator

from zope.app.securitypolicy.interfaces import \
     IRolePermissionMap, IPrincipalPermissionMap, IPrincipalRoleMap
from zope.app.securitypolicy.principalpermission \
     import principalPermissionManager
from zope.app.securitypolicy.rolepermission import rolePermissionManager
from zope.app.securitypolicy.principalrole import principalRoleManager
from zope.app.security.settings import Allow, Deny

getPermissionsForPrincipal = \
                principalPermissionManager.getPermissionsForPrincipal
getPermissionsForRole = rolePermissionManager.getPermissionsForRole
getRolesForPrincipal = principalRoleManager.getRolesForPrincipal

globalContext = object()


class ZopeSecurityPolicy:

    implements(ISecurityPolicy)

    def __init__(self, ownerous=True, authenticated=True):
        """
            Two optional keyword arguments may be provided:

            ownerous -- Untrusted users can create code
                (e.g. Python scripts or templates),
                so check that code owners can access resources.
                The argument must have a truth value.
                The default is true.

            authenticated -- Allow access to resources based on the
                privileges of the authenticated user.
                The argument must have a truth value.
                The default is true.

                This (somewhat experimental) option can be set
                to false on sites that allow only public
                (unauthenticated) access. An anticipated
                scenario is a ZEO configuration in which some
                clients allow only public access and other
                clients allow full management.
        """

        self._ownerous = ownerous
        self._authenticated = authenticated

    def checkPermission(self, permission, object, context):
        # XXX We aren't really handling multiple principals yet

        # mapping from principal to set of roles
        user = context.user
        if user is system_user:
            return True

        roledict = {'zope.Anonymous': Allow}
        principals = {user.getId() : roledict}

        role_permissions = {}
        remove = {}

        # Look for placeless grants first.

        # 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

        # 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

        # 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

        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

        # 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


        # 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

        # Look for placeful grants
        for place in LocationIterator(object):

            # Copy specific principal permissions
            prinper = queryAdapter(place, IPrincipalPermissionMap)
            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

                            assert setting is Allow
                            remove[principal] = True

            # 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

            # Collect principal roles
            prinrole = queryAdapter(place, IPrincipalRoleMap)
            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

            # Collect role permissions
            roleper = queryAdapter(place, IRolePermissionMap)
            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
            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

            # 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

        return False # deny by default


def permissionsOfPrincipal(principal, object):
    permissions = {}

    roles = {'zope.Anonymous': Allow}
    principalid = principal.getId()

    # 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 = queryAdapter(place, IPrincipalPermissionMap)
        if prinper is not None:
            for permission, setting in prinper.getPermissionsForPrincipal(
                principalid):
                if permission not in permissions:
                    permissions[permission] = setting

        # Collect principal roles
        prinrole = queryAdapter(place, IPrincipalRoleMap)
        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 = queryAdapter(place, IRolePermissionMap)
        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

zopeSecurityPolicy=ZopeSecurityPolicy()




More information about the Zope3-Checkins mailing list