[Zope-Checkins] CVS: Zope2 - DT_In.py:1.48.4.3 DT_String.py:1.39.54.1 DT_Util.py:1.72.18.6 DT_With.py:1.11.142.1 DocumentTemplate.py:1.10.160.2 cDocumentTemplate.c:1.35.60.1 pDocumentTemplate.py:1.27.40.1

shane@digicool.com shane@digicool.com
Thu, 26 Apr 2001 18:25:40 -0400 (EDT)


Update of /cvs-repository/Zope2/lib/python/DocumentTemplate
In directory korak:/tmp/cvs-serv10837/lib/python/DocumentTemplate

Modified Files:
      Tag: RestrictedPythonBranch
	DT_In.py DT_String.py DT_Util.py DT_With.py 
	DocumentTemplate.py cDocumentTemplate.c pDocumentTemplate.py 
Log Message:
Modified the way DTML namespaces implement security: now there is an
attribute of TemplateDicts called read_guard which implements the
"read guard" interface as defined by RestrictedPython.



--- Updated File DT_In.py in package Zope2 --
--- DT_In.py	2001/04/25 20:26:35	1.48.4.2
+++ DT_In.py	2001/04/26 22:25:08	1.48.4.3
@@ -595,7 +595,7 @@
             else:
                 result = []
                 append=result.append
-                validate=md.validate
+                read_guard = md.read_guard
                 for index in range(first,end):
                     # preset
                     kw['previous-sequence']= 0
@@ -625,17 +625,17 @@
         
                     if index==last: kw['sequence-end']=1
 
-                    client=sequence[index]
-
-                    if validate is not None:
-                        try: vv=validate(sequence,sequence,None,client,md)
-                        except: vv=0
-                        if not vv:
+                    if read_guard is not None:
+                        try: client = read_guard(sequence)[index]
+                        except ValidationError, vv:
                             if (params.has_key('skip_unauthorized') and
                                 params['skip_unauthorized']):
                                 if index==first: kw['sequence-start']=0
                                 continue
-                            raise ValidationError, index
+                            raise ValidationError, '(item %s): %s' % (
+                                index, vv)
+                    else:
+                        client = sequence[index]
 
                     kw['sequence-index']=index
                     if type(client)==TupleType and len(client)==2:
@@ -708,20 +708,20 @@
         try:
                 result = []
                 append=result.append
-                validate=md.validate
+                read_guard = md.read_guard
                 for index in range(l):
                     if index==last: kw['sequence-end']=1
-                    client=sequence[index]
-
-                    if validate is not None:
-                        try: vv=validate(sequence,sequence,None,client,md)
-                        except: vv=0
-                        if not vv:
-                            if (self.args.has_key('skip_unauthorized') and
-                                self.args['skip_unauthorized']):
-                                if index==1: kw['sequence-start']=0
+                    if read_guard is not None:
+                        try: client = read_guard(sequence)[index]
+                        except ValidationError, vv:
+                            if (params.has_key('skip_unauthorized') and
+                                params['skip_unauthorized']):
+                                if index==first: kw['sequence-start']=0
                                 continue
-                            raise ValidationError, index
+                            raise ValidationError, '(item %s): %s' % (
+                                index, vv)
+                    else:
+                        client = sequence[index]
 
                     kw['sequence-index']=index
                     if type(client)==TupleType and len(client)==2:

--- Updated File DT_String.py in package Zope2 --
--- DT_String.py	2000/12/12 21:20:25	1.39
+++ DT_String.py	2001/04/26 22:25:08	1.39.54.1
@@ -500,7 +500,7 @@
             if globals: push(globals)
             if mapping:
                 push(mapping)
-            md.validate=self.validate
+            md.read_guard=self.read_guard
             if client is not None:
                 if type(client)==type(()):
                     md.this=client[-1]
@@ -545,8 +545,8 @@
             if pushed: md._pop(pushed) # Get rid of circular reference!
             md.level=level # Restore previous level
 
-    validate__roles__=()
-    validate=None
+    read_guard__roles__=()
+    read_guard=None
 
     def __str__(self):
         return self.read()

--- Updated File DT_Util.py in package Zope2 --
--- DT_Util.py	2001/04/26 02:43:15	1.72.18.5
+++ DT_Util.py	2001/04/26 22:25:08	1.72.18.6
@@ -87,6 +87,7 @@
 
 import regex, string, math, os
 from string import strip, join, atoi, lower, split, find
+from RestrictedPython.Eval import RestrictionCapableEval
 
 str=__builtins__['str'] # Waaaaa, waaaaaaaa needed for pickling waaaaa
 
@@ -103,46 +104,22 @@
             if type(v) is st: v=atoi(v)
     return v or 0
 
-_marker=[]
+_marker = []  # Create a new marker object.
 
 def careful_getattr(md, inst, name, default=_marker):
-    
-    if name[:1]!='_':
-
-        # Try to get the attribute normally so that we don't
-        # accidentally acquire when we shouldn't.
-        try: v=getattr(inst, name)
-        except:
-            if default is not _marker:
-                return default
-            raise
-
-        validate=md.validate
-
-        if validate is None: return v
-
-        if hasattr(inst,'aq_acquire'):
-            return inst.aq_acquire(name, validate, md)
-
-        if validate(inst,inst,name,v,md): return v
-
-    raise ValidationError, name
+    read_guard = md.read_guard
+    if read_guard is not None:
+        inst = read_guard(inst)
+    if default is _marker:
+        return getattr(inst, name)
+    else:
+        return getattr(inst, name, default)
 
 def careful_hasattr(md, inst, name):
-    v=getattr(inst, name, _marker)
-    if v is not _marker:
-        try: 
-            if name[:1]!='_':
-                validate=md.validate                
-                if validate is None: return 1
-    
-                if hasattr(inst,'aq_acquire'):
-                    inst.aq_acquire(name, validate, md)
-                    return 1
-    
-                if validate(inst,inst,name,v,md): return 1
-        except: pass
-    return 0
+    read_guard = md.read_guard
+    if read_guard is not None:
+        inst = read_guard(inst)
+    return hasattr(inst, name)
 
 def careful_range(md, iFirst, *args):
     # limited range function from Martijn Pieters
@@ -196,10 +173,6 @@
 
 d['test']=test
 
-def obsolete_attr(self, inst, name, md):
-    return careful_getattr(md, inst, name)
-
-d['attr']=obsolete_attr
 d['getattr']=careful_getattr
 d['hasattr']=careful_hasattr
 d['range']=careful_range
@@ -263,78 +236,31 @@
 d['reorder']=reorder
 
 
-class DTMLGuard:
-    _md = None
-
-    def __init__(self, ob):
-        self._ob = ob
-
-    def __getattr__(self, name):
-        if name[:1]!='_':  # This condition is probably unnecessary.
-            inst = self._ob
-            # Try to get the attribute normally so that we don't
-            # accidentally acquire when we shouldn't.
-            try: v=getattr(inst, name)
-            except:
-                if default is not _marker:
-                    return default
-                raise
-            md = self._md
-            validate = md.validate
-            if validate is None:
-                return v
-            if hasattr(inst, 'aq_acquire'):
-                return inst.aq_acquire(name, validate, md)
-            if validate(inst, inst, name, v, md):
-                return v
-        raise ValidationError, name
-
-    def __len__(self):
-        return len(self._ob)
-
-    def __getitem__(self, key):
-        mapping = self._ob
-        v = mapping[key]
-        if type(v) is type(''):
-            return v # Short-circuit common case
-        md = self._md
-        validate = md.validate
-        if validate is None or validate(mapping, mapping, None, v, md):
-            return v
-        raise ValidationError, key
-
-    def __getslice__(self, lo, hi):
-        seq = self._ob
-        v = seq[lo:hi]
-        if type(seq) is type(''):
-            return v # Short-circuit common case
-        md = self._md
-        validate = md.validate
-        if validate is not None:
-            for e in v:
-                if not validate(seq, seq, None, e, md):
-                    raise ValidationError, (
-                        'unauthorized access to slice member')
-        return v
-
-from RestrictedPython.Eval import RestrictionCapableEval
-
 class Eval(RestrictionCapableEval):
 
     def eval(self, md):
-        # Create a temporary subclass of DTMLGuard.
-        class Guard (DTMLGuard): pass
-        Guard._md = md
-        d = {'_': md, '_read_guard': Guard}
+        guard = getattr(md, 'read_guard', None)
+        if guard is not None:
+            self.prepRestrictedCode()
+            code = self.rcode
+            d = {'_': md, '_read_': guard}
+        else:
+            self.prepUnrestrictedCode()
+            code = self.ucode
+            d = {'_': md}
+        d.update(self.globals)
+        has_key = d.has_key
         for name in self.used:
             __traceback_info__ = name
-            try: d[name] = md.getitem(name,0)
+            try:
+                if not has_key(name):
+                    d[name] = md.getitem(name, 0)
             except KeyError:
                 # Swallow KeyErrors since the expression
                 # might not actually need the name.  If it
                 # does need the name, a NameError will occur.
                 pass
-        return eval(self.code, self.globals, d)
+        return eval(code, d)
 
     def __call__(self, **kw):
         # Never used?

--- Updated File DT_With.py in package Zope2 --
--- DT_With.py	2000/05/11 18:54:14	1.11
+++ DT_With.py	2001/04/26 22:25:08	1.11.142.1
@@ -139,8 +139,8 @@
         if self.only:
             _md=md
             md=TemplateDict()
-            if hasattr(_md, 'validate'):
-                md.validate=_md.validate
+            if hasattr(_md, 'read_guard'):
+                md.read_guard = _md.read_guard
 
         md._push(v)
         try: return render_blocks(self.section, md)

--- Updated File DocumentTemplate.py in package Zope2 --
--- DocumentTemplate.py	2001/04/26 02:43:16	1.10.160.1
+++ DocumentTemplate.py	2001/04/26 22:25:08	1.10.160.2
@@ -145,31 +145,15 @@
 
     Document templates provide a basic level of access control by
     preventing access to names beginning with an underscore.
-    Addational control may be provided by providing document templates
-    with a 'validate' method.  This would typically be done by
+    Additional control may be provided by providing document templates
+    with a 'read_guard' method.  This would typically be done by
     subclassing one or more of the DocumentTemplate classes.
 
-    If provided, the the 'validate' method will be called when objects
+    If provided, the the 'read_guard' method will be called when objects
     are accessed as accessed as instance attributes or when they are
-    accessed through keyed access in an expression..  The 'validate'
-    method will be called with five arguments:
-
-    1. The containing object that the object was accessed from,
-
-    2. The actual containing object that the object was found in,
-       which may be different from the containing onject the object
-       was accessed from, if the containing object supports
-       acquisition,
-
-    3. The name used to acces the object,
-
-    4. The object, and
-
-    5. The namespace object used to render the document template.
-
-       If a document template was called from Bobo, then the namespace
-       object will have an attribute, AUTHENTICATED_USER that is the
-       user object that was found if and when Bobo authenticated a user.
+    accessed through keyed access in an expression..  The 'read_guard'
+    method will be called with the containing object.  It can
+    return a wrapper object from which the attribute will be accessed.
 
 Document Templates may be created 4 ways:
 

--- Updated File cDocumentTemplate.c in package Zope2 --
--- cDocumentTemplate.c	2000/11/21 22:08:50	1.35
+++ cDocumentTemplate.c	2001/04/26 22:25:08	1.35.60.1
@@ -92,7 +92,7 @@
 static PyObject *py_isDocTemp=0, *py_blocks=0, *py_=0, *join=0, *py_acquire;
 static PyObject *py___call__, *py___roles__, *py_AUTHENTICATED_USER;
 static PyObject *py_hasRole, *py__proxy_roles, *py_Unauthorized;
-static PyObject *py_Unauthorized_fmt, *py_validate;
+static PyObject *py_Unauthorized_fmt, *py_read_guard;
 static PyObject *py__push, *py__pop, *py_aq_base, *py_renderNS;
 
 /* ----------------------------------------------------- */
@@ -108,7 +108,7 @@
   PyObject *inst;
   PyObject *cache;
   PyObject *namespace;
-  PyObject *validate;
+  PyObject *read_guard;
 } InstanceDictobject;
 
 staticforward PyExtensionClass InstanceDictType;
@@ -116,18 +116,18 @@
 static PyObject *
 InstanceDict___init__(InstanceDictobject *self, PyObject *args)
 {
-  self->validate=NULL;
+  self->read_guard=NULL;
   UNLESS(PyArg_ParseTuple(args, "OO|O",
 			  &(self->inst),
 			  &(self->namespace),
-			  &(self->validate)))
+			  &(self->read_guard)))
     return NULL;
   Py_INCREF(self->inst);
   Py_INCREF(self->namespace);
-  if (self->validate)
-    Py_INCREF(self->validate);
+  if (self->read_guard)
+    Py_INCREF(self->read_guard);
   else
-    UNLESS(self->validate=PyObject_GetAttr(self->namespace, py_validate))
+    UNLESS(self->read_guard=PyObject_GetAttr(self->namespace, py_read_guard))
        return NULL;
     
   UNLESS(self->cache=PyDict_New()) return NULL;
@@ -150,7 +150,7 @@
   Py_XDECREF(self->inst);
   Py_XDECREF(self->cache);
   Py_XDECREF(self->namespace);
-  Py_XDECREF(self->validate);
+  Py_XDECREF(self->read_guard);
   Py_DECREF(self->ob_type);
   PyMem_DEL(self);
 }
@@ -182,7 +182,7 @@
   char *name;
   
   /* Try to get value from the cache */
-  if (r=PyObject_GetItem(self->cache, key)) return r;
+  if ((r=PyObject_GetItem(self->cache, key))) return r;
   PyErr_Clear();
   
   /* Check for __str__ */
@@ -193,56 +193,31 @@
       return PyObject_Str(self->inst);
     }
   
-  /* Do explicit acquisition with "roles" rule */
-  if (r=PyObject_GetAttr(self->inst, py_acquire))
-    {
-      /* Sanity check in case of explicit Aq */
-      if (v=PyObject_GetAttr(self->inst, key)) Py_DECREF(v);  
-      else 
-	{
-	  Py_DECREF(r);
-	  goto KeyError;
-	}
-
-      if (self->validate != Py_None)
-	{
-	  UNLESS_ASSIGN(r,PyObject_CallFunction(
-		 r, "OOO", key, self->validate, self->namespace))
-	    {
-	      PyObject *tb;
-
-	      PyErr_Fetch(&r, &v, &tb);
-	      if (r != PyExc_AttributeError || PyObject_Compare(v,key))
-		{
-		  PyErr_Restore(r,v,tb);
-		  return NULL;
-		}
-	      Py_XDECREF(r);
-	      Py_XDECREF(v);
-	      Py_XDECREF(tb);
-	      
-	      goto KeyError;
-	    }
-	}
-      else
-	UNLESS_ASSIGN(r, PyObject_GetAttr(self->inst, key)) goto KeyError;
-    }  
-  else
-    {
-      PyErr_Clear();
+  if (self->read_guard != Py_None) {
+    r = PyObject_CallFunction(self->read_guard, "O", self->inst);
+    if (!r) return NULL;
+  }
+  else {
+    r = self->inst;
+    Py_INCREF(r);
+  }
 
-      /* OK, use getattr */
-      UNLESS(r=PyObject_GetAttr(self->inst, key)) goto KeyError;
+  ASSIGN(r, PyObject_GetAttr(r, key));
+  if (!r) {
+    PyObject *tb;
+
+    PyErr_Fetch(&r, &v, &tb);
+    if (r != PyExc_AttributeError) /* || PyObject_Compare(v,key)) */
+      {
+	PyErr_Restore(r,v,tb);
+	return NULL;
+      }
+    Py_XDECREF(r);
+    Py_XDECREF(v);
+    Py_XDECREF(tb);
 
-      if (self->validate != Py_None)
-	{
-	  UNLESS(v=PyObject_CallFunction(
-	    self->validate,"OOOOO",
-	    self->inst, self->inst, key, r, self->namespace))
-	    return NULL;
-	  Py_DECREF(v);
-	}
-    }
+    goto KeyError;
+  }
   
   if (r && PyObject_SetItem(self->cache, key, r) < 0) PyErr_Clear();
   
@@ -312,9 +287,7 @@
 staticforward PyExtensionClass MMtype;
 
 static PyObject *
-MM_push(self, args)
-	MM *self;
-	PyObject *args;
+MM_push(MM *self, PyObject *args)
 {
   PyObject *src;
   UNLESS(PyArg_Parse(args, "O", &src)) return NULL;
@@ -324,9 +297,7 @@
 }
 
 static PyObject *
-MM_pop(self, args)
-	MM *self;
-	PyObject *args;
+MM_pop(MM *self, PyObject *args)
 {
   int i=1, l;
   PyObject *r;
@@ -343,9 +314,7 @@
 }
 
 static PyObject *
-MM__init__(self, args)
-     MM *self;
-     PyObject *args;
+MM__init__(MM *self, PyObject *args)
 {
   UNLESS(PyArg_Parse(args, "")) return NULL;
   UNLESS(self->data=PyList_New(0)) return NULL;
@@ -385,7 +354,7 @@
     Py_INCREF(base);
   }
 
-  if ( value = PyObject_GetAttr(base, py_isDocTemp) ) {
+  if ( (value = PyObject_GetAttr(base, py_isDocTemp)) ) {
     if (PyObject_IsTrue(value)) {
       result = 1;
     }
@@ -408,12 +377,12 @@
   while (--i >= 0)
     {
       e=PyList_GetItem(self->data,i);
-      if (e=PyObject_GetItem(e,key))
+      if ((e=PyObject_GetItem(e,key)))
 	{
           if (!call) return e;
 
           /* Try calling __render_with_namespace__ */
-          if (rr = PyObject_GetAttr(e, py_renderNS)) 
+          if ((rr = PyObject_GetAttr(e, py_renderNS))) 
             {
               Py_DECREF(e);
               UNLESS_ASSIGN(rr, PyObject_CallFunction(rr, "O", self))
@@ -516,8 +485,7 @@
 };
 
 static void
-MM_dealloc(self)
-     MM *self;
+MM_dealloc(MM *self)
 {
   Py_XDECREF(self->data);
   Py_XDECREF(self->dict);
@@ -538,7 +506,7 @@
     {
       PyObject *v;
 
-      if (v=PyDict_GetItem(self->dict, name))
+      if ((v=PyDict_GetItem(self->dict, name)))
 	{
 	  Py_INCREF(v);
 	  return v;
@@ -568,8 +536,7 @@
 }
 
 static int
-MM_length(self)
-	MM *self;
+MM_length(MM *self)
 {
   long l=0, el, i;
   PyObject *e=0;
@@ -800,7 +767,7 @@
 		    {
 		      /* We have to be careful to handle key errors here */
 		      n=cond;
-		      if (cond=PyObject_GetItem(md,cond))
+		      if ((cond=PyObject_GetItem(md,cond)))
 			{
 			  if (PyDict_SetItem(cache, n, cond) < 0)
 			    {
@@ -912,7 +879,7 @@
 };
 
 void
-initcDocumentTemplate()
+initcDocumentTemplate(void)
 {
   PyObject *m, *d;
   char *rev="$Revision$";
@@ -927,7 +894,7 @@
   UNLESS(py___roles__=PyString_FromString("__roles__")) return;
   UNLESS(py__proxy_roles=PyString_FromString("_proxy_roles")) return;
   UNLESS(py_hasRole=PyString_FromString("hasRole")) return;
-  UNLESS(py_validate=PyString_FromString("validate")) return;
+  UNLESS(py_read_guard=PyString_FromString("read_guard")) return;
   UNLESS(py__push=PyString_FromString("_push")) return;
   UNLESS(py__pop=PyString_FromString("_pop")) return;
   UNLESS(py_aq_base=PyString_FromString("aq_base")) return;

--- Updated File pDocumentTemplate.py in package Zope2 --
--- pDocumentTemplate.py	2001/01/16 18:08:27	1.27
+++ pDocumentTemplate.py	2001/04/26 22:25:08	1.27.40.1
@@ -117,14 +117,14 @@
 
 class InstanceDict:
 
-    validate=None
+    read_guard=None
 
-    def __init__(self,o,namespace,validate=None):
+    def __init__(self,o,namespace,read_guard=None):
         self.self=o
         self.cache={}
         self.namespace=namespace
-        if validate is None: self.validate=namespace.validate
-        else: self.validate=validate
+        if read_guard is None: self.read_guard=namespace.read_guard
+        else: self.read_guard=read_guard
 
     def has_key(self,key):
         return hasattr(self.self,key)
@@ -144,13 +144,16 @@
         if key[:1]=='_':
             if key != '__str__':
                 raise KeyError, key # Don't divuldge private data
-            r=str(inst)
+            return str(inst)
+
+        read_guard = self.read_guard
+        if read_guard is None:
+            inst1 = inst
         else:
-            try: r=getattr(inst,key)
-            except AttributeError: raise KeyError, key
+            inst1 = read_guard(inst)
 
-        v=self.validate
-        if v is not None: v(inst,inst,key,r,self.namespace)
+        try: r = getattr(inst1, key)
+        except AttributeError: raise KeyError, key
 
         self.cache[key]=r
         return r