[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security - ISecurityContext.py:1.1.2.1 ISecurityManagement.py:1.1.2.1 ISecurityManager.py:1.1.2.1 ISecurityPolicy.py:1.1.2.1 SecurityContext.py:1.1.2.1 SecurityManagement.py:1.1.2.1 SecurityManager.py:1.1.2.1 SimpleSecurityPolicies.py:1.1.2.1 Checker.py:1.1.2.10

Jim Fulton jim@zope.com
Sat, 27 Apr 2002 12:58:56 -0400


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

Modified Files:
      Tag: SecurityProxy-branch
	Checker.py 
Added Files:
      Tag: SecurityProxy-branch
	ISecurityContext.py ISecurityManagement.py ISecurityManager.py 
	ISecurityPolicy.py SecurityContext.py SecurityManagement.py 
	SecurityManager.py SimpleSecurityPolicies.py 
Log Message:
Moved security management modules to Zope.Security.

Added like_unto attribute to protect class so you can say that a class
has the same protections as another class::

  <security:protectClass name=".RootFolder." like_unto=".Folder." />

Added some additional calls to removeAllProxies in some component
lookup code while debugging integration of new security model.

Added protections for BTree types.


=== 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/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



=== Zope3/lib/python/Zope/Security/Checker.py 1.1.2.9 => 1.1.2.10 ===
-from Zope.Exceptions import Unauthorized, Forbidden, DuplicationError
+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
-# XXX SecurityManagement needs to move out of App
-from Zope.App.Security.SecurityManagement import getSecurityManager
+from Zope.Security.SecurityManagement import getSecurityManager
 
 # Marker for public attributes
 CheckerPublic = object()
@@ -86,7 +86,7 @@
         elif name in _always_available:
             return
 
-        raise Forbidden(name)
+        raise ForbiddenAttribute(name)
 
     def proxy(self, value):
         'See Zope.Security.IChecker.IChecker'
@@ -254,9 +254,14 @@
 }
 
 _default_checkers = {
-    dict: NamesChecker(['__getitem__', 'get', 'has_key', '__len__',
-                         'keys', 'values', 'items']),
-    list: NamesChecker(['__getitem__', 'index', 'count', '__len__']),
+    dict: NamesChecker(['__getitem__', '__len__', '__iter__',
+                        'get', 'has_key', '__copy__',
+                        'keys', 'values', 'items',
+                        'iterkeys', 'iteritems', 'itervalues', '__contains__',
+                        ]),
+    list: NamesChecker(['__getitem__', '__len__', '__iter__',
+                        'index', 'count']),
+
     # YAGNI: () a rock
     tuple: NamesChecker(['__getitem__', '__len__']),
     InstanceType: _instanceChecker,