[Zope-Checkins] CVS: Zope/lib/python/AccessControl - PermissionRole.py:1.10.30.1 User.py:1.158.18.1 ZopeGuards.py:1.6.28.1 ZopeSecurityPolicy.py:1.12.30.1 __init__.py:1.11.58.1 cAccessControl.c:1.10.12.1 cPermissionRole.py:NONE cZopeSecurityPolicy.py:NONE pPermissionRole.py:NONE pZopeSecurityPolicy.py:NONE
Jim Fulton
jim@zope.com
Mon, 15 Oct 2001 17:23:14 -0400
Update of /cvs-repository/Zope/lib/python/AccessControl
In directory cvs.zope.org:/tmp/cvs-serv21338/lib/python/AccessControl
Modified Files:
Tag: cAccessControl-review-branch
PermissionRole.py User.py ZopeGuards.py ZopeSecurityPolicy.py
__init__.py cAccessControl.c
Removed Files:
Tag: cAccessControl-review-branch
cPermissionRole.py cZopeSecurityPolicy.py pPermissionRole.py
pZopeSecurityPolicy.py
Log Message:
Checking in changes made during review of new cAccessControl
implementation. The changes fall into two classes:
- Changes made to C code
- Switching to use of Unauthorized class exception.
This one is especially significant. :)
=== Zope/lib/python/AccessControl/PermissionRole.py 1.10 => 1.10.30.1 ===
__version__='$Revision$'[11:-2]
-import cAccessControl
-rolesForPermissionOn=cAccessControl.rolesForPermissionOn
-PermissionRole=cAccessControl.PermissionRole
-imPermisionRole=cAccessControl.imPermissionRole
-_what_not_even_god_should_do= cAccessControl._what_not_even_god_should_do
+try:
+ import cAccessControl
+
+except ImportError:
+ # Fall back to Python implementation
+
+ 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)
+
+else:
+ # C Optimizations:
+ rolesForPermissionOn=cAccessControl.rolesForPermissionOn
+ PermissionRole=cAccessControl.PermissionRole
+ imPermisionRole=cAccessControl.imPermissionRole
+ _what_not_even_god_should_do= cAccessControl._what_not_even_god_should_do
##############################################################################
# Test functions:
=== Zope/lib/python/AccessControl/User.py 1.158 => 1.158.18.1 ===
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.6.28.1 ===
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.12 => 1.12.30.1 ===
+##############################################################################
+#
+# 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
-import cAccessControl
+$Id$'''
+__version__='$Revision$'[11:-2]
-ZopeSecurityPolicy = cAccessControl.ZopeSecurityPolicy
+
+try:
+ import cAccessControl
+except:
+ # Fall back on Python implementation
+
+ 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):
+ roles=rolesForPermissionOn(permission, object)
+ if type(roles) is StringType:
+ roles=[roles]
+ return context.user.allowed(object, roles)
+
+else:
+ # C Optimization
+ from SimpleObjectPolicies import _noroles
+ ZopeSecurityPolicy = cAccessControl.ZopeSecurityPolicy
=== Zope/lib/python/AccessControl/__init__.py 1.11 => 1.11.58.1 ===
##############################################################################
-Unauthorized = 'Unauthorized'
+from unauthorized import Unauthorized
import DTML
del DTML
=== Zope/lib/python/AccessControl/cAccessControl.c 1.10 => 1.10.12.1 === (1121/1221 lines abridged)
#include "Acquisition.h"
-#define OBJECT(o) ((PyObject *) (o))
-#ifdef win32
-#define PUBLIC
-#else
-#define PUBLIC
-#endif
+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))
/*
** Structures
@@ -84,23 +88,6 @@
PyObject *_v;
} imPermissionRole;
-/* ZSPCACHE does NOT work securely; don't turn it on! */
-#define ZSPCACHE 0
-
-#if ZSPCACHE
-typedef struct {
- long accessed;
- long container;
- long name;
- long value;
- long context;
- long roles;
- PyObject *result;
-} ZSPCacheLine;
-
-#define ZSPCACHEENTRIES 512
-#endif
-
/*
** Prototypes
*/
@@ -111,20 +98,19 @@
static void ZopeSecurityPolicy_dealloc(ZopeSecurityPolicy *self);
[-=- -=- -=- 1121 lines omitted -=- -=- -=-]
** ----------------------------------------------------------------
*/
-
-PUBLIC void initcAccessControl(void) {
+void initcAccessControl(void) {
PyObject *module;
PyObject *dict;
char *rev = "$Revision$";
@@ -1787,9 +1514,15 @@
aq_init();
+ if (ZopeSecurityPolicy_setup() < 0) return;
+
ZopeSecurityPolicyType.tp_getattro =
(getattrofunc) PyExtensionClassCAPI->getattro;
+
+
+
+
module = Py_InitModule4("cAccessControl",
cAccessControl_methods,
"$Id: %\n",
@@ -1813,12 +1546,6 @@
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);
@@ -1832,12 +1559,5 @@
imPermissionRoleType);
imPermissionRoleObj = PyDict_GetItemString(dict, "imPermissionRole");
-
-#if ZSPCACHE
- ZSPCacheInit();
-#endif
-
- if (PyErr_Occurred())
- Py_FatalError("Can't initialize module cAccessControl");
}
=== 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 ===