[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security - Checker.py:1.2 IChecker.py:1.2 ISecurityContext.py:1.2 ISecurityManagement.py:1.2 ISecurityManager.py:1.2 ISecurityPolicy.py:1.2 ISecurityProxyFactory.py:1.2 Proxy.py:1.2 RestrictedBuiltins.py:1.2 RestrictedInterpreter.py:1.2 SecurityContext.py:1.2 SecurityManagement.py:1.2 SecurityManager.py:1.2 SimpleSecurityPolicies.py:1.2 _Proxy.c:1.2 __init__.py:1.2 setup.py:1.2
Jim Fulton
jim@zope.com
Mon, 10 Jun 2002 19:30:06 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/Security
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/Security
Added Files:
Checker.py IChecker.py ISecurityContext.py
ISecurityManagement.py ISecurityManager.py ISecurityPolicy.py
ISecurityProxyFactory.py Proxy.py RestrictedBuiltins.py
RestrictedInterpreter.py SecurityContext.py
SecurityManagement.py SecurityManager.py
SimpleSecurityPolicies.py _Proxy.c __init__.py setup.py
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.
=== Zope3/lib/python/Zope/Security/Checker.py 1.1 => 1.2 ===
+from Zope.Exceptions \
+ import Unauthorized, ForbiddenAttribute, Forbidden, DuplicationError
+from Interface.IInterface import IInterface
+from Interface import Interface
+from _Proxy import _Proxy as Proxy
+from ISecurityProxyFactory import ISecurityProxyFactory
+from Zope.Security.SecurityManagement import getSecurityManager
+import sys, os, types
+
+if os.environ.get('ZOPE_WATCH_CHECKERS'):
+ WATCH_CHECKERS = 1
+else:
+ WATCH_CHECKERS = 0
+
+
+# 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 = getattr(object, '__Security_checker__', None)
+
+ 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'
+
+ if WATCH_CHECKERS:
+ print >> sys.stderr, ('Checking %r.%s:' % (object, name)),
+
+ # We have the information we need already
+ permission = self.__permission_func(name)
+ if permission:
+ if permission is CheckerPublic:
+ if WATCH_CHECKERS:
+ print >> sys.stderr, 'Public.'
+ return # Public
+ manager = getSecurityManager()
+ if manager.checkPermission(permission, object):
+ if WATCH_CHECKERS:
+ print >> sys.stderr, 'Granted.'
+ return
+ else:
+ if WATCH_CHECKERS:
+ print >> sys.stderr, 'Unauthorized.'
+ raise Unauthorized(name=name)
+ elif name in _always_available:
+ if WATCH_CHECKERS:
+ print >> sys.stderr, 'Always available.'
+ return
+
+ if WATCH_CHECKERS:
+ print >> sys.stderr, 'Forbidden.'
+
+ raise ForbiddenAttribute(name)
+
+ def proxy(self, value):
+ 'See Zope.Security.IChecker.IChecker'
+ # Now we need to create a proxy
+
+ checker = getattr(value, '__Security_checker__', None)
+ if checker is None:
+ 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 InterfaceChecker(interface, permission_id=CheckerPublic):
+ return NamesChecker(interface.names(1), permission_id)
+
+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 or checker is None:
+ 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__',
+ '__bases__'])
+
+_interfaceChecker = NamesChecker(['__str__', '__repr__', '__name__',
+ '__module__', '__bases__',
+ 'isImplementedBy', 'extends'])
+
+BasicTypes = {
+ object: NoProxy,
+ int: NoProxy,
+ float: NoProxy,
+ long: NoProxy,
+ complex: NoProxy,
+ types.NoneType: 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__']),
+ types.InstanceType: _instanceChecker,
+ Proxy: NoProxy,
+ types.ClassType: _classChecker,
+ types.FunctionType: _callableChecker,
+ types.MethodType: _callableChecker,
+ types.BuiltinFunctionType: _callableChecker,
+ types.BuiltinMethodType: _callableChecker,
+ type: _typeChecker,
+ types.ModuleType: _moduleChecker,
+ type(iter([])): NamesChecker(['next']),
+ type(Interface): _interfaceChecker,
+ }
+
+
+def _clear():
+ _checkers.clear()
+ _checkers.update(_default_checkers)
+ _checkers.update(BasicTypes)
+
+_clear()
+
+from Zope.Testing.CleanUp import addCleanUp
+addCleanUp(_clear)
=== Zope3/lib/python/Zope/Security/IChecker.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+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.
+ """
=== Zope3/lib/python/Zope/Security/ISecurityContext.py 1.1 => 1.2 ===
+#
+# 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.'
+ )
+
=== Zope3/lib/python/Zope/Security/ISecurityManagement.py 1.1 => 1.2 ===
+#
+# 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.
+ """
=== Zope3/lib/python/Zope/Security/ISecurityManager.py 1.1 => 1.2 ===
+#
+# 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.
+ """
=== Zope3/lib/python/Zope/Security/ISecurityPolicy.py 1.1 => 1.2 ===
+#
+# 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.
+ """
=== Zope3/lib/python/Zope/Security/ISecurityProxyFactory.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+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.
+ """
+
=== Zope3/lib/python/Zope/Security/Proxy.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from _Proxy import getObject, getChecker
+from _Proxy import _Proxy as Proxy
+from Checker import ProxyFactory, Checker as _trustedChecker
+
+def trustedRemoveSecurityProxy(object):
+ if ((type(object) is Proxy) and
+ isinstance(getChecker(object), _trustedChecker)
+ ):
+ return getObject(object)
+
+ return object
+
+
+def getTestProxyItems(proxy):
+ """Try to get checker names and permissions for testing
+
+ If this succeeds, a sorted sequence of items is returned,
+ otherwise, None is retirned.
+ """
+ checker = getChecker(proxy)
+ func = checker.getPermission_func()
+ dict = getattr(func, '__self__', None)
+ if dict is None:
+ return None
+ items = dict.items()
+ items.sort()
+ return items
+
=== Zope3/lib/python/Zope/Security/RestrictedBuiltins.py 1.1 => 1.2 ===
+#
+# 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
+#
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+import sys
+
+def RestrictedBuiltins():
+
+ from Proxy import ProxyFactory
+ from Checker import NamesChecker
+
+ # It's better to say what is safe than it say what is not safe
+ _safe = [
+ 'ArithmeticError', 'AssertionError', 'AttributeError',
+ 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError',
+ 'Exception', 'FloatingPointError', 'IOError', 'ImportError',
+ 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
+ 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented',
+ 'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning',
+ 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError',
+ 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
+ 'SystemExit', 'TabError', 'TypeError', 'UnboundLocalError',
+ 'UnicodeError', 'UserWarning', 'ValueError', 'Warning',
+ 'ZeroDivisionError',
+ '__debug__', '__doc__', '__name__', 'abs', 'apply', 'buffer',
+ 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile',
+ 'complex', 'copyright', 'credits', 'delattr', 'dict',
+ 'divmod', 'eval', 'filter', 'float', 'getattr', 'globals',
+ 'hasattr', 'hash', 'hex', 'id', 'int', 'isinstance',
+ 'issubclass', 'iter', 'len', 'license', 'list', 'locals',
+ 'long', 'map', 'max', 'min', 'object', 'oct', 'ord', 'pow',
+ 'property', 'quit', 'range', 'reduce', 'repr', 'round',
+ 'setattr', 'slice', 'staticmethod', 'str', 'super', 'tuple',
+ 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip',
+ ]
+
+ # XXX dir segfaults with a seg fault due to a bas tuple check in
+ # merge_class_dict in object.c. The assert macro seems to be doing
+ # the wrong think. Basically, if an object has bases, then bases
+ # is assumed to be a tuple.
+
+ # Anything that accesses an external file is a no no:
+ # 'open', 'execfile', 'file'
+
+ # We dont want restricted code to call exit: 'SystemExit', 'exit'
+
+ # Other no nos:
+ # help prints
+ # input does I/O
+ # raw_input does I/O
+ # intern's effect is too global
+ # reload does import, XXX doesn't it use __import__?
+
+ _builtinTypeChecker = NamesChecker(
+ ['__str__', '__repr__', '__name__', '__module__',
+ '__bases__', '__call__'])
+
+ import __builtin__
+
+ builtins = {}
+ for name in _safe:
+ value = getattr(__builtin__, name)
+ if isinstance(value, type):
+ value = ProxyFactory(value, _builtinTypeChecker)
+ else:
+ value = ProxyFactory(value)
+ builtins[name] = value
+
+ def __import__(name, globals=None, locals=None, fromlist=()):
+ # Waaa, we have to emulate __import__'s weird semantics.
+ try:
+ module = sys.modules[name]
+ if fromlist:
+ return module
+
+ l = name.find('.')
+ if l < 0:
+ return module
+
+ return sys.modules[name[:l]]
+
+ except KeyError:
+ raise ImportError(name)
+
+ builtins['__import__'] = ProxyFactory(__import__)
+
+ return builtins
+
+RestrictedBuiltins = RestrictedBuiltins()
=== Zope3/lib/python/Zope/Security/RestrictedInterpreter.py 1.1 => 1.2 ===
+#
+# 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
+#
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+import sys
+
+from Proxy import ProxyFactory
+from RestrictedBuiltins import RestrictedBuiltins
+
+class RestrictedInterpreter:
+
+ def __init__(self):
+ self.globals = {'__builtins__' : RestrictedBuiltins}
+
+ def ri_exec(self, code):
+ # what is the type of code?
+ exec code in self.globals
=== Zope3/lib/python/Zope/Security/SecurityContext.py 1.1 => 1.2 ===
+#
+# 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 = {}
=== Zope3/lib/python/Zope/Security/SecurityManagement.py 1.1 => 1.2 ===
+#
+# 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 )
+
=== Zope3/lib/python/Zope/Security/SecurityManager.py 1.1 => 1.2 ===
+#
+# 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 )
+
=== Zope3/lib/python/Zope/Security/SimpleSecurityPolicies.py 1.1 => 1.2 ===
+#
+# 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/_Proxy.c 1.1 => 1.2 === (801/901 lines abridged)
+ * Security proxy.
+ */
+
+#include <Python.h>
+
+static PyObject *__class__str = 0, *__name__str = 0, *__module__str = 0;
+
+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;
[-=- -=- -=- 801 lines omitted -=- -=- -=-]
+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;
+
+ __class__str = PyString_FromString("__class__");
+ if (! __class__str) return;
+
+ __name__str = PyString_FromString("__name__");
+ if (! __name__str) return;
+
+ __module__str = PyString_FromString("__module__");
+ if (! __module__str) return;
+
+ 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);
+}
=== Zope3/lib/python/Zope/Security/__init__.py 1.1 => 1.2 ===
=== Zope3/lib/python/Zope/Security/setup.py 1.1 => 1.2 ===
+##############################################################################
+#
+# 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"])])