[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - IUser.py:1.1.2.1 SecurityContext.py:1.1.2.1 SecurityManagement.py:1.1.2.1 SecurityManager.py:1.1.2.1 User.py:1.1.2.1

Tres Seaver tseaver@zope.com
Fri, 30 Nov 2001 16:06:40 -0500


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

Added Files:
      Tag: Zope-3x-branch
	IUser.py SecurityContext.py SecurityManagement.py 
	SecurityManager.py User.py 
Log Message:
 - Stub in more of the security framework.

=== Added File Zope3/lib/python/Zope/App/Security/IUser.py ===
# Copyright (c) 2001 Zope Coporation and Contributors.  All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 
# FOR A PARTICULAR PURPOSE.

""" Stock user interface """

from Interface import Interface

class IUser( Interface ):
    """
    """
    def getUserName():
        """
        """


=== Added File Zope3/lib/python/Zope/App/Security/SecurityContext.py ===
# Copyright (c) 2001 Zope Coporation and Contributors.  All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 
# FOR A PARTICULAR PURPOSE.

""" 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/App/Security/SecurityManagement.py ===
# Copyright (c) 2001 Zope Coporation and Contributors.  All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 
# FOR A PARTICULAR PURPOSE.

""" Default ISecurityManagement implementation """

from ISecurityManagement import ISecurityManagement, ISecurityManagementSetup
from SecurityManager import SecurityManager
from SecurityContext import SecurityContext

__implements__ = ( ISecurityManagement, ISecurityManagementSetup )

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

_managers={}

#
#   ISecurityManagementSetup implementation
#
def newSecurityManager( user ):
    """
        Install a new SecurityManager, using user.  Return the
        old SecurityManager, if any, or None.
    """
    thread_id = get_ident()
    old = _managers.get( thread_id, None )
    _managers[ thread_id ] = SecurityManager( thread_id
                                            , SecurityContext( user )
                                            )
    return old

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

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:
        import User
        manager = newSecurityManager( User.UserWithName( 'Anonymous User' ) )
        
    return manager

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.
    """
    SecurityManager.setSecurityPolicy( aSecurityPolicy )



=== Added File Zope3/lib/python/Zope/App/Security/SecurityManager.py ===
# Copyright (c) 2001 Zope Coporation and Contributors.  All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 
# FOR A PARTICULAR PURPOSE.

""" Default ISecurityManager implementation """

import ZopeSecurityPolicy, os, string

max_stack_size = 100

_defaultPolicy = ZopeSecurityPolicy.ZopeSecurityPolicy()

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, thread_id, context ):
        self._thread_id = thread_id
        self._context = context
        self._policy = None

    def validate( self, accessed, container, name, value, roles ):
        """
            Validate access.

            Arguments:

            accessed -- the object that was being accessed

            container -- the object the value was found in

            name -- The attribute name used to access the value

            value -- The value retrieved though the access.

            roles -- an (optional) list of roles to use when authorizing
                     access
        
            The arguments may be provided as keyword arguments. Some of
            these arguments may be ommitted, however, the policy may
            reject access in some cases when arguments are ommitted.
            It is best to provide all the values possible.

            A boolean value is returned indicating whether the value is
            accessible. An Unauthorized exception may be raised in some
            cases.
        """
        policy = self._policy
        if policy is None: policy = _defaultPolicy
        return policy.validate( accessed, container, name, value,
                                self._context, roles )

    def validateValue( self, value, roles ):
        """
            Validate access. This is a shortcut for the common case of
            validating a value without providing access information.

            A boolean value is returned indicating whether the value is
            accessible. An Unauthorized exception may be raised in some
            cases.
        """
        policy = self._policy
        if policy is None:
            policy = _defaultPolicy
        return policy.validate( None, None, None, value, self._context, roles )

    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
        """
        policy = self._policy
        if policy is None:
            policy = _defaultPolicy
        return policy.checkPermission( permission, object, self._context )

    def addContext( self, anExecutableObject ):
        """
            Add an ExecutableObject to the current security
            context.

            There is no return.
        """
        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 removeContext( self, anExecutableObject ):
        """
            Remove an ExecutableObject.

            There is no return.
        """
        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 getUser( 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 calledByExecutable( self ):
        """
            Determine if called through an ExecutableObject.

            A true value is returned if any ExecutableObjects 
            have (directly or indirectly) called the current method and
            a true value otherwise.

            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.

            (The value returned by the initial implementation
            is actually size of the context stack, which is the depth
            of the through-the-web call stack.  Is this information
            valuable enough to promise in the interface?)     
        """
        return len( self._context.stack )



=== Added File Zope3/lib/python/Zope/App/Security/User.py ===
# Copyright (c) 2001 Zope Coporation and Contributors.  All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 1.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 
# FOR A PARTICULAR PURPOSE.

""" Default IUser implementations """

from IUser import IUser

class UserWithName:

    __implements__ = IUser

    def __init__( self, user_name ):
        self._user_name = user_name

    def getUserName( self ):
        return self._user_name

'''
class UnrestrictedUser( UserWithName ):

    __implements__( IUser )

unrestricted = UnrestrictedUser( 'System' )

class AnonymousUser( UserWithName ):

    __implements__( IUser )

nobody = AnonymousUser( 'Anonymous' )
'''