[Zope3-checkins] CVS: Zope3/src/zope/app/security - __init__.py:1.1.2.1 _protections.py:1.1.2.1 basicauthadapter.py:1.1.2.1 basicvfsauthadapter.py:1.1.2.1 configure.zcml:1.1.2.1 exceptions.py:1.1.2.1 loginpassword.py:1.1.2.1 meta.zcml:1.1.2.1 metaconfigure.py:1.1.2.1 permissionfield.py:1.1.2.1 protectclass.py:1.1.2.1 settings.py:1.1.2.1 zopesecuritypolicy.py:1.1.2.1

Jim Fulton jim@zope.com
Mon, 23 Dec 2002 14:32:18 -0500


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

Added Files:
      Tag: NameGeddon-branch
	__init__.py _protections.py basicauthadapter.py 
	basicvfsauthadapter.py configure.zcml exceptions.py 
	loginpassword.py meta.zcml metaconfigure.py permissionfield.py 
	protectclass.py settings.py zopesecuritypolicy.py 
Log Message:
Initial renaming before debugging

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


=== Added File Zope3/src/zope/app/security/_protections.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 protection information for some standard low-level types

Revision information:
$Id: _protections.py,v 1.1.2.1 2002/12/23 19:32:15 jim Exp $
"""

def protect():
    from zope.security.checker import defineChecker, NamesChecker, NoProxy


    # excluding _check, _bucket_type, _firstbucket, and write operations
    _btreeChecker = NamesChecker(['__str__', '__repr__', '__contains__',
                                  '__getitem__', '__iter__', '__len__',  
                                  'byValue', 'get', 'has_key', 'items', 
                                  'iteritems', 'iterkeys', 'itervalues',
                                  'keys', 'maxKey', 'minKey', 'values'])

    # excluding _next
    _btreeBucketChecker = NamesChecker([
            '__contains__', '__getitem__', '__iter__', '__len__', '__repr__',
            '__str__', 'byValue', 'get', 'has_key', 'items', 'iteritems',
            'iterkeys', 'itervalues', 'keys', 'maxKey','minKey', 'values'])
    
    _btreeSetChecker = NamesChecker([
            '__contains__', '__getitem__', '__iter__', '__len__', '__repr__',
            '__str__', 'has_key', 'insert', 'keys', 'maxKey', 'minKey'])
    
    # excluding _bucket_type, _check
    _btreeTreeSetChecker = NamesChecker([
            '__contains__', '__iter__', '__len__', '__repr__',
            '__str__', 'has_key', 'insert', 'keys', 'maxKey', 'minKey'])
    
    _btreeItemsChecker = NamesChecker([
            '__iter__', '__repr__', '__str__', '__getitem__', '__len__',
            '__contains__'])
    
    _iteratorChecker = NamesChecker(['next'])

    from zodb.btrees.IIBTree import IIBTree, IIBucket, IISet, IITreeSet
    from zodb.btrees.IOBTree import IOBTree, IOBucket, IOSet, IOTreeSet
    from zodb.btrees.OIBTree import OIBTree, OIBucket, OISet, OITreeSet
    from zodb.btrees.OOBTree import OOBTree, OOBucket, OOSet, OOTreeSet

    _btree_checkers = { 
        IIBTree: _btreeChecker,
        IOBTree: _btreeChecker,
        OIBTree: _btreeChecker,
        OOBTree: _btreeChecker,
        IIBucket: _btreeBucketChecker,
        IOBucket: _btreeBucketChecker,
        OIBucket: _btreeBucketChecker,
        OOBucket: _btreeBucketChecker,
        IISet: _btreeSetChecker,
        IOSet: _btreeSetChecker,
        OISet: _btreeSetChecker,
        OOSet: _btreeSetChecker,
        IITreeSet: _btreeTreeSetChecker,
        IOTreeSet: _btreeTreeSetChecker,
        OITreeSet: _btreeTreeSetChecker,
        OOTreeSet: _btreeTreeSetChecker,
        type(iter(IIBTree())): NoProxy, # II-iterator is a rock
        type(iter(IOBTree())): _iteratorChecker, # IO-iterator
        type(iter(OIBTree())): _iteratorChecker, # OI-iterator
        type(iter(OOBTree())): _iteratorChecker, # OO-iterator
        type(IIBTree().keys()): NoProxy, # IIBTreeItems is a rock
        type(IOBTree().keys()): _btreeItemsChecker, # IOBTreeItems
        type(OIBTree().keys()): _btreeItemsChecker, # OIBTreeItems
        type(OOBTree().keys()): _btreeItemsChecker, # OOBTreeItems
    }
    for which_type, checker in _btree_checkers.iteritems():
        defineChecker(which_type, checker)

    from persistence.list import PersistentList

    defineChecker(PersistentList,
                  NamesChecker(
                     ['__getitem__', '__getslice__', '__len__', '__iter__',
                      '__contains__', 'index', 'count'])
                  )

    from persistence.dict import PersistentDict

    defineChecker(PersistentDict,
                  NamesChecker(['__getitem__', '__len__', '__iter__',
                        'get', 'has_key', '__copy__',
                        'keys', 'values', 'items',
                        'iterkeys', 'iteritems', 'itervalues', '__contains__',
                        ]
                     )
                  )

    # In Python 2.3 and up, PersistentMetaClass is just type.
    # It causes an error to define a new checker for type.
    from persistence import PersistentMetaClass
    if PersistentMetaClass != type:
        from zope.security.checker import _typeChecker
        defineChecker(PersistentMetaClass, _typeChecker)


=== Added File Zope3/src/zope/app/security/basicauthadapter.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.
# 
##############################################################################
# HTTP Basic Authentication adapter

from zope.publisher.interfaces.http import IHTTPCredentials
from zope.app.security.loginpassword import LoginPassword

class BasicAuthAdapter(LoginPassword):

    __used_for__ = IHTTPCredentials

    __request = None

    def __init__(self, request):
        self.__request = request
        # XXX base64 decoding should be done here, not in request
        lpw = request._authUserPW()
        if lpw is None:
            login, password = None, None
        else:
            login, password = lpw
        LoginPassword.__init__(self, login, password)

    def needLogin(self, realm):
        self.__request.unauthorized("basic realm=%s" % realm)


=== Added File Zope3/src/zope/app/security/basicvfsauthadapter.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.
# 
##############################################################################
# HTTP Basic Authentication adapter

from zope.publisher.interfaces.vfs import IVFSCredentials
from zope.app.security.loginpassword import LoginPassword

class BasicVFSAuthAdapter(LoginPassword):

    __used_for__ = IVFSCredentials

    __request = None

    def __init__(self, request):
        self.__request = request
        # XXX base64 decoding should be done here, not in request
        lpw = request._authUserPW()
        if lpw is None:
            login, password = None, None
        else:
            login, password = lpw
        LoginPassword.__init__(self, login, password)

    def needLogin(self, realm):
        self.__request.unauthorized("Did not work")


=== Added File Zope3/src/zope/app/security/configure.zcml ===
<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:browser='http://namespaces.zope.org/browser'
   >

  <include package=".Registries" />

  <!-- Standard Permissions -->

  <permission id="Zope.View"
                       title="View"
                       />

  <permission id="Zope.Security"
                       title="Change security settings"
                       />

  <permission id="Zope.ManageContent" 
                       title="Manage Content"
                       />

  <permission id="Zope.ManageBindings" 
                       title="Manage Service Bindings"
                       />

  <permission id="Zope.ManageCode" 
                       title="Manage Code"
                       description="Manage executable code, including
                                    Python, SQL, ZPT, etc."
                        />

  <permission id="Zope.ManageServices" 
                       title="Manage Services"
                        />

  <!-- XXX What is this for? -->
  <permission id="Zope.ManageApplication" 
                       title="Manage Application"
                       />

  <!-- XXX What is this for? -->
  <permission id="Zope.I18n" 
                       title="Use Internationalization (?XXX)"
                       />

  <include package=".Grants" />

  <securityPolicy 
      name="Zope.App.Security.ZopeSecurityPolicy.zopeSecurityPolicy" />

  <adapter factory="zope.app.security.basicauthadapter.BasicAuthAdapter"
           provides="zope.app.interfaces.security.ILoginPassword"
           for="zope.publisher.interfaces.http.IHTTPCredentials" />

  <adapter factory="zope.app.security.basicvfsauthadapter.BasicVFSAuthAdapter"
           provides="zope.app.interfaces.security.ILoginPassword"
           for="zope.publisher.interfaces.vfs.IVFSCredentials" />

  <include package=".Browser" />
  
</zopeConfigure>



=== Added File Zope3/src/zope/app/security/exceptions.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.
# 
##############################################################################
"""

Revision information:
$Id: exceptions.py,v 1.1.2.1 2002/12/23 19:32:15 jim Exp $
"""

class UndefinedPermissionError(Exception):
    """Somebody tried to use a permission before it was defined.
    """


=== Added File Zope3/src/zope/app/security/loginpassword.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.
# 
##############################################################################
from zope.app.interfaces.security import ILoginPassword

class LoginPassword:

    __implements__ = ILoginPassword

    def __init__(self, login, password):
        self.__login = login
        if login is None:
            self.__password = None
        else:
            self.__password = password or ""

    def getLogin(self):
        return self.__login

    def getPassword(self):
        return self.__password

    def needLogin(self, realm):
        pass


=== Added File Zope3/src/zope/app/security/meta.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>

  <include package=".Registries" file="meta.zcml" />
  <include package=".Grants.Global" file="meta.zcml" />

  <directives namespace="http://namespaces.zope.org/zope">
    <directive name="securityPolicy" attributes="name"
       handler="zope.app.security.metaconfigure.securityPolicy" />
  </directives>

</zopeConfigure>


=== Added File Zope3/src/zope/app/security/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.2.1 2002/12/23 19:32:15 jim Exp $
"""

from zope.configuration.action import Action
from zope.security.securitymanager import setSecurityPolicy

def securityPolicy(_context, name):
    policy = _context.resolve(name)
    if callable(policy):
        policy = policy()
    return [
        Action(
            discriminator = 'defaultPolicy',
            callable = setSecurityPolicy,
            args = (policy,),
            )
        ]




=== Added File Zope3/src/zope/app/security/permissionfield.py ===
##############################################################################
#
# Copyright (c) 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.
# 
##############################################################################
"""These are the interfaces for the common fields.

$Id: permissionfield.py,v 1.1.2.1 2002/12/23 19:32:15 jim Exp $
"""

from zope.schema.interfaces import IValueSet
from zope.schema import ValueSet
from zope.schema.interfaces import ValidationError
from zope.component import getService

class IPermissionField(IValueSet):
    u"""Fields with Permissions as values
    """

class PermissionField(ValueSet):
    __doc__ = IPermissionField.__doc__
    __implements__ = IPermissionField

    def _validate(self, value):
        super(PermissionField, self)._validate(value)
        service = getService(self.context, 'Permissions')
        if service.getPermission(value.getId()) is None:
            raise ValidationError("Unknown permission", value)



=== Added File Zope3/src/zope/app/security/protectclass.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.
# 
##############################################################################
"""Make assertions about permissions needed to access class instances attributes
"""

from zope.app.security.exceptions import UndefinedPermissionError
from zope.app.security.registries.permissionregistry import permissionRegistry

from zope.security.checker import defineChecker, getCheckerForInstancesOf
from zope.security.checker import Checker, CheckerPublic

def checkPermission(permission):
    """Check to make sure that the permission is valid.
    """
    if not permissionRegistry.definedPermission(permission):
        raise UndefinedPermissionError(permission)

def protectName(class_, name, permission):
    "Set a permission on a particular name."
    
    checkPermission(permission)
    
    checker = getCheckerForInstancesOf(class_)
    if checker is None:
        checker = Checker({}.get, {}.get)
        defineChecker(class_, checker)

    if permission == 'Zope.Public':
        # Translate public permission to CheckerPublic
        permission = CheckerPublic

    # We know a dictionart get method was used because we set it
    protections = checker.getPermission_func().__self__    
    protections[name] = permission

def protectSetAttribute(class_, name, permission):
    "Set a permission on a particular name."
    
    checkPermission(permission)
    
    checker = getCheckerForInstancesOf(class_)
    if checker is None:
        checker = Checker({}.get, {}.get)
        defineChecker(class_, checker)

    if permission == 'Zope.Public':
        # Translate public permission to CheckerPublic
        permission = CheckerPublic

    # We know a dictionart get method was used because we set it
    protections = checker.getSetattrPermission_func().__self__    
    protections[name] = permission

def protectLikeUnto(class_, like_unto):
    """Use the protections from like_unto for class_
    """
    
    unto_checker = getCheckerForInstancesOf(like_unto)
    if unto_checker is None:
        return

    # We know a dictionart get method was used because we set it
    unto_protections = unto_checker.getPermission_func().__self__
    
    checker = getCheckerForInstancesOf(class_)
    if checker is None:
        checker = Checker({}.get)
        defineChecker(class_, checker)

    # OK, so it's a hack.
    protections = checker.getPermission_func().__self__
    for name in unto_protections:
        protections[name] = unto_protections[name]


=== Added File Zope3/src/zope/app/security/settings.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 setting constants """


class PermissionSetting(object):
    """PermissionSettings should be considered as immutable.
    They can be compared by identity. They are identified by
    their name.
    """

    def __new__(cls, name, description=None):
        """Keep a dict of PermissionSetting instances, indexed by
        name. If the name already exists in the dict, return that
        instance rather than creating a new one.
        """
        instances = cls.__dict__.get('__instances__')
        if instances is None:
            cls.__instances__ = instances = {}
        it = instances.get(name)
        if it is None:
            instances[name] = it = object.__new__(cls)
            it._init(name, description)
        return it

    def _init(self, name, description):
        self.__name = name
        self.__description = description

    def getDescription(self):
        return self.__description

    def getName(self):
        return self.__name

    def __str__(self):
        return "PermissionSetting: %s" % self.__name

# register PermissionSettings to be symbolic constants by identity,
# even when pickled and unpickled.
import copy_reg
copy_reg.constructor(PermissionSetting)
copy_reg.pickle(PermissionSetting,
                PermissionSetting.getName,
                PermissionSetting)


Allow = PermissionSetting('Allow',
    'Explicit allow setting for permissions')

Deny = PermissionSetting('Deny',
    'Explicit deny setting for permissions')

Unset = PermissionSetting('Unset',
    'Unset constant that denotes no setting for permission and role')



=== Added File Zope3/src/zope/app/security/zopesecuritypolicy.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: zopesecuritypolicy.py,v 1.1.2.1 2002/12/23 19:32:15 jim Exp $
"""
__version__='$Revision: 1.1.2.1 $'[11:-2]

from zope.component import queryAdapter

from zope.proxy.context.context import ContainmentIterator

from zope.exceptions import Unauthorized, Forbidden

from zope.security.interfaces import ISecurityPolicy
from zope.security.securitymanagement import system_user

from zope.app.interfaces.security \
     import IRolePermissionManager, IRolePermissionMap
from zope.app.interfaces.security \
    import IPrincipalPermissionManager, IPrincipalPermissionMap
from zope.app.interfaces.security \
    import IPrincipalRoleManager, IPrincipalRoleMap
from zope.app.interfaces.security import IRolePermissionManager
from zope.app.security.registries.permissionregistry import permissionRegistry 
from zope.app.security.registries.principalregistry import principalRegistry 
from zope.app.security.registries.roleregistry import roleRegistry
from zope.app.security.grants.global.principalpermissionmanager \
     import principalPermissionManager 
from zope.app.security.grants.global.rolepermissionmanager \
     import rolePermissionManager 
from zope.app.security.grants.global.principalrolemanager \
     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=1, authenticated=1):
        """
            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
                privaledges 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 1
        
        principals = {user : {'Anonymous': Allow}}
        
        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 0
                    assert setting is Allow
                    remove[principal] = 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 1


        # 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 in roles:
                if role in role_permissions:
                    if permission in role_permissions[role]:
                        setting = role_permissions[role][permission]
                        if setting is Deny:
                            return 0
                        remove[principal] = 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 1

        # Look for placeful grants
        for place in ContainmentIterator(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 0

                            assert setting is Allow
                            remove[principal] = 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 1
                
            # 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 in roles:
                    if role in role_permissions:
                        if permission in role_permissions[role]:
                            setting = role_permissions[role][permission]
                            if setting is Deny:
                                return 0
                            remove[principal] = 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 1

        return 0 # deny by default


def permissionsOfPrincipal(principal, object):
    permissions = {}
    roles = {'Anonymous': Allow} # Everyone has anonymous
    role_permissions = {}

    # Make two passes.

    # First, collect what we know about the principal:


    # get placeless principal permissions
    for permission, setting in getPermissionsForPrincipal(principal):
        if permission not in permissions:
            permissions[permission] = setting

    # get placeless principal roles
    for role, setting in getRolesForPrincipal(principal):
        if role not in roles:
            roles[role] = setting

    # get placeful principal permissions and roles
    for place in ContainmentIterator(object):

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