[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security - Checker.py:1.1.4.1 IChecker.py:1.1.4.1 ISecurityContext.py:1.1.4.1 ISecurityManagement.py:1.1.4.1 ISecurityManager.py:1.1.4.1 ISecurityPolicy.py:1.1.4.1 ISecurityProxyFactory.py:1.1.4.1 Proxy.py:1.1.4.1 RestrictedInterpreter.py:1.1.4.1 SecurityContext.py:1.1.4.1 SecurityManagement.py:1.1.4.1 SecurityManager.py:1.1.4.1 SimpleSecurityPolicies.py:1.1.4.1 _Proxy.c:1.1.4.1 __init__.py:1.1.4.1 setup.py:1.1.4.1

Jim Fulton jim@zope.com
Sun, 28 Apr 2002 13:16:50 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Security
In directory cvs.zope.org:/tmp/cvs-serv17050/lib/python/Zope/Security

Added Files:
      Tag: Zope-3x-branch
	Checker.py IChecker.py ISecurityContext.py 
	ISecurityManagement.py ISecurityManager.py ISecurityPolicy.py 
	ISecurityProxyFactory.py Proxy.py RestrictedInterpreter.py 
	SecurityContext.py SecurityManagement.py SecurityManager.py 
	SimpleSecurityPolicies.py _Proxy.c __init__.py setup.py 
Log Message:
HOTYB: Merged SecurityProxy-branch into main branch.  

All tests pass and folders can be listed and added through the web.
It is likely that most other things don't work and will need to be
fixed. The reason is that many accesses that should have been checked
before are now being checked and additional checks and thinking about
permissions and security settings are needed.

I'm in the process of drafting a paper for the wiki that describes the
changes in more detail.


=== Added File Zope3/lib/python/Zope/Security/Checker.py ===
from Zope.Security.IChecker import IChecker
from Zope.Exceptions \
     import Unauthorized, ForbiddenAttribute, Forbidden, DuplicationError
from Interface.IInterface import IInterface
from _Proxy import _Proxy as Proxy
from types import InstanceType, ClassType, FunctionType, MethodType, ModuleType
from ISecurityProxyFactory import ISecurityProxyFactory
from Zope.Security.SecurityManagement import getSecurityManager

# Marker for public attributes
CheckerPublic = object()

def ProxyFactory(object, checker=None):
    """Factory function that creats a proxy for an object

    The proxy checker is looked up if not provided.
    """
    
    if checker is None:        
        checker = selectChecker(object)
        if checker is None:
            return object

    else:
        # Maybe someone passed us a proxy and a checker
        if type(object) is Proxy:
            # XXX should we keep the existing proxy or create a new one.
            return object

    return Proxy(object, checker)

ProxyFactory.__implements__ = ISecurityProxyFactory

class Checker:

    __implements__ =  IChecker

    def __init__(self, permission_func):
        """Create a checker

        A callable must be provided for computing permissions for
        names. The callable will be called with attribute names and
        must return a permission id, None, or the special marker,
        CheckerPublic. If None is returned, then access to the name is
        forbidden. If CheckerPublic is returned, then access will be
        granted without checking a permission.
        """

        self.__permission_func = permission_func


    def getPermission_func(self):
        return self.__permission_func

    def permission_id(self, name):
        """Return the result of calling the permission func
        """
        return self.__permission_func(name)

    ############################################################
    # Implementation methods for interface
    # Zope.Security.IChecker.

    def check_getattr(self, object, name):
        'See Zope.Security.IChecker.IChecker'
        self.check(object, name)

    def check_setattr(self, object, name):
        'See Zope.Security.IChecker.IChecker'
        # YAGNI
        raise Forbidden("Can't set attributes in untrusted code.")

    def check(self, object, name):
        'See Zope.Security.IChecker.IChecker'

        # We have the information we need already
        permission = self.__permission_func(name)
        if permission:
            if permission is CheckerPublic:
                return # Public
            manager = getSecurityManager()
            if manager.checkPermission(permission, object):
                return
            else:
                raise Unauthorized(name=name)
        elif name in _always_available:
            return

        raise ForbiddenAttribute(name)

    def proxy(self, value):
        'See Zope.Security.IChecker.IChecker'
        # Now we need to create a proxy
        checker = selectChecker(value)
        if checker is None:
            return value

        return Proxy(value, checker)

    #
    ############################################################

def NamesChecker(names=(), permission_id=CheckerPublic, **__kw__):
    """Return a checker that grants access to a set of names.

    A sequence of names is given as the first argument. If a second
    argument, permission_id, is given, it is the permission required
    to access the names.  Additional names and persmission ids can be
    supplied as keyword arguments.
    """

    data = {}
    data.update(__kw__)
    for name in names:
        if data.get(name, permission_id) is not permission_id:
            raise DuplicationError(name)
        data[name] = permission_id

    return Checker(data.get)

def MultiChecker(specs):
    """Create a checker from a sequence of specifications

    A specification is:

    - A two-tuple with:

      o a sequence of names or an interface

      o a permission id

      All the names in the sequence of names or the interface are
      protected by the permission.

    - A dictionoid (having anitems method), with items that are
      name/permission-id pairs.
    """
    data = {}

    for spec in specs:
        if type(spec) is tuple:
            names, permission_id = spec
            if IInterface.isImplementedBy(names):
                names = names.names(1)
            for name in names:
                if data.get(name, permission_id) is not permission_id:
                    raise DuplicationError(name)
                data[name] = permission_id
        else:
            for name, permission_id in spec.items():
                if data.get(name, permission_id) is not permission_id:
                    raise DuplicationError(name)
                data[name] = permission_id

    return Checker(data.get)

def NonPrivateChecker(permission_id = CheckerPublic):

    def check(name, permission_id=permission_id):
        if name.startswith('_'):
            return None
        return permission_id

    return Checker(check)


def selectChecker(object):
    """Get a checker for the given object

    The appropriate checker is returned or None is returned. If the
    return value is None, then object should not be wrapped in a proxy.
    """
    checker = _getChecker(type(object), _defaultChecker)
    if checker is NoProxy:
        return None

    while not isinstance(checker, Checker):
        checker = checker(object)
        if checker is NoProxy:
            return None
    
    return checker

def getCheckerForInstancesOf(class_):
    return _checkers.get(class_)
    
    

def defineChecker(type_, checker):
    """Define a checker for a given type of object

    The checker can be a Checker, or a function that, when called with
    an object, returns a Checker.
    """
    if type_ in _checkers:
        raise DuplicationError(type_)
    _checkers[type_] = checker


NoProxy = object()

# _checkers is a mapping.
#
#  - Keys are types
#
#  - Values are
#
#    o None => rock
#    o a Checker
#    o a function returning None or a Checker
#
_checkers = {}
_getChecker = _checkers.get

_defaultChecker = Checker({}.get)

def _instanceChecker(inst):
    checker = _checkers.get(inst.__class__, _defaultChecker)
    if checker is _defaultChecker and isinstance(inst, Exception):
        return NoProxy # XXX we should be more careful
    return checker

def _classChecker(class_):
    checker = _checkers.get(class_, _typeChecker)
    if checker is _typeChecker and issubclass(class_, Exception):
        return NoProxy # XXX we should be more careful

    return checker

def _moduleChecker(module):
    return _checkers.get(module, _typeChecker)



_always_available = ['__lt__', '__le__', '__eq__',
                     '__gt__', '__ge__', '__ne__',
                     '__hash__', '__nonzero__',
                     '__class__', '__implements__',
                     ]

_callableChecker = NamesChecker(['__str__', '__repr__', '__name__',
                                 '__call__'])
_typeChecker = NamesChecker(['__str__', '__repr__', '__name__', '__module__'])

BasicTypes = {
    int: NoProxy,
    float: NoProxy,
    long: NoProxy,
    complex: NoProxy,
    type(None): NoProxy,
    str: NoProxy,
    unicode: NoProxy,
    type(not 1): NoProxy, # Boolean, if available :)
}

_default_checkers = {
    dict: NamesChecker(['__getitem__', '__len__', '__iter__',
                        'get', 'has_key', '__copy__',
                        'keys', 'values', 'items',
                        'iterkeys', 'iteritems', 'itervalues', '__contains__',
                        ]),
    list: NamesChecker(['__getitem__', '__getslice__', '__len__', '__iter__',
                        '__contains__', 'index', 'count']),

    # YAGNI: () a rock
    tuple: NamesChecker(['__getitem__', '__getslice__',
                         '__contains__', '__len__', '__iter__']),
    InstanceType: _instanceChecker,
    Proxy: NoProxy,
    ClassType: _classChecker,
    FunctionType: _callableChecker,
    MethodType: _callableChecker,
    type: _typeChecker,
    ModuleType: _moduleChecker,
    type(iter([])): NamesChecker(['next']),
    }


def _clear():
    _checkers.clear()
    _checkers.update(_default_checkers)
    _checkers.update(BasicTypes)

_clear()

from Zope.Testing.CleanUp import addCleanUp
addCleanUp(_clear)


=== Added File Zope3/lib/python/Zope/Security/IChecker.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: IChecker.py,v 1.1.4.1 2002/04/28 17:16:49 jim Exp $
"""

from Interface import Interface

class IChecker(Interface):
    """Security-proxy plugin objects that implement low-level checks

    The checker is responsible for creating proxies for
    operation return values, via the proxy method.

    There are check_getattr() and check_setattr() methods for checking
    getattr and setattr, and a check() method for all other operations.

    The check methods may raise errors.  They return no value.

    Example (for __getitem__):

           checker.check(ob, "__getitem__")
           return checker.proxy(ob[key])
    """

    def check_getattr(ob, name):
        """Check whether attribute access is allowed.
        """

    def check_setattr(ob, name):
        """Check whether attribute assignment is allowed.
        """

    def check(ob, operation):
        """Check whether operation is allowed.

        The operation name is the Python special method name,
        e.g. "__getitem__".
        """

    def proxy(value):
        """Return a security proxy for the value.
        """


=== Added File Zope3/lib/python/Zope/Security/ISecurityContext.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 Interface import Interface
from Interface.Attribute import Attribute

class ISecurityContext( Interface ):
    """
        Capture transient request-specific security information.
    """
    Attribute( 'stack'
             , 'A stack of elements, each either be an ExecutableObject'
               'or a tuple consisting of an ExecutableObject and a'
               'custom SecurityPolicy.'
             )

    Attribute( 'principal'
             , 'The AUTHENTICATED_USER for the request.'
             )



=== Added File Zope3/lib/python/Zope/Security/ISecurityManagement.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 Interface import Interface

class ISecurityManagementSetup( Interface ):
    """
        Infrastructure (including tests, etc.) calls these things to
        tweak the security manager.
    """
    def newSecurityManager( user ):
        """
            Install a new SecurityManager, using user.  Return the
            old SecurityManager, if any, or None.
        """

    def replaceSecurityManager( old_manager ):
        """
            Replace the SecurityManager with 'old_manager', which
            must implement ISecurityManager.
        """

    def noSecurityManager():
        """
            Clear any existing SecurityManager.
        """

class ISecurityManagement( Interface ):
    """
        "Public" SM API.
    """
    def getSecurityManager():
        """
            Get a SecurityManager (create if needed).
        """

    def setSecurityPolicy( aSecurityPolicy ):
        """
            Set the system default security policy. 

            This method should only be caused by system startup code.
            It should never, for example, be called during a web request.
        """


=== Added File Zope3/lib/python/Zope/Security/ISecurityManager.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 Interface import Interface

# XXX This interface has too muct Zope application dependence. This
# needs to be refactored somehow.

class ISecurityManager( Interface ):
    """
        A security manager provides methods for checking access and managing
        executable context and policies.
    """

    def getPrincipal():
        """
            Return the authenticated principal. 

            This is equivalent to something like::

            REQUEST['AUTHENTICATED_USER']

            but is a bit cleaner, especially if 'REQUEST' isn't handy.
        """

    def checkPermission( permission, object ):
        """
            Check whether the security context allows the given
            permission on the given object. Return a boolean value.

            Arguments:

            permission -- A permission name

            object -- The object being accessed according to the permission
        """

    def pushExecutable( anExecutableObject ):
        """
            Push an ExecutableObject onto the manager's stack, and
            activate it's custom security policy, if any.
        """

    def popExecutable( anExecutableObject ):
        """
            Pop the topmost ExecutableObject from the stack, deactivating
            any custom security policy it might have installed.
        """

    def calledByExecutable():
        """
            Return a boolean indicating whether the current request has
            invoked any IExecutableObjects.

            This can be used to determine if an object was called 
            (more or less) directly from a URL, or if it was called by
            through-the-web provided code.
        """


=== Added File Zope3/lib/python/Zope/Security/ISecurityPolicy.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 Interface import Interface

class ISecurityPolicy( Interface ):

    def checkPermission( permission
                       , object
                       , context
                       ):
        """
            Check whether the security context allows the given permission on
            the given object, returning a boolean value.

            Arguments:

            permission -- A permission name

            object -- The object being accessed according to the permission

            context -- A SecurityContext, which provides access to information
            shuch as the context stack and AUTHENTICATED_USER.
        """


=== Added File Zope3/lib/python/Zope/Security/ISecurityProxyFactory.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: ISecurityProxyFactory.py,v 1.1.4.1 2002/04/28 17:16:49 jim Exp $
"""

from Interface import Interface

class ISecurityProxyFactory(Interface):

    def __call__(object, checker=None):
        """Create a security proxy

        If a checker is given, then use it, otherwise, try to figure
        out a checker.

        If the object is already a security proxy, then it will be
        returned.
        """



=== Added File Zope3/lib/python/Zope/Security/Proxy.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: Proxy.py,v 1.1.4.1 2002/04/28 17:16:49 jim Exp $
"""

from _Proxy import getObject, getChecker
from _Proxy import _Proxy as Proxy
from Checker import ProxyFactory



=== Added File Zope3/lib/python/Zope/Security/RestrictedInterpreter.py ===
import sys

from Zope.Security.Proxy import ProxyFactory

class RestrictedInterpreter:

    ok_builtin_modules = ('audioop', 'array', 'binascii',
                          'cmath', 'errno', 'imageop',
                          'marshal', 'math', 'md5', 'operator',
                          'parser', 'regex', 'pcre', 'rotor', 'select',
                          'sha', '_sre', 'strop', 'struct', 'time')

    ok_sys_names = ('ps1', 'ps2', 'copyright', 'version',
                    'platform', 'exit', 'maxint')

    nok_builtin_names = ('open', 'file', 'reload', '__import__')

    def __init__(self, checker):
        self.checker = checker
        self.builtins = {}
        self.globals = {'__builtins__' : self.builtins}
        self.create_builtins()

    def ri_exec(self, code):
        # what is the type of code?
        exec code in self.globals

    def create_builtins(self):
        import __builtin__
        for k, v in __builtin__.__dict__.iteritems():
            if k not in self.nok_builtin_names:
                self.builtins[k] = ProxyFactory(v, self.checker)
        self.builtins['__import__'] = ProxyFactory(self.ri_import)

    def ri_import(self, name, globals, locals, fromlist):
        # XXX handle fromlist
        return sys.modules[name]


=== Added File Zope3/lib/python/Zope/Security/SecurityContext.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.
# 
##############################################################################
""" Default ISecurityContext impl """

from ISecurityContext import ISecurityContext

class SecurityContext:
    """
        Capture transient request-specific security information.

        Attribute( 'stack'
                , 'A stack of elements, each either be an ExecutableObject'
                'or a tuple consisting of an ExecutableObject and a'
                'custom SecurityPolicy.'
                )

        Attribute( 'user'
                , 'The AUTHENTICATED_USER for the request.'
                )
    """

    def __init__( self, user ):

        self.stack       = []
        self.user        = user
        self.objectCache = {}


=== Added File Zope3/lib/python/Zope/Security/SecurityManagement.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.
# 
##############################################################################
""" Default ISecurityManagement implementation """

from ISecurityManagement import ISecurityManagement, ISecurityManagementSetup
from SecurityManager import SecurityManager
from SecurityManager import setSecurityPolicy as _setSecurityPolicy
from SecurityContext import SecurityContext

__implements__ = ( ISecurityManagement, ISecurityManagementSetup )

try:
    import thread
except:
    get_ident=lambda: 0
else:
    get_ident=thread.get_ident

_managers={}

from Zope.Testing.CleanUp import addCleanUp
addCleanUp(_managers.clear)


#
#   ISecurityManagementSetup implementation
#
def newSecurityManager( user ):
    """
        Install a new SecurityManager, using user.  Return the
        old SecurityManager, if any, or None.
    """
    return replaceSecurityManager( SecurityManager( SecurityContext( user ) ) )

def replaceSecurityManager( old_manager ):
    """
        Replace the SecurityManager with 'old_manager', which
        must implement ISecurityManager.
    """
    thread_id = get_ident()
    old = _managers.get( thread_id, None )
    _managers[ thread_id ] = old_manager
    return old

def noSecurityManager():
    """
        Clear any existing SecurityManager.
    """
    try:
        del _managers[ get_ident() ]
    except KeyError:
        pass

#
#   ISecurityManagement implementation
#
def getSecurityManager():
    """
        Get a SecurityManager (create if needed).
    """
    thread_id = get_ident()
    manager=_managers.get( thread_id, None )

    if manager is None:
        newSecurityManager( None )
        manager=_managers.get( thread_id, None )
        
    return manager

def setSecurityPolicy( aSecurityPolicy ):
    """
        Set the system default security policy, and return the previous
        value.

        This method should only be caused by system startup code.
        It should never, for example, be called during a web request.
    """
    return _setSecurityPolicy( aSecurityPolicy )



=== Added File Zope3/lib/python/Zope/Security/SecurityManager.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.
# 
##############################################################################
""" Default ISecurityManager implementation """

import os
from SimpleSecurityPolicies import ParanoidSecurityPolicy

MAX_STACK_SIZE = 100

_defaultPolicy = ParanoidSecurityPolicy()

def _clear():
    global _defaultPolicy
    _defaultPolicy = ParanoidSecurityPolicy()

from Zope.Testing.CleanUp import addCleanUp
addCleanUp(_clear)


def setSecurityPolicy( aSecurityPolicy ):
    """
        Set the system default security policy. 

        This method should only be caused by system startup code. It should
        never, for example, be called during a web request.
    """
    global _defaultPolicy

    last, _defaultPolicy = _defaultPolicy, aSecurityPolicy

    return last

from ISecurityManager import ISecurityManager

class SecurityManager:
    """
        A security manager provides methods for checking access and managing
        executable context and policies.
    """
    __implements__ = ISecurityManager
    
    def __init__( self, context ):
        self._context = context
        self._policy = None

    def _getPolicy( self ):
        """
            Find current policy, or default.
        """
        policy = self._policy
        if policy is None:
            policy = _defaultPolicy
        return policy

    #
    #   ISecurityManager implementation
    #
    def getPrincipal( self ):
        """
            Return the authenticated user. 

            This is equivalent to something like::

            REQUEST['AUTHENTICATED_USER']

            but is a bit cleaner, especially if 'REQUEST' isn't handy.
        """
        return self._context.user

    def checkPermission( self, permission, object ):
        """
            Check whether the security context allows the given
            permission on the given object. Return a boolean value.

            Arguments:

            permission -- A permission name

            object -- The object being accessed according to the permission
        """
        return self._getPolicy().checkPermission( permission, object
                                              , self._context )

    def pushExecutable( self, anExecutableObject ):
        """
            Push an ExecutableObject onto the manager's stack, and
            activate it's custom security policy, if any.
        """
        stack=self._context.stack

        if len( stack ) >= MAX_STACK_SIZE:
            raise SystemError, 'Excessive recursion'

        stack.append( anExecutableObject )
        p = getattr( anExecutableObject, '_customSecurityPolicy', None )

        if p is not None:
            p = p()

        self._policy = p

    def popExecutable( self, anExecutableObject ):
        """
            Pop the topmost ExecutableObject from the stack, deactivating
            any custom security policy it might have installed.
        """
        stack=self._context.stack

        if not stack:
            return

        top = stack[-1]

        if top is anExecutableObject:
            del stack[-1]
        else:
            indexes = range(len(stack))
            indexes.reverse()
            for i in indexes:
                top=stack[i]
                if top is anExecutableObject:
                    del stack[i:]
                    break
            else:
                return

        if stack:

            top = stack[-1]
            p = getattr( top, '_customSecurityPolicy', None )

            if p is not None:
                p=p()
            self._policy=p

        else:
            self._policy=None

    def calledByExecutable( self ):
        """
            Return a boolean indicating whether the current request has
            invoked any IExecutableObjects.

            This can be used to determine if an object was called 
            (more or less) directly from a URL, or if it was called by
            through-the-web provided code.
        """
        return len( self._context.stack )



=== Added File Zope3/lib/python/Zope/Security/SimpleSecurityPolicies.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.
# 
##############################################################################
""" Simple ISecurityPolicy implementations."""

from ISecurityPolicy import ISecurityPolicy
from Zope.Exceptions import Unauthorized

class ParanoidSecurityPolicy:
    """
        Deny all access.
    """
    __implements__ = ISecurityPolicy

    def checkPermission( sel, permission, object, context ):
        if (context.user is None   # no user
            and not context.stack  # no untrusted code
            ):
            return 1 # Nobody not to trust!
        
        return 0

class PermissiveSecurityPolicy:
    """
        Allow all access
    """
    __implements__ = ISecurityPolicy

    def checkPermission( self, permission, object, context ):
        return 1



=== Added File Zope3/lib/python/Zope/Security/_Proxy.c === (690/790 lines abridged)
/*
 * Security proxy.
 */

#include <Python.h>

typedef struct {
	PyObject_HEAD
	PyObject *proxy_object;
	PyObject *proxy_checker;
} ProxyObject;

#define Proxy_Check(proxy) \
	PyObject_TypeCheck(proxy, &ProxyType)

#define Proxy_GetObject(proxy) \
        (((ProxyObject *)proxy)->proxy_object)

#define Proxy_GetChecker(proxy) \
        (((ProxyObject *)proxy)->proxy_checker)


staticforward PyTypeObject ProxyType;


/*
 * Machinery to call the checker.
 */

typedef PyObject *(*function1)(PyObject *);

static int
check(PyObject *checker, char *opname, PyObject *object)
{
	PyObject *checked;

	checked = PyObject_CallMethod(checker, "check", "(Os)",
				      object, opname);
	if (checked == NULL)
		return 0;
	Py_DECREF(checked);
	return 1;
}

static int
checkattr(PyObject *checker, char *check_method,
	  PyObject *object, PyObject *name)
{
	PyObject *checked;


[-=- -=- -=- 690 lines omitted -=- -=- -=-]

		PyErr_SetString(PyExc_TypeError,
				"getObject argument must be a _Proxy");
		return NULL;
	}
	result = Proxy_GetObject(arg);
	Py_INCREF(result);
	return result;
}

static PyObject *
module_getChecker(PyObject *self, PyObject *arg)
{
	PyObject *result;

	if (!Proxy_Check(arg)) {
		PyErr_SetString(PyExc_TypeError,
				"getChecker argument must be a _Proxy");
		return NULL;
	}
	result = Proxy_GetChecker(arg);
	Py_INCREF(result);
	return result;
}

static PyMethodDef
module_functions[] = {
	{"getObject", module_getObject, METH_O, "get object from proxy"},
	{"getChecker", module_getChecker, METH_O, "get checker from proxy"},
	{NULL}
};

static char
module___doc__[] = "Security proxy implementation.";

void
init_Proxy(void)
{
	PyObject *m;

	ProxyType.ob_type = &PyType_Type;
	if (PyType_Ready(&ProxyType) < 0)
		return;

	m = Py_InitModule3("_Proxy", module_functions, module___doc__);
	if (m == NULL)
		return;

	Py_INCREF(&ProxyType);
	PyModule_AddObject(m, "_Proxy", (PyObject *)&ProxyType);
}


=== Added File Zope3/lib/python/Zope/Security/__init__.py ===



=== Added File Zope3/lib/python/Zope/Security/setup.py ===
#! /usr/bin/env python
##############################################################################
#
# 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 distutils.core import setup, Extension

setup(name="_Proxy", version = "0.1",
      ext_modules=[Extension("_Proxy", ["_Proxy.c"])])