[Zope-Checkins] CVS: Zope/lib/python/AccessControl - unauthorized.py:1.2 PermissionRole.py:1.12 SecurityManager.py:1.7 User.py:1.160 ZopeGuards.py:1.7 ZopeSecurityPolicy.py:1.14 __init__.py:1.12 cAccessControl.c:1.11 cPermissionRole.py:NONE cZopeSecurityPolicy.py:NONE pPermissionRole.py:NONE pZopeSecurityPolicy.py:NONE
Shane Hathaway
shane@digicool.com
Fri, 19 Oct 2001 11:12:56 -0400
Update of /cvs-repository/Zope/lib/python/AccessControl
In directory cvs.zope.org:/tmp/cvs-serv23442/lib/python/AccessControl
Modified Files:
PermissionRole.py SecurityManager.py User.py ZopeGuards.py
ZopeSecurityPolicy.py __init__.py cAccessControl.c
Added Files:
unauthorized.py
Removed Files:
cPermissionRole.py cZopeSecurityPolicy.py pPermissionRole.py
pZopeSecurityPolicy.py
Log Message:
- Merged cAccessControl-review-branch.
- Made some corrections to the DTML tests, which aren't currently working
in testrunner but work when run directly. ??
=== Zope/lib/python/AccessControl/unauthorized.py 1.1 => 1.2 ===
+#
+# Zope Public License (ZPL) Version 1.0
+# -------------------------------------
+#
+# Copyright (c) Digital Creations. All rights reserved.
+#
+# This license has been certified as Open Source(tm).
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions in source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions, and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# 3. Digital Creations requests that attribution be given to Zope
+# in any manner possible. Zope includes a "Powered by Zope"
+# button that is installed by default. While it is not a license
+# violation to remove this button, it is requested that the
+# attribution remain. A significant investment has been put
+# into Zope, and this effort will continue if the Zope community
+# continues to grow. This is one way to assure that growth.
+#
+# 4. All advertising materials and documentation mentioning
+# features derived from or use of this software must display
+# the following acknowledgement:
+#
+# "This product includes software developed by Digital Creations
+# for use in the Z Object Publishing Environment
+# (http://www.zope.org/)."
+#
+# In the event that the product being advertised includes an
+# intact Zope distribution (with copyright and license included)
+# then this clause is waived.
+#
+# 5. Names associated with Zope or Digital Creations must not be used to
+# endorse or promote products derived from this software without
+# prior written permission from Digital Creations.
+#
+# 6. Modified redistributions of any form whatsoever must retain
+# the following acknowledgment:
+#
+# "This product includes software developed by Digital Creations
+# for use in the Z Object Publishing Environment
+# (http://www.zope.org/)."
+#
+# Intact (re-)distributions of any official Zope release do not
+# require an external acknowledgement.
+#
+# 7. Modifications are encouraged but must be packaged separately as
+# patches to official Zope releases. Distributions that do not
+# clearly separate the patches from the original work must be clearly
+# labeled as unofficial distributions. Modifications which do not
+# carry the name Zope may be packaged in any form, as long as they
+# conform to all of the clauses above.
+#
+#
+# Disclaimer
+#
+# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
+# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# This software consists of contributions made by Digital Creations and
+# many individuals on behalf of Digital Creations. Specific
+# attributions are listed in the accompanying credits file.
+#
+##############################################################################
+"""Access control exceptions
+"""
+
+import zExceptions
+
+class Unauthorized(zExceptions.Unauthorized):
+
+ def getValueName(self):
+ v=self.value
+ n=getattr(v, 'getId', v)
+ if n is v: n=getattr(v, 'id', v)
+ if n is v: n=getattr(v, '__name__', v)
+ if n is not v:
+ if callable(n):
+ try: n = n()
+ except TypeError: pass
+ return n
+
+ c = getattr(v, '__class__', type(v))
+ c = getattr(c, '__name__', 'object')
+ return "a particular %s" % c
+
=== Zope/lib/python/AccessControl/PermissionRole.py 1.11 => 1.12 ===
__version__='$Revision$'[11:-2]
-if 0: # cAccessControl is not working
- import cAccessControl
- rolesForPermissionOn=cAccessControl.rolesForPermissionOn
- PermissionRole=cAccessControl.PermissionRole
- imPermissionRole=cAccessControl.imPermissionRole
- _what_not_even_god_should_do= cAccessControl._what_not_even_god_should_do
+_use_python_impl = 0
+import os
+if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
+ _use_python_impl = 1
else:
- import pPermissionRole
- from pPermissionRole import rolesForPermissionOn, PermissionRole
- from pPermissionRole import imPermissionRole, _what_not_even_god_should_do
+ try:
+ # C Optimization:
+ from cAccessControl import rolesForPermissionOn, \
+ PermissionRole, imPermissionRole, _what_not_even_god_should_do
+ except ImportError:
+ # Fall back to Python implementation.
+ _use_python_impl = 1
+
+
+if _use_python_impl:
+
+ import sys
+
+ from ExtensionClass import Base
+
+ import string
+
+ name_trans=filter(lambda c, an=string.letters+string.digits+'_': c not in an,
+ map(chr,range(256)))
+ name_trans=string.maketrans(string.join(name_trans,''), '_'*len(name_trans))
+
+ def rolesForPermissionOn(perm, object, default=('Manager',)):
+ """Return the roles that have the given permission on the given object
+ """
+ im=imPermissionRole()
+ im._p='_'+string.translate(perm, name_trans)+"_Permission"
+ im._d=default
+ return im.__of__(object)
+
+
+ class PermissionRole(Base):
+ """Implement permission-based roles.
+
+ Under normal circumstances, our __of__ method will be
+ called with an unwrapped object. The result will then be called
+ with a wrapped object, if the original object was wrapped.
+ To deal with this, we have to create an intermediate object.
+
+ """
+
+ def __init__(self, name, default=('Manager',)):
+ self.__name__=name
+ self._p='_'+string.translate(name,name_trans)+"_Permission"
+ self._d=default
+
+ def __of__(self, parent, None=None, getattr=getattr):
+ r=imPermissionRole()
+ r._p=self._p
+ r._pa=parent
+ r._d=self._d
+ p=getattr(parent, 'aq_inner', None)
+ if p is not None:
+ return r.__of__(p)
+ else:
+ return r
+
+
+ # This is used when a permission maps explicitly to no permission.
+ _what_not_even_god_should_do=[]
+
+ class imPermissionRole(Base):
+ """Implement permission-based roles
+ """
+
+ def __of__(self, parent,tt=type(()),st=type(''),getattr=getattr,None=None):
+ obj=parent
+ n=self._p
+ r=None
+ while 1:
+ if hasattr(obj,n):
+ roles=getattr(obj, n)
+
+ if roles is None: return 'Anonymous',
+
+ t=type(roles)
+
+ if t is tt:
+ # If we get a tuple, then we don't acquire
+ if r is None: return roles
+ return r+list(roles)
+
+ if t is st:
+ # We found roles set to a name. Start over
+ # with the new permission name. If the permission
+ # name is '', then treat as private!
+ if roles:
+ if roles != n:
+ n=roles
+ # If we find a name that is the same as the
+ # current name, we just ignore it.
+ roles=None
+ else:
+ return _what_not_even_god_should_do
+
+ elif roles:
+ if r is None: r=list(roles)
+ else: r=r+list(roles)
+
+ obj=getattr(obj, 'aq_inner', None)
+ if obj is None: break
+ obj=obj.aq_parent
+
+ if r is None: r=self._d
+
+ return r
+
+ # The following methods are needed in the unlikely case that an unwrapped
+ # object is accessed:
+ def __getitem__(self, i):
+ try:
+ v=self._v
+ except:
+ v=self._v=self.__of__(self._pa)
+ del self._pa
+
+ return v[i]
+
+ def __len__(self):
+ try:
+ v=self._v
+ except:
+ v=self._v=self.__of__(self._pa)
+ del self._pa
+
+ return len(v)
##############################################################################
# Test functions:
=== Zope/lib/python/AccessControl/SecurityManager.py 1.6 => 1.7 ===
policy=self._policy
if policy is None: policy=_defaultPolicy
- return policy.validate(accessed, container, name, value,
- self._context, roles)
+ if roles is _noroles:
+ return policy.validate(accessed, container, name, value,
+ self._context)
+ else:
+ return policy.validate(accessed, container, name, value,
+ self._context, roles)
def DTMLValidate(self, accessed=None, container=None, name=None,
value=None,md=None):
@@ -175,15 +179,19 @@
policy=self._policy
if policy is None: policy=_defaultPolicy
return policy.validate(accessed, container, name, value,
- self._context, _noroles)
+ self._context)
def validateValue(self, value, roles=_noroles):
"""Convenience for common case of simple value validation.
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
- return policy.validate(None, None, None, value,
- self._context, roles)
+ if roles is _noroles:
+ return policy.validate(None, None, None, value,
+ self._context)
+ else:
+ 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
=== Zope/lib/python/AccessControl/User.py 1.159 => 1.160 ===
from PermissionRole import _what_not_even_god_should_do, rolesForPermissionOn
import AuthEncoding
-from AccessControl import getSecurityManager, Unauthorized
+from AccessControl import getSecurityManager
+from zExceptions import Unauthorized
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager
from AccessControl.ZopeSecurityPolicy import _noroles
=== Zope/lib/python/AccessControl/ZopeGuards.py 1.6 => 1.7 ===
from SecurityInfo import secureModule
from SimpleObjectPolicies import Containers
-
-Unauthorized = 'Unauthorized'
+from zExceptions import Unauthorized
_marker = [] # Create a new marker object.
=== Zope/lib/python/AccessControl/ZopeSecurityPolicy.py 1.13 => 1.14 ===
+##############################################################################
+#
+# Zope Public License (ZPL) Version 1.0
+# -------------------------------------
+#
+# Copyright (c) Digital Creations. All rights reserved.
+#
+# This license has been certified as Open Source(tm).
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions in source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions, and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# 3. Digital Creations requests that attribution be given to Zope
+# in any manner possible. Zope includes a "Powered by Zope"
+# button that is installed by default. While it is not a license
+# violation to remove this button, it is requested that the
+# attribution remain. A significant investment has been put
+# into Zope, and this effort will continue if the Zope community
+# continues to grow. This is one way to assure that growth.
+#
+# 4. All advertising materials and documentation mentioning
+# features derived from or use of this software must display
+# the following acknowledgement:
+#
+# "This product includes software developed by Digital Creations
+# for use in the Z Object Publishing Environment
+# (http://www.zope.org/)."
+#
+# In the event that the product being advertised includes an
+# intact Zope distribution (with copyright and license included)
+# then this clause is waived.
+#
+# 5. Names associated with Zope or Digital Creations must not be used to
+# endorse or promote products derived from this software without
+# prior written permission from Digital Creations.
+#
+# 6. Modified redistributions of any form whatsoever must retain
+# the following acknowledgment:
+#
+# "This product includes software developed by Digital Creations
+# for use in the Z Object Publishing Environment
+# (http://www.zope.org/)."
+#
+# Intact (re-)distributions of any official Zope release do not
+# require an external acknowledgement.
+#
+# 7. Modifications are encouraged but must be packaged separately as
+# patches to official Zope releases. Distributions that do not
+# clearly separate the patches from the original work must be clearly
+# labeled as unofficial distributions. Modifications which do not
+# carry the name Zope may be packaged in any form, as long as they
+# conform to all of the clauses above.
+#
+#
+# Disclaimer
+#
+# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
+# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# This software consists of contributions made by Digital Creations and
+# many individuals on behalf of Digital Creations. Specific
+# attributions are listed in the accompanying credits file.
+#
+##############################################################################
+__doc__='''Define Zope\'s default security policy
-from SimpleObjectPolicies import _noroles
-if 0: # cAccessControl is not working
- import cAccessControl
+$Id$'''
+__version__='$Revision$'[11:-2]
- ZopeSecurityPolicy = cAccessControl.ZopeSecurityPolicy
+
+_use_python_impl = 0
+import os
+if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
+ _use_python_impl = 1
else:
- from pZopeSecurityPolicy import ZopeSecurityPolicy
+ try:
+ # C Optimization:
+ from cAccessControl import ZopeSecurityPolicy
+ from SimpleObjectPolicies import _noroles
+ except ImportError:
+ # Fall back to Python implementation.
+ _use_python_impl = 1
+
+
+if _use_python_impl:
+
+ from types import StringType
+
+ import SimpleObjectPolicies
+ from AccessControl import Unauthorized
+ _noroles=SimpleObjectPolicies._noroles
+ from zLOG import LOG, PROBLEM
+ from Acquisition import aq_base
+
+ from PermissionRole import _what_not_even_god_should_do, \
+ rolesForPermissionOn
+
+
+ class ZopeSecurityPolicy:
+
+ def __init__(self, ownerous=1):
+ self._ownerous=ownerous
+
+ def validate(self, accessed, container, name, value, context,
+ roles=_noroles, None=None, type=type, IntType=type(0),
+ DictType=type({}), getattr=getattr, _noroles=_noroles,
+ StringType=type(''),
+ Containers=SimpleObjectPolicies.Containers,
+ valid_aq_=('aq_parent','aq_explicit')):
+
+
+ ############################################################
+ # Provide special rules for the acquisition attributes
+ if type(name) is StringType:
+ if name[:3]=='aq_' and name not in valid_aq_:
+ return 0
+
+ containerbase = aq_base(container)
+ accessedbase=getattr(accessed, 'aq_base', container)
+
+ ############################################################
+ # If roles weren't passed in, we'll try to get them from the object
+
+ if roles is _noroles:
+ roles=getattr(value, '__roles__', _noroles)
+
+ ############################################################
+ # We still might not have any roles
+
+ if roles is _noroles:
+
+ ############################################################
+ # We have an object without roles and we didn't get a list
+ # of roles passed in. Presumably, the value is some simple
+ # object like a string or a list. We'll try to get roles
+ # from its container.
+ if container is None: return 0 # Bail if no container
+
+ roles=getattr(container, '__roles__', _noroles)
+ if roles is _noroles:
+ aq=getattr(container, 'aq_acquire', None)
+ if aq is None:
+ roles=_noroles
+ if containerbase is not accessedbase: return 0
+ else:
+ # Try to acquire roles
+ try: roles=aq('__roles__')
+ except AttributeError:
+ roles=_noroles
+ if containerbase is not accessedbase: return 0
+
+ # We need to make sure that we are allowed to
+ # get unprotected attributes from the container. We are
+ # allowed for certain simple containers and if the
+ # container says we can. Simple containers
+ # may also impose name restrictions.
+ p=Containers(type(container), None)
+ if p is None:
+ p=getattr(container,
+ '__allow_access_to_unprotected_subobjects__', None)
+
+ if p is not None:
+ tp=type(p)
+ if tp is not IntType:
+ if tp is DictType:
+ p=p.get(name, None)
+ else:
+ p=p(name, value)
+
+ if not p:
+ if (containerbase is accessedbase):
+ raise Unauthorized(name, value)
+ else:
+ return 0
+
+ if roles is _noroles: return 1
+
+ # We are going to need a security-aware object to pass
+ # to allowed(). We'll use the container.
+ value=container
+
+ # Short-circuit tests if we can:
+ try:
+ if roles is None or 'Anonymous' in roles: return 1
+ except TypeError:
+ # 'roles' isn't a sequence
+ LOG('Zope Security Policy', PROBLEM, "'%s' passed as roles"
+ " during validation of '%s' is not a sequence." % (
+ `roles`, name))
+ raise
+
+ # Check executable security
+ stack=context.stack
+ if stack:
+ eo=stack[-1]
+
+ # If the executable had an owner, can it execute?
+ if self._ownerous:
+ owner=eo.getOwner()
+ if (owner is not None) and not owner.allowed(value, roles):
+ # We don't want someone to acquire if they can't
+ # get an unacquired!
+ if accessedbase is containerbase:
+ raise Unauthorized(name, value)
+ return 0
+
+ # Proxy roles, which are a lot safer now.
+ proxy_roles=getattr(eo, '_proxy_roles', None)
+ if proxy_roles:
+ for r in proxy_roles:
+ if r in roles: return 1
+
+ # Proxy roles actually limit access!
+ if accessedbase is containerbase:
+ raise Unauthorized(name, value)
+
+ return 0
+
+
+ try:
+ if context.user.allowed(value, roles): return 1
+ except AttributeError: pass
+
+ # We don't want someone to acquire if they can't get an unacquired!
+ if accessedbase is containerbase:
+ raise Unauthorized(name, value)
+
+ return 0
+
+ def checkPermission(self, permission, object, context):
+ # XXX proxy roles and executable owner are not checked
+ roles=rolesForPermissionOn(permission, object)
+ if type(roles) is StringType:
+ roles=[roles]
+ return context.user.allowed(object, roles)
+
=== Zope/lib/python/AccessControl/__init__.py 1.11 => 1.12 ===
##############################################################################
-Unauthorized = 'Unauthorized'
+from unauthorized import Unauthorized
import DTML
del DTML
=== Zope/lib/python/AccessControl/cAccessControl.c 1.10 => 1.11 === (1568/1668 lines abridged)
#include "Acquisition.h"
+
+static void
+PyVar_Assign(PyObject **v, PyObject *e)
+{
+ Py_XDECREF(*v);
+ *v=e;
+}
+
+#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
+#define UNLESS(E) if (!(E))
#define OBJECT(o) ((PyObject *) (o))
-#ifdef win32
-#define PUBLIC
-#else
-#define PUBLIC
-#endif
+static PyObject *
+callmethod1(PyObject *self, PyObject *name, PyObject *arg)
+{
+ UNLESS(self = PyObject_GetAttr(self,name)) return NULL;
+ name = PyTuple_New(1);
+ if (name == NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ Py_INCREF(arg);
+ PyTuple_SET_ITEM(name, 0, arg);
+ ASSIGN(self, PyObject_CallObject(self, name));
+ Py_DECREF(name);
+ return self;
+}
+
+static PyObject *
+callfunction2(PyObject *function, PyObject *arg0, PyObject *arg1)
+{
+ PyObject *t, *r;
+ t = PyTuple_New(2);
+ if (t == NULL)
+ return NULL;
+ Py_INCREF(arg0);
+ Py_INCREF(arg1);
+ PyTuple_SET_ITEM(t, 0, arg0);
+ PyTuple_SET_ITEM(t, 1, arg1);
+ r = PyObject_CallObject(function, t);
+ Py_DECREF(t);
+ return r;
+}
[-=- -=- -=- 1568 lines omitted -=- -=- -=-]
PyDict_SetItemString(dict, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
- if (!ZopeSecurityPolicy_setup()) {
- Py_FatalError("Can't initialize module cAccessControl "
- "-- dependancies failed to load.");
- return;
- }
-
PyDict_SetItemString(dict, "_what_not_even_god_should_do",
_what_not_even_god_should_do);
@@ -1831,13 +1489,31 @@
PyExtensionClass_Export(dict, "imPermissionRole",
imPermissionRoleType);
- imPermissionRoleObj = PyDict_GetItemString(dict, "imPermissionRole");
+ imPermissionRoleObj = PyDict_GetItemString(dict, "imPermissionRole");
-#if ZSPCACHE
- ZSPCacheInit();
-#endif
+ /*| from SimpleObjectPolicies import Containers
+ */
- if (PyErr_Occurred())
- Py_FatalError("Can't initialize module cAccessControl");
+ IMPORT(module, "AccessControl.SimpleObjectPolicies");
+ GETATTR(module, Containers);
+ Py_DECREF(module);
+ module = NULL;
+
+ /*| from unauthorized import Unauthorized
+ */
+
+ IMPORT(module, "AccessControl.unauthorized");
+ GETATTR(module, Unauthorized);
+ Py_DECREF(module);
+ module = NULL;
+
+ /*| from zLOG import LOG, PROBLEM
+ */
+
+ IMPORT(module, "zLOG");
+ GETATTR(module, LOG);
+ GETATTR(module, PROBLEM);
+ Py_DECREF(module);
+ module = NULL;
}
=== Removed File Zope/lib/python/AccessControl/cPermissionRole.py ===
=== Removed File Zope/lib/python/AccessControl/cZopeSecurityPolicy.py ===
=== Removed File Zope/lib/python/AccessControl/pPermissionRole.py ===
=== Removed File Zope/lib/python/AccessControl/pZopeSecurityPolicy.py ===