Commit 8997c967 authored by matt@zope.com's avatar matt@zope.com

Document Template accelerations and additonal C Security Manager accelerations

from cAccessControl-review-branch.
parent a7131d9f
......@@ -89,6 +89,11 @@ Zope Changes
- API help topics can now document functions as well as classes.
- Security accelerations in c
- Accelerated C Document Template handling; Document Templates
can now do additional rendering in C, improving performance.
Bugs fixed
- WebDAV: Zope escaped nested object properties derived from
......
......@@ -148,6 +148,16 @@ Security issues
2.5+)
ZSP_OWNEROUS_SKIP
If set, will cause the Zope Security Policy to skip checks relating
to ownership, for servers on which ownership is not important.
ZSP_AUTHENTICATED_SKIP
If set, will cause the Zope Security Policy to skip checks relating
to authentication, for servers which serve only anonymous content.
DISALLOW_LOCAL_PRODUCTS
unknown
......
......@@ -84,26 +84,42 @@
##############################################################################
'''Add security system support to Document Templates
$Id: DTML.py,v 1.7 2001/06/21 17:16:31 shane Exp $'''
__version__='$Revision: 1.7 $'[11:-2]
$Id: DTML.py,v 1.8 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.8 $'[11:-2]
from DocumentTemplate import DT_Util
import SecurityManagement, string, math, whrandom, random
import DocumentTemplate.sequence
from ZopeGuards import guarded_getattr, guarded_getitem, _marker
from ZopeGuards import guarded_getattr, guarded_getitem
class RestrictedDTML:
'''
A mix-in for derivatives of DT_String.String that adds Zope security.
'''
def guarded_getattr(self, ob, name, default=_marker):
return guarded_getattr(ob, name, default)
def guarded_getattr(self, *args): # ob, name [, default]
return guarded_getattr(*args)
def guarded_getitem(self, ob, index):
return guarded_getitem(ob, index)
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import RestrictedDTMLMixin
except ImportError:
pass
else:
class RestrictedDTML(RestrictedDTMLMixin, RestrictedDTML):
'''
A mix-in for derivatives of DT_String.String that adds Zope security.
'''
# Allow access to unprotected attributes
DT_Util.TemplateDict.__allow_access_to_unprotected_subobjects__=1
string.__allow_access_to_unprotected_subobjects__=1
......
......@@ -85,8 +85,8 @@
__doc__='''Objects that implement Permission-based roles.
$Id: PermissionRole.py,v 1.12 2001/10/19 15:12:25 shane Exp $'''
__version__='$Revision: 1.12 $'[11:-2]
$Id: PermissionRole.py,v 1.13 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.13 $'[11:-2]
_use_python_impl = 0
import os
......
......@@ -85,8 +85,21 @@
__doc__='''short description
$Id: SecurityManagement.py,v 1.4 2001/07/02 16:29:55 evan Exp $'''
__version__='$Revision: 1.4 $'[11:-2]
$Id: SecurityManagement.py,v 1.5 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.5 $'[11:-2]
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
manager=SecurityManager(
thread_id,
SecurityContext(SpecialUsers.nobody))
_managers[thread_id]=manager
return manager
import SpecialUsers
from SecurityManager import SecurityManager
......@@ -110,19 +123,6 @@ def noSecurityManager():
except: pass
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
manager=SecurityManager(
thread_id,
SecurityContext(SpecialUsers.nobody))
_managers[thread_id]=manager
return manager
def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy.
......
......@@ -85,8 +85,8 @@
__doc__='''short description
$Id: SecurityManager.py,v 1.7 2001/10/19 15:12:25 shane Exp $'''
__version__='$Revision: 1.7 $'[11:-2]
$Id: SecurityManager.py,v 1.8 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.8 $'[11:-2]
import ZopeSecurityPolicy, os, string
......@@ -95,7 +95,12 @@ _noroles = ZopeSecurityPolicy._noroles
try: max_stack_size=string.atoi(os.environ.get('Z_MAX_STACK_SIZE','100'))
except: max_stack_size=100
_defaultPolicy=ZopeSecurityPolicy.ZopeSecurityPolicy()
if os.environ.has_key("ZSP_OWNEROUS_SKIP"): ownerous=0
else: ownerous=1
if os.environ.has_key("ZSP_AUTHENTICATION_SKIP"): authenticated=0
else: authenticated=1
_defaultPolicy=ZopeSecurityPolicy.ZopeSecurityPolicy(ownerous=ownerous,
authenticated=authenticated)
def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy.
......@@ -107,6 +112,7 @@ def setSecurityPolicy(aSecurityPolicy):
_defaultPolicy=aSecurityPolicy
return last
class SecurityManager:
"""A security manager provides methods for checking access and managing
executable context and policies
......@@ -120,7 +126,7 @@ class SecurityManager:
def __init__(self, thread_id, context):
self._thread_id=thread_id
self._context=context
self._policy=None
self._policy=_defaultPolicy
def validate(self, accessed=None, container=None, name=None, value=None,
roles=_noroles):
......@@ -144,7 +150,6 @@ class SecurityManager:
all the values possible.
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
if roles is _noroles:
return policy.validate(accessed, container, name, value,
self._context)
......@@ -153,7 +158,7 @@ class SecurityManager:
self._context, roles)
def DTMLValidate(self, accessed=None, container=None, name=None,
value=None,md=None):
value=None, md=None):
"""Validate access.
* THIS EXISTS FOR DTML COMPATIBILITY *
......@@ -177,7 +182,6 @@ class SecurityManager:
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
return policy.validate(accessed, container, name, value,
self._context)
......@@ -185,7 +189,6 @@ class SecurityManager:
"""Convenience for common case of simple value validation.
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
if roles is _noroles:
return policy.validate(None, None, None, value,
self._context)
......@@ -204,7 +207,6 @@ class SecurityManager:
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)
......@@ -218,7 +220,10 @@ class SecurityManager:
raise SystemError, 'Excessive recursion'
stack.append(anExecutableObject)
p=getattr(anExecutableObject, '_customSecurityPolicy', None)
if p is not None: p=p()
if p is not None:
p=p()
else:
p=_defaultPolicy
self._policy=p
def removeContext(self, anExecutableObject,
......@@ -245,10 +250,13 @@ class SecurityManager:
if stack:
top=stack[-1]
p=getattr(top, '_customSecurityPolicy', None)
if p is not None: p=p()
if p is not None:
p=p()
else:
p=_defaultPolicy
self._policy=p
else:
self._policy=None
self._policy=_defaultPolicy
def getUser(self):
"""Get the current authenticated user"""
......@@ -260,3 +268,17 @@ class SecurityManager:
return len(self._context.stack)
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import SecurityManager as cSecurityManager
except ImportError:
pass
else:
class SecurityManager(cSecurityManager, SecurityManager):
"""A security manager provides methods for checking access and managing
executable context and policies
"""
......@@ -83,7 +83,7 @@
#
##############################################################################
__version__='$Revision: 1.7 $'[11:-2]
__version__='$Revision: 1.8 $'[11:-2]
from RestrictedPython.Guards import safe_builtins, _full_read_guard, \
full_write_guard
......@@ -98,10 +98,21 @@ _marker = [] # Create a new marker object.
safe_builtins = safe_builtins.copy()
safe_builtins.update(utility_builtins)
def aq_validate(inst, obj, name, v, validate):
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import aq_validate, guarded_getattr
except ImportError:
def aq_validate(inst, obj, name, v, validate):
return validate(inst, obj, name, v)
def guarded_getattr(inst, name, default=_marker):
def guarded_getattr(inst, name, default=_marker):
if name[:1] != '_':
# Try to get the attribute normally so that unusual
# exceptions are caught early.
......@@ -121,6 +132,7 @@ def guarded_getattr(inst, name, default=_marker):
if validate(inst, inst, name, v):
return v
raise Unauthorized, name
safe_builtins['getattr'] = guarded_getattr
def guarded_hasattr(object, name):
......
......@@ -85,8 +85,8 @@
__doc__='''Define Zope\'s default security policy
$Id: ZopeSecurityPolicy.py,v 1.14 2001/10/19 15:12:25 shane Exp $'''
__version__='$Revision: 1.14 $'[11:-2]
$Id: ZopeSecurityPolicy.py,v 1.15 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.15 $'[11:-2]
_use_python_impl = 0
......@@ -119,8 +119,32 @@ if _use_python_impl:
class ZopeSecurityPolicy:
def __init__(self, ownerous=1):
def __init__(self, ownerous=1, authenticated=1):
"""Create a Zope security policy.
Two optional keyword arguments may be provided:
ownerous -- Untrusted users can create code
(e.g. Python scripts or templates),
so check that code owners can access resources.
The argument must have a truth value.
The default is true.
authenticated -- Allow access to resources based on the
privaledges of the authenticated user.
The argument must have a truth value.
The default is true.
This (somewhat experimental) option can be set
to false on sites that allow only public
(unauthenticated) access. An anticipated
scenario is a ZEO configuration in which some
clients allow only public access and other
clients allow full management.
"""
self._ownerous=ownerous
self._authenticated=authenticated
def validate(self, accessed, container, name, value, context,
roles=_noroles, None=None, type=type, IntType=type(0),
......@@ -239,7 +263,8 @@ if _use_python_impl:
try:
if context.user.allowed(value, roles): return 1
if self._authenticated and context.user.allowed(value, roles):
return 1
except AttributeError: pass
# We don't want someone to acquire if they can't get an unacquired!
......@@ -254,4 +279,3 @@ if _use_python_impl:
if type(roles) is StringType:
roles=[roles]
return context.user.allowed(object, roles)
This diff is collapsed.
......@@ -147,8 +147,8 @@ __doc__='''Conditional insertion
variable is not reevaluated.
'''
__rcs_id__='$Id: DT_If.py,v 1.16 1999/03/10 00:15:07 klm Exp $'
__version__='$Revision: 1.16 $'[11:-2]
__rcs_id__='$Id: DT_If.py,v 1.17 2001/10/26 16:07:50 matt Exp $'
__version__='$Revision: 1.17 $'[11:-2]
from DT_Util import ParseError, parse_params, name_param, str
......@@ -192,7 +192,7 @@ class If:
if elses is not None: sections.append(elses)
self.simple_form=tuple(sections)
self.simple_form=('i',)+tuple(sections)
class Unless:
name='unless'
......@@ -204,7 +204,7 @@ class Unless:
name,expr=name_param(args,'unless',1)
if expr is None: cond=name
else: cond=expr.eval
self.simple_form=(cond,None,section.blocks)
self.simple_form=('i',cond,None,section.blocks)
class Else(Unless):
# The else tag is included for backward compatibility and is deprecated.
......
......@@ -217,8 +217,8 @@ Evaluating expressions without rendering results
''' # '
__rcs_id__='$Id: DT_Var.py,v 1.44 2001/10/02 14:23:32 shane Exp $'
__version__='$Revision: 1.44 $'[11:-2]
__rcs_id__='$Id: DT_Var.py,v 1.45 2001/10/26 16:07:50 matt Exp $'
__version__='$Revision: 1.45 $'[11:-2]
from DT_Util import parse_params, name_param, str
import re, string, sys
......@@ -254,7 +254,11 @@ class Var:
if len(args)==1 and fmt=='s':
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=expr,
self.simple_form=('v', expr)
elif len(args)==2 and fmt=='s' and args.has_key('html_quote'):
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=('v', expr, 'h')
def render(self, md):
args=self.args
......@@ -353,7 +357,7 @@ class Call:
name, expr = name_param(args,'call',1)
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=expr,None
self.simple_form=('i', expr, None)
def url_quote(v, name='(Unknown name)', md={}):
......
......@@ -84,7 +84,7 @@
****************************************************************************/
static char cDocumentTemplate_module_documentation[] =
""
"\n$Id: cDocumentTemplate.c,v 1.39 2001/06/21 19:08:59 shane Exp $"
"\n$Id: cDocumentTemplate.c,v 1.40 2001/10/26 16:07:50 matt Exp $"
;
#include "ExtensionClass.h"
......@@ -94,7 +94,7 @@ static PyObject *py___call__, *py___roles__, *py_AUTHENTICATED_USER;
static PyObject *py_hasRole, *py__proxy_roles, *py_Unauthorized;
static PyObject *py_Unauthorized_fmt, *py_guarded_getattr;
static PyObject *py__push, *py__pop, *py_aq_base, *py_renderNS;
static PyObject *py___class__;
static PyObject *py___class__, *html_quote;
/* ----------------------------------------------------- */
......@@ -398,13 +398,29 @@ static PyObject *
MM_cget(MM *self, PyObject *key, int call)
{
long i;
PyObject *e, *rr, *tb;
PyObject *e, *rr;
UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while (--i >= 0)
{
e=PyList_GetItem(self->data,i);
if ((e=PyObject_GetItem(e,key)))
e=PyList_GET_ITEM(self->data,i);
if (PyDict_Check(e))
{
e=PyDict_GetItem(e, key);
Py_XINCREF(e);
}
else
{
UNLESS (e=PyObject_GetItem(e,key))
{
if (PyErr_Occurred() == PyExc_KeyError)
PyErr_Clear();
else
return NULL;
}
}
if (e)
{
if (!call) return e;
......@@ -437,17 +453,8 @@ MM_cget(MM *self, PyObject *key, int call)
}
return e;
}
PyErr_Fetch(&e, &rr, &tb);
if (e != PyExc_KeyError)
{
PyErr_Restore(e,rr,tb);
return NULL;
}
Py_XDECREF(e);
Py_XDECREF(rr);
Py_XDECREF(tb);
}
PyErr_SetObject(PyExc_KeyError,key);
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
......@@ -726,7 +733,7 @@ static int
render_blocks_(PyObject *blocks, PyObject *rendered,
PyObject *md, PyObject *mda)
{
PyObject *block;
PyObject *block, *t;
int l, i, k=0, append;
if ((l=PyList_Size(blocks)) < 0) return -1;
......@@ -735,27 +742,48 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
block=PyList_GET_ITEM(((PyListObject*)blocks), i);
append=1;
if (PyTuple_Check(block))
if (PyTuple_Check(block)
&& PyTuple_GET_SIZE(block) > 1
&& PyTuple_GET_ITEM(block, 0)
&& PyString_Check(PyTuple_GET_ITEM(block, 0)))
{
switch (PyString_AS_STRING(PyTuple_GET_ITEM(block, 0))[0])
{
int bs;
case 'v': /* var */
t=PyTuple_GET_ITEM(block,1);
bs=((PyTupleObject*)block)->ob_size;
if (t == NULL) return -1;
if (bs==1)
if (PyString_Check(t)) t=PyObject_GetItem(md, t);
else t=PyObject_CallObject(t, mda);
if (t == NULL || (! PyString_Check(t)))
{
/* Simple var */
block=PyTuple_GET_ITEM(block,0);
if (PyString_Check(block)) block=PyObject_GetItem(md,block);
else block=PyObject_CallObject(block,mda);
if (block) ASSIGN(block, PyObject_Str(block));
UNLESS(block) return -1;
if (t) ASSIGN(t, PyObject_Str(t));
UNLESS(t) return -1;
}
else
if (PyString_Check(t)
&& PyTuple_GET_SIZE(block) == 3) /* html_quote */
{
if (strchr(PyString_AS_STRING(t), '&')
&& strchr(PyString_AS_STRING(t), '<')
&& strchr(PyString_AS_STRING(t), '>')
&& strchr(PyString_AS_STRING(t), '"')
)
ASSIGN(t, PyObject_CallFunction(html_quote, "O", t));
if (t == NULL) return -1;
}
block = t;
break;
case 'i': /* if */
{
/* if */
int icond, m;
int icond, m, bs;
PyObject *cond, *n, *cache;
bs = PyTuple_GET_SIZE(block) - 1; /* subtract code */
UNLESS(cache=PyDict_New()) return -1;
cond=PyObject_GetAttr(md,py__push);
if (cond) ASSIGN(cond, PyObject_CallFunction(cond,"O",cache));
......@@ -767,7 +795,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
m=bs-1;
for (icond=0; icond < m; icond += 2)
{
cond=PyTuple_GET_ITEM(block,icond);
cond=PyTuple_GET_ITEM(block,icond+1);
if (PyString_Check(cond))
{
/* We have to be careful to handle key errors here */
......@@ -804,7 +832,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
if (PyObject_IsTrue(cond))
{
Py_DECREF(cond);
block=PyTuple_GET_ITEM(block,icond+1);
block=PyTuple_GET_ITEM(block,icond+1+1);
if (block!=Py_None &&
render_blocks_(block, rendered, md, mda) < 0)
return if_finally(md,1);
......@@ -815,7 +843,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
}
if (icond==m)
{
block=PyTuple_GET_ITEM(block,icond);
block=PyTuple_GET_ITEM(block,icond+1);
if (block!=Py_None &&
render_blocks_(block, rendered, md, mda) < 0)
return if_finally(md,1);
......@@ -823,6 +851,13 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
if (if_finally(md,0) == -2) return -1;
}
break;
default:
PyErr_Format(PyExc_ValueError,
"Invalid DTML command code, %s",
PyString_AS_STRING(PyTuple_GET_ITEM(block, 0)));
return -1;
}
}
else if (PyString_Check(block))
{
......@@ -904,10 +939,14 @@ void
initcDocumentTemplate(void)
{
PyObject *m, *d;
char *rev="$Revision: 1.39 $";
char *rev="$Revision: 1.40 $";
DictInstanceType.ob_type=&PyType_Type;
UNLESS (html_quote = PyImport_ImportModule("html_quote")) return;
ASSIGN(html_quote, PyObject_GetAttrString(html_quote, "html_quote"));
UNLESS (html_quote) return;
UNLESS(py_isDocTemp=PyString_FromString("isDocTemp")) return;
UNLESS(py_renderNS=PyString_FromString("__render_with_namespace__")) return;
UNLESS(py_blocks=PyString_FromString("blocks")) return;
......@@ -946,6 +985,4 @@ initcDocumentTemplate(void)
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred())
Py_FatalError("can't initialize module cDocumentTemplate");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment