[Checkins] SVN: five.pt/trunk/ Added access-control security to Python expression. Thanks to Leonardo Rochael Almeida for contributing to this feature.
Malthe Borch
mborch at gmail.com
Fri Feb 18 09:47:59 EST 2011
Log message for revision 120422:
Added access-control security to Python expression. Thanks to Leonardo Rochael Almeida for contributing to this feature.
Changed:
U five.pt/trunk/CHANGES.txt
U five.pt/trunk/setup.py
U five.pt/trunk/src/five/pt/configure.zcml
U five.pt/trunk/src/five/pt/expressions.py
U five.pt/trunk/src/five/pt/tests/locals.pt
A five.pt/trunk/src/five/pt/tests/secure.pt
U five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py
U five.pt/trunk/versions.cfg
-=-
Modified: five.pt/trunk/CHANGES.txt
===================================================================
--- five.pt/trunk/CHANGES.txt 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/CHANGES.txt 2011-02-18 14:47:59 UTC (rev 120422)
@@ -1,6 +1,11 @@
Changelog
=========
+In next release...
+
+- Python-expressions are now subject to access-control security.
+ [malthe]
+
1.3.3 - 2010-09-30
~~~~~~~~~~~~~~~~~~
Modified: five.pt/trunk/setup.py
===================================================================
--- five.pt/trunk/setup.py 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/setup.py 2011-02-18 14:47:59 UTC (rev 120422)
@@ -27,6 +27,7 @@
'setuptools',
'z3c.pt>=1.2.1',
'Chameleon>=1.2.11',
+ 'sourcecodegen',
],
entry_points="""
[z3c.autoinclude.plugin]
Modified: five.pt/trunk/src/five/pt/configure.zcml
===================================================================
--- five.pt/trunk/src/five/pt/configure.zcml 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/src/five/pt/configure.zcml 2011-02-18 14:47:59 UTC (rev 120422)
@@ -10,6 +10,10 @@
component=".expressions.path_translator" />
<utility
+ name="python"
+ component=".expressions.python_translator" />
+
+ <utility
name="exists"
component=".expressions.exists_translator" />
Modified: five.pt/trunk/src/five/pt/expressions.py
===================================================================
--- five.pt/trunk/src/five/pt/expressions.py 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/src/five/pt/expressions.py 2011-02-18 14:47:59 UTC (rev 120422)
@@ -1,3 +1,5 @@
+from compiler import parse
+
from z3c.pt.expressions import PathTranslator
from z3c.pt.expressions import ExistsTranslator
from z3c.pt.expressions import ZopeExistsTraverser
@@ -2,2 +4,5 @@
from z3c.pt.expressions import ProviderTranslator
+from chameleon.zpt.expressions import PythonTranslator
+from chameleon.core import types
+from sourcecodegen import generate_code
@@ -7,7 +12,16 @@
from OFS.interfaces import ITraversable
from Products.PageTemplates import ZRPythonExpr
from zExceptions import NotFound, Unauthorized
+from RestrictedPython.RestrictionMutator import RestrictionMutator
+from RestrictedPython import MutatingWalker
+from RestrictedPython.Guards import safe_builtins
+from AccessControl.ZopeGuards import guarded_getattr
+from AccessControl.ZopeGuards import guarded_getitem
+from AccessControl.ZopeGuards import guarded_apply
+from AccessControl.ZopeGuards import guarded_iter
+from AccessControl.ZopeGuards import protected_inplacevar
+
from zope import component
from zope.proxy import removeAllProxies
from zope.traversing.adapters import traversePathElement
@@ -121,6 +135,50 @@
class FiveProviderTranslator(ProviderTranslator):
content_provider_traverser = FiveContentProviderTraverser()
+
+class FivePythonTranslator(PythonTranslator):
+ rm = RestrictionMutator()
+
+ secured = {
+ '_getattr_': guarded_getattr,
+ '_getitem_': guarded_getitem,
+ '_apply_': guarded_apply,
+ '_getiter_': guarded_iter,
+ '_inplacevar_': protected_inplacevar,
+ }
+
+ def translate(self, string, escape=None):
+ """We use the ``parser`` module to determine if
+ an expression is a valid python expression.
+
+ Make sure the formatted syntax error exception contains the
+ expression string.
+
+ >>> from traceback import format_exc
+ >>> translate = PythonTranslator().translate
+ >>> try: translate('abc:def:ghi')
+ ... except SyntaxError, e: 'abc:def:ghi' in format_exc(e)
+ True
+ """
+
+ if isinstance(string, unicode):
+ string = string.encode('utf-8')
+
+ if string:
+ expression = string.strip()
+ node = parse(expression, 'eval').node
+ MutatingWalker.walk(node, self.rm)
+ string = generate_code(node)
+
+ if isinstance(string, str):
+ string = string.decode('utf-8')
+
+ value = types.value(string.strip())
+ value.symbol_mapping.update(self.secured)
+
+ return value
+
+python_translator = FivePythonTranslator()
path_translator = PathTranslator()
exists_translator = ExistsTranslator()
provider_translator = FiveProviderTranslator()
Modified: five.pt/trunk/src/five/pt/tests/locals.pt
===================================================================
--- five.pt/trunk/src/five/pt/tests/locals.pt 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/src/five/pt/tests/locals.pt 2011-02-18 14:47:59 UTC (rev 120422)
@@ -5,7 +5,6 @@
<div tal:replace="python:'here==container:'+str(here==container)" />
<div tal:replace="string:root:${root/getPhysicalPath}" />
<div tal:replace="string:nothing:${nothing}" />
- <div tal:define="cgi python:modules['cgi']">
- modules:<span tal:replace="python:cgi.escape(view.tagsoup())" />
- </div>
+ <div tal:define="cgi python:modules['cgi']"
+ tal:replace="python: dir(cgi)" />
</div>
Added: five.pt/trunk/src/five/pt/tests/secure.pt
===================================================================
--- five.pt/trunk/src/five/pt/tests/secure.pt (rev 0)
+++ five.pt/trunk/src/five/pt/tests/secure.pt 2011-02-18 14:47:59 UTC (rev 120422)
@@ -0,0 +1,4 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <span tal:replace="python: modules['cgi'].escape(view.tagsoup())" />
+</div>
Modified: five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py 2011-02-18 14:47:59 UTC (rev 120422)
@@ -15,9 +15,6 @@
def available(self):
return 'yes'
- def tagsoup(self):
- return '<foo></bar>'
-
index = ViewPageTemplateFile('locals.pt')
@@ -30,6 +27,15 @@
index = ViewPageTemplateFile('options.pt')
+class SecureView(BrowserView):
+ index = ViewPageTemplateFile('secure.pt')
+
+ __allow_access_to_unprotected_subobjects__ = True
+
+ def tagsoup(self):
+ return '<foo></bar>'
+
+
class MissingView(BrowserView):
index = ViewPageTemplateFile('missing.pt')
@@ -49,6 +55,21 @@
result = view.index()
self.failUnless('Hello world!' in result)
+ def test_secure(self):
+ view = SecureView(self.folder, self.folder.REQUEST)
+ from zExceptions import Unauthorized
+ try:
+ result = view.index()
+ except Unauthorized:
+ pass
+ else:
+ self.fail("Expected unauthorized.")
+
+ from AccessControl.SecurityInfo import allow_module
+ allow_module("cgi")
+ result = view.index()
+ self.failUnless('<foo></bar>' in result)
+
def test_locals(self):
view = LocalsView(self.folder, self.folder.REQUEST)
result = view.index()
@@ -59,7 +80,7 @@
self.failUnless('here==container:True' in result)
self.failUnless("root:(\'\',)" in result)
self.failUnless("nothing:None" in result)
- self.failUnless("modules:<foo>" in result)
+ self.failUnless("rfc822" in result)
def test_locals_base(self):
view = LocalsBaseView(self.folder, self.folder.REQUEST)
Modified: five.pt/trunk/versions.cfg
===================================================================
--- five.pt/trunk/versions.cfg 2011-02-18 14:01:54 UTC (rev 120421)
+++ five.pt/trunk/versions.cfg 2011-02-18 14:47:59 UTC (rev 120422)
@@ -1,7 +1,7 @@
[versions]
chameleon.core = 1.0.4
chameleon.zpt = 1.1.3
-Chameleon = 1.2.3
+Chameleon = 1.3.0-rc1
z3c.pt = 1.2.1
zope.testing = 3.7.1
zope.i18n = 3.6.0
More information about the checkins
mailing list