[Zope3-checkins] SVN: Zope3/trunk/src/zope/ Added untrusted dtml
support
Jim Fulton
jim at zope.com
Thu Jul 29 00:57:37 EDT 2004
Log message for revision 26826:
Added untrusted dtml support
- Added restricted compilation of python functions
- Added more careful getting of instance attrs
- Added additional hooks in the trusted code to
make swithing in untrusted versions possible.
- Centralized the untrusted support so that it's easier to use it, for
example in both dtmlpage and sqlscript.
Changed:
U Zope3/trunk/src/zope/app/dtmlpage/dtmlpage.py
U Zope3/trunk/src/zope/app/sqlscript/dtml.py
U Zope3/trunk/src/zope/documenttemplate/dt_in.py
U Zope3/trunk/src/zope/documenttemplate/dt_string.py
U Zope3/trunk/src/zope/documenttemplate/dt_try.py
U Zope3/trunk/src/zope/documenttemplate/dt_util.py
U Zope3/trunk/src/zope/documenttemplate/dt_with.py
U Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py
A Zope3/trunk/src/zope/documenttemplate/untrusted/
A Zope3/trunk/src/zope/documenttemplate/untrusted/README.txt
A Zope3/trunk/src/zope/documenttemplate/untrusted/__init__.py
A Zope3/trunk/src/zope/documenttemplate/untrusted/tests.py
A Zope3/trunk/src/zope/documenttemplate/untrusted/untrusted.py
-=-
Modified: Zope3/trunk/src/zope/app/dtmlpage/dtmlpage.py
===================================================================
--- Zope3/trunk/src/zope/app/dtmlpage/dtmlpage.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/app/dtmlpage/dtmlpage.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -20,7 +20,7 @@
from persistent import Persistent
from zope.security.proxy import ProxyFactory
-from zope.documenttemplate.dt_html import HTML
+from zope.documenttemplate.untrusted import UntrustedHTML
from zope.interface import implements
from zope.app.annotation.interfaces import IAnnotatable
@@ -42,22 +42,14 @@
def setSource(self, text, content_type='text/html'):
'''See interface `IDTMLPage`'''
- self.template = HTML(text)
+ self.template = UntrustedHTML(text)
self.content_type = content_type
def render(self, request, *args, **kw):
"""See interface `IDTMLRenderPage`"""
+ return self.template(self.__parent__, request, REQUEST=request, **kw)
- instance = ProxyFactory(self.__parent__)
- request = ProxyFactory(request)
- for k in kw:
- kw[k] = ProxyFactory(kw[k])
- kw['REQUEST'] = request
-
- return self.template(instance, request, **kw)
-
-
__call__ = render
source = property(getSource, setSource, None,
Modified: Zope3/trunk/src/zope/app/sqlscript/dtml.py
===================================================================
--- Zope3/trunk/src/zope/app/sqlscript/dtml.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/app/sqlscript/dtml.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -20,6 +20,7 @@
from zope.documenttemplate.dt_html import HTML
from zope.documenttemplate.dt_util import ParseError, parse_params, name_param
+from zope.documenttemplate.untrusted import UntrustedHTML
from interfaces import MissingInput
@@ -77,7 +78,10 @@
return ''
raise KeyError, key, sys.exc_info()[2]
- if isinstance(v, (list, tuple)):
+ if (list in v.__class__.__mro__ # isinstance doesn't work w
+ or # security proxies, so we use
+ tuple in v.__class__.__mro__ # this __mro__ trick.
+ ):
if len(v) > 1 and not self.multiple:
raise 'Multiple Values', (
'multiple values are not allowed for <em>%s</em>'
@@ -272,7 +276,7 @@
__call__ = render
-class SQLDTML(HTML):
+class SQLDTML(UntrustedHTML):
__name__ = 'SQLDTML'
commands = HTML.commands.copy()
Modified: Zope3/trunk/src/zope/documenttemplate/dt_in.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_in.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/dt_in.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -315,10 +315,8 @@
$Id$
"""
-from zope.documenttemplate.dt_util import \
- ParseError, parse_params, name_param
-from zope.documenttemplate.dt_util import \
- render_blocks, InstanceDict, ValidationError, Eval
+from zope.documenttemplate.dt_util import ParseError, parse_params, name_param
+from zope.documenttemplate.dt_util import render_blocks, ValidationError, Eval
import re
from zope.documenttemplate.dt_insv import sequence_variables, opt
@@ -583,7 +581,7 @@
if mapping:
push(client)
else:
- push(InstanceDict(client, md))
+ md._push_instance(client)
try:
append(render(section, md))
@@ -680,7 +678,7 @@
if mapping:
push(client)
else:
- push(InstanceDict(client, md))
+ md._push_instance(client)
try:
append(render(section, md))
Modified: Zope3/trunk/src/zope/documenttemplate/dt_string.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_string.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/dt_string.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -17,8 +17,7 @@
"""
import re, thread
-from zope.documenttemplate.dt_util import \
- ParseError, InstanceDict, TemplateDict, render_blocks
+from zope.documenttemplate.dt_util import ParseError, render_blocks
from zope.documenttemplate.dt_var import Var, Call, Comment
from zope.documenttemplate.dt_return import ReturnTag, DTReturn
@@ -44,6 +43,8 @@
"""
+ from zope.documenttemplate.dt_util import TemplateDict
+
# Document Templates masquerade as functions:
class func_code:
pass
@@ -422,7 +423,7 @@
pushed=None
try:
- if mapping.__class__ is TemplateDict:
+ if isinstance(mapping, self.TemplateDict):
pushed=0
except:
pass
@@ -436,7 +437,7 @@
push(self.globals)
pushed = pushed+1
else:
- md = TemplateDict()
+ md = self.TemplateDict()
push = md._push
shared_globals = self.shared_globals
if shared_globals:
@@ -463,11 +464,11 @@
# if client is a tuple, it represents a "path" of clients
# which should be pushed onto the md in order.
for ob in client:
- push(InstanceDict(ob, md)) # Circ. Ref. 8-|
+ md._push_instance(ob)
pushed += 1
else:
# otherwise its just a normal client object.
- push(InstanceDict(client, md)) # Circ. Ref. 8-|
+ md._push_instance(client)
pushed += 1
if self._vars:
Modified: Zope3/trunk/src/zope/documenttemplate/dt_try.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_try.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/dt_try.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -18,9 +18,8 @@
import sys, traceback
from StringIO import StringIO
-from zope.documenttemplate.dt_util \
- import ParseError, parse_params, render_blocks
-from zope.documenttemplate.dt_util import InstanceDict
+from zope.documenttemplate.dt_util import ParseError, parse_params
+from zope.documenttemplate.dt_util import render_blocks
from zope.documenttemplate.dt_return import DTReturn
from types import StringType
@@ -181,7 +180,7 @@
error_tb = f.getvalue()
ns = md.namespace(error_type=errname, error_value=v,
error_tb=error_tb)[0]
- md._push(InstanceDict(ns,md))
+ md._push_instance(ns)
return render_blocks(handler, md)
finally:
md._pop(1)
Modified: Zope3/trunk/src/zope/documenttemplate/dt_util.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_util.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/dt_util.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -19,8 +19,10 @@
from types import ListType, StringType, TupleType
-from zope.documenttemplate.pdocumenttemplate import \
- InstanceDict, TemplateDict, render_blocks
+# These imports are for the use of clients of this module, as this
+# module is the canonical place to get them.
+from zope.documenttemplate.pdocumenttemplate import TemplateDict, InstanceDict
+from zope.documenttemplate.pdocumenttemplate import render_blocks
class ParseError(Exception):
@@ -65,8 +67,8 @@
def eval(self, mapping):
- d={'_vars': mapping,
- '_': mapping}
+ d={'_vars': mapping._proxied(),
+ '_': mapping._proxied()}
code = self.code
for name in code.co_names:
if not d.has_key(name):
@@ -79,7 +81,9 @@
# does need the name, a NameError will occur.
pass
- return eval(code, {'__builtins__': None}, d)
+ return eval(code,
+ {'__builtins__': getattr(mapping, '__builtins__', None)},
+ d)
def __call__(self, **kw):
Modified: Zope3/trunk/src/zope/documenttemplate/dt_with.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_with.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/dt_with.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -35,9 +35,8 @@
$Id$
"""
-from zope.documenttemplate.dt_util import \
- parse_params, name_param, InstanceDict, render_blocks
-from zope.documenttemplate.dt_util import TemplateDict
+from zope.documenttemplate.dt_util import parse_params, name_param
+from zope.documenttemplate.dt_util import render_blocks
from types import StringTypes, TupleType
@@ -70,18 +69,19 @@
else:
v = expr(md)
- if not self.mapping:
- if isinstance(v, TupleType) and len(v) == 1:
- v = v[0]
- v = InstanceDict(v, md)
-
if self.only:
_md = md
- md = TemplateDict()
+ md = md.__class__()
if hasattr(_md, 'validate'):
md.validate = _md.validate
- md._push(v)
+ if self.mapping:
+ md._push(v)
+ else:
+ if isinstance(v, TupleType) and len(v) == 1:
+ v = v[0]
+ md._push_instance(v)
+
try:
return render_blocks(self.section, md)
finally:
Modified: Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -54,12 +54,6 @@
inst = self.self
- if key[:1] == '_':
- if key != '__str__':
- raise KeyError, key # Don't divuldge private data
- else:
- return str(inst)
-
try:
r = getattr(inst, key)
except AttributeError:
@@ -122,6 +116,12 @@
def _push(self, d):
return self.dicts.push(d)
+ def _push_instance(self, inst):
+ self._push(InstanceDict(inst, self))
+
+ def _proxied(self):
+ return self
+
def __init__(self):
m = self.dicts = MultiMapping()
self._pop = m.pop
Added: Zope3/trunk/src/zope/documenttemplate/untrusted/README.txt
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/untrusted/README.txt 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/untrusted/README.txt 2004-07-29 04:57:37 UTC (rev 26826)
@@ -0,0 +1,84 @@
+Untrusted Document Templates
+============================
+
+Untrusted document templates implement an untrusted interpreter for
+the DTML language. Untrusted templates protect any data they're given.
+
+ >>> from zope.documenttemplate.untrusted import UntrustedHTML
+
+Consider a sample class, which allows access to attributes f1, f2, and name:
+
+ >>> from zope.security.checker import NamesChecker
+ >>> class C(object):
+ ... def __init__(self, name, **kw):
+ ... self.name = name
+ ... self.__dict__.update(kw)
+ ... def f1(self):
+ ... return 'f1 called'
+ ... def f2(self):
+ ... return 'f2 called'
+ ... __Security_checker__ = NamesChecker(['f1', 'f2', 'name'])
+
+We can get at alowed data just fine:
+
+ >>> UntrustedHTML('<dtml-var f1> <dtml-var name>')(C('bob'))
+ 'f1 called bob'
+
+But we'll get an error if we try to access an attribute we're not
+alowed to get:
+
+ >>> UntrustedHTML('<dtml-var x>')(C('bob', x=1))
+ Traceback (most recent call last):
+ ...
+ KeyError: 'x'
+
+If we create data inside the template, we'll be allowed to manipulate
+it:
+
+ >>> UntrustedHTML('''
+ ... <dtml-let data="[]">
+ ... <dtml-call expr="data.append(1)"><dtml-var data>
+ ... </dtml-let>
+ ... ''')()
+ '\n [1]\n'
+
+but any attributes we get from data we create are proxied, and
+this protected:
+
+ >>> UntrustedHTML('''
+ ... <dtml-let data="[]">
+ ... <dtml-with data><dtml-with __class__><dtml-var __dict__>
+ ... </dtml-with></dtml-with>
+ ... </dtml-let>
+ ... ''')()
+ Traceback (most recent call last):
+ ...
+ KeyError: '__dict__'
+
+ >>> UntrustedHTML('''
+ ... <dtml-let data="[]">
+ ... <dtml-var expr="data.__class__.__dict__">
+ ... </dtml-let>
+ ... ''')()
+ Traceback (most recent call last):
+ ...
+ ForbiddenAttribute: ('__dict__', <type 'list'>)
+
+ >>> UntrustedHTML('''<dtml-var expr="'foo'.__class__.__dict__">''')()
+ Traceback (most recent call last):
+ ...
+ ForbiddenAttribute: ('__dict__', <type 'str'>)
+
+Access is provided to a number of utility functions provided by the
+template dict, but not to hidden functions:
+
+ >>> UntrustedHTML('''<dtml-var expr="_.abs(-1)">''')()
+ '1'
+
+But not to privare attributes:
+
+ >>> UntrustedHTML('''<dtml-var expr="_._pop()">''')()
+ Traceback (most recent call last):
+ ...
+ ForbiddenAttribute: ('_pop', <an UntrustedTemplateDict>)
+
Property changes on: Zope3/trunk/src/zope/documenttemplate/untrusted/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/documenttemplate/untrusted/__init__.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/untrusted/__init__.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/untrusted/__init__.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -0,0 +1 @@
+from zope.documenttemplate.untrusted.untrusted import UntrustedHTML
Property changes on: Zope3/trunk/src/zope/documenttemplate/untrusted/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/documenttemplate/untrusted/tests.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/untrusted/tests.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/untrusted/tests.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Untrusted python tests
+
+$Id$
+"""
+import unittest
+from zope.testing import doctestunit
+
+def test_suite():
+ return unittest.TestSuite((
+ doctestunit.DocFileSuite('README.txt',),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Property changes on: Zope3/trunk/src/zope/documenttemplate/untrusted/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/documenttemplate/untrusted/untrusted.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/untrusted/untrusted.py 2004-07-29 04:53:03 UTC (rev 26825)
+++ Zope3/trunk/src/zope/documenttemplate/untrusted/untrusted.py 2004-07-29 04:57:37 UTC (rev 26826)
@@ -0,0 +1,67 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""Untrusted document template support
+
+$Id$
+"""
+
+from zope.security.checker import ProxyFactory
+from zope.documenttemplate.dt_html import HTML
+from zope.documenttemplate.dt_util import InstanceDict, TemplateDict
+from zope.security.untrustedpython.rcompile import compile
+from zope.security.untrustedpython.builtins import SafeBuiltins
+from zope.security.checker import NamesChecker
+
+class UntrustedInstanceDict(InstanceDict):
+
+ def __getitem__(self, key):
+ return ProxyFactory(InstanceDict.__getitem__(self, key))
+
+class UntrustedTemplateDict(TemplateDict):
+
+ __builtins__ = SafeBuiltins
+
+ __Security_checker__ = NamesChecker([
+ 'math', 'random', 'range', 'pow', 'test', 'getattr', 'attr', 'hasattr',
+ 'render', 'namespace', 'reorder',
+ 'None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int',
+ 'len', 'max', 'min', 'oct', 'ord', 'round', 'str',
+ ])
+
+ def _push_instance(self, inst):
+ self._push(UntrustedInstanceDict(inst, self))
+
+ def _proxied(self):
+ return ProxyFactory(self)
+
+ def __repr__(self):
+ return '<an UntrustedTemplateDict>'
+
+
+class UntrustedHTML(HTML):
+ __name__ = 'UntrustedHTML'
+
+ TemplateDict = UntrustedTemplateDict
+
+ def compile_python_expresssion(self, src):
+ return compile(src, getattr(self, '__name__', '<string>'), 'eval')
+
+ def __call__(self, client=None, mapping={}, **kw):
+ if kw:
+ kw = dict([(k, ProxyFactory(v)) for (k, v) in kw.items()])
+
+ return HTML.__call__(self,
+ ProxyFactory(client),
+ ProxyFactory(mapping),
+ **kw)
Property changes on: Zope3/trunk/src/zope/documenttemplate/untrusted/untrusted.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Zope3-Checkins
mailing list