diff options
| author | Tres Seaver <tseaver@palladion.com> | 2012-12-23 20:54:14 +0000 |
|---|---|---|
| committer | Tres Seaver <tseaver@palladion.com> | 2012-12-23 20:54:14 +0000 |
| commit | 55e331efcb2cae2f6b570c82a76d9665a66ccedf (patch) | |
| tree | 11d0b7a89201fae03dd65a34b6b4251b6f29452a /src | |
| parent | 2b25f701924ea78cdc252e37db733274e3691fa4 (diff) | |
| download | zope-security-55e331efcb2cae2f6b570c82a76d9665a66ccedf.tar.gz | |
Move more narrative doctests into Sphinx.
Diffstat (limited to 'src')
| -rw-r--r-- | src/zope/security/untrustedpython/builtins.txt | 114 | ||||
| -rw-r--r-- | src/zope/security/untrustedpython/interpreter.txt | 112 | ||||
| -rw-r--r-- | src/zope/security/untrustedpython/rcompile.txt | 128 | ||||
| -rw-r--r-- | src/zope/security/untrustedpython/tests.py | 37 |
4 files changed, 0 insertions, 391 deletions
diff --git a/src/zope/security/untrustedpython/builtins.txt b/src/zope/security/untrustedpython/builtins.txt deleted file mode 100644 index 5ee1066..0000000 --- a/src/zope/security/untrustedpython/builtins.txt +++ /dev/null @@ -1,114 +0,0 @@ -Safe Builtins -============= - -When executing untrusted Python code, we need to make sure that we -only give the code access to safe, basic or proxied objects. This -included the builtin objects provided to Python code through a special -__builtins__ module in globals. The `builtins` module provides a -suitable module object: - - >>> from zope.security.untrustedpython.builtins import SafeBuiltins - >>> d = {'__builtins__': SafeBuiltins} - >>> exec 'x = str(1)' in d - >>> d['x'] - '1' - -The object is immutable: - - >>> SafeBuiltins.foo = 1 - Traceback (most recent call last): - ... - AttributeError: foo - - >>> del SafeBuiltins['getattr'] - Traceback (most recent call last): - ... - TypeError: object does not support item deletion - - - - Exception raised: - ... - TypeError: object does not support item deletion - -(Note that you can mutate it through its `__dict__` attribute, - however, when combined with the untrusted code compiler, getting the - `__dict__` attribute will return a proxied object that will prevent - mutation.) - -It contains items with keys that are all strings and values that are -either proxied or are basic types: - - >>> from zope.security.proxy import Proxy - >>> for key, value in SafeBuiltins.__dict__.items(): - ... if not isinstance(key, str): - ... raise TypeError(key) - ... if value is not None and not isinstance(value, (Proxy, int, str)): - ... raise TypeError(value, key) - -It doesn't contain unsafe items, such as eval, globals, etc: - - >>> SafeBuiltins.eval - Traceback (most recent call last): - ... - AttributeError: 'ImmutableModule' object has no attribute 'eval' - >>> SafeBuiltins.globals - Traceback (most recent call last): - ... - AttributeError: 'ImmutableModule' object has no attribute 'globals' - -The safe builtins also contains a custom __import__ function. - - >>> imp = SafeBuiltins.__import__ - -As with regular import, it only returns the top-level package if no -fromlist is specified: - - >>> import zope.security - >>> imp('zope.security') == zope - True - >>> imp('zope.security', {}, {}, ['*']) == zope.security - True - -Note that the values returned are proxied: - - >>> type(imp('zope.security')) is Proxy - True - -This means that, having imported a module, you will only be able to -access attributes for which you are authorized. - -Unlike regular __import__, you can only import modules that have been -previously imported. This is to prevent unauthorized execution of -module-initialization code: - - >>> security = zope.security - >>> import sys - >>> del sys.modules['zope.security'] - >>> imp('zope.security') - Traceback (most recent call last): - ... - ImportError: zope.security - - >>> sys.modules['zope.security'] = security - -Package-relative imports are supported (for now): - - >>> imp('security', {'__name__': 'zope', '__path__': []}) == security - True - >>> imp('security', {'__name__': 'zope.foo'}) == zope.security - True - - >>> imp('security.untrustedpython', {'__name__': 'zope.foo'}) == security - True - >>> from zope.security import untrustedpython - >>> imp('security.untrustedpython', {'__name__': 'zope.foo'}, {}, ['*'] - ... ) == untrustedpython - True - - - - - - - diff --git a/src/zope/security/untrustedpython/interpreter.txt b/src/zope/security/untrustedpython/interpreter.txt deleted file mode 100644 index dce15da..0000000 --- a/src/zope/security/untrustedpython/interpreter.txt +++ /dev/null @@ -1,112 +0,0 @@ -Untrusted Python interpreter -============================ - -The interpreter module provides very basic Python interpreter -support. It combined untrusted code compilation with safe builtins -and an exec-like API. The exec_src function can be used to execute -Python source: - - >>> from zope.security.untrustedpython.interpreter import exec_src - >>> d = {} - >>> exec_src("x=1", d) - >>> d['x'] - 1 - - >>> exec_src("x=getattr", d) - - -Note that the safe builtins dictionary is inserted into the -dictionary: - - >>> from zope.security.untrustedpython.builtins import SafeBuiltins - >>> d['__builtins__'] == SafeBuiltins - True - -All of the non-basic items in the safe builtins are proxied: - - >>> exec_src('str=str', d) - >>> from zope.security.proxy import Proxy - >>> type(d['str']) is Proxy - True - -Note that, while you can get to the safe `__builtins__`'s dictionary, -you can't use the dictionary to mutate it: - - >>> from zope.security.interfaces import ForbiddenAttribute - - >>> try: exec_src('__builtins__.__dict__["x"] = 1', d) - ... except ForbiddenAttribute: print 'Forbidden!' - Forbidden! - - >>> try: exec_src('del __builtins__.__dict__["str"]', d) - ... except ForbiddenAttribute: print 'Forbidden!' - Forbidden! - - >>> try: exec_src('__builtins__.__dict__.update({"x": 1})', d) - ... except ForbiddenAttribute: print 'Forbidden!' - Forbidden! - -Because the untrusted code compiler is used, you can't use exec, -raise, or try/except statements: - - >>> exec_src("exec 'x=1'", d) - Traceback (most recent call last): - ... - SyntaxError: Line 1: exec statements are not supported - -Any attribute-access results will be proxied: - - >>> exec_src("data = {}\nupdate = data.update\nupdate({'x': 'y'})", d) - >>> type(d['update']) is Proxy - True - -In this case, we were able to get to and use the update method because -the data dictionary itself was created by the untrusted code and was, -thus, unproxied. - -You can compile code yourself and call exec_code instead: - - >>> from zope.security.untrustedpython.rcompile import compile - >>> code = compile('x=2', '<mycode>', 'exec') - >>> d = {} - >>> from zope.security.untrustedpython.interpreter import exec_code - >>> exec_code(code, d) - >>> d['x'] - 2 - -This is useful if you are going to be executing the same expression -many times, as you can avoid the cost of repeated comilation. - -Compiled Programs ------------------ - -A slightly higher-level interface is provided by compiled programs. -These make it easier to safetly safe the results of compilation: - - >>> from zope.security.untrustedpython.interpreter import CompiledProgram - >>> p = CompiledProgram('x=2') - >>> d = {} - >>> p.exec_(d) - >>> d['x'] - 2 - -When you execute a compiled program, you can supply an object with a -write method to get print output: - - >>> p = CompiledProgram('print "Hello world!"') - >>> import cStringIO - >>> f = cStringIO.StringIO() - >>> p.exec_({}, output=f) - >>> f.getvalue() - 'Hello world!\n' - - -Compiled Expressions --------------------- - -You can also precompile expressions: - - >>> from zope.security.untrustedpython.interpreter import CompiledExpression - >>> p = CompiledExpression('x*2') - >>> p.eval({'x': 2}) - 4 diff --git a/src/zope/security/untrustedpython/rcompile.txt b/src/zope/security/untrustedpython/rcompile.txt deleted file mode 100644 index 919757e..0000000 --- a/src/zope/security/untrustedpython/rcompile.txt +++ /dev/null @@ -1,128 +0,0 @@ -================================== -Support for Restricted Python Code -================================== - -This package provides a way to compile -untrusted Python code so that it can be executed safely. - -This form of restricted Python assumes that security proxies will be -used to protect assets. Given this, the only thing that actually -needs to be done differently by the generated code is to: - -- Ensure that all attribute lookups go through a safe version of the getattr() - function that's been provided in the built-in functions used in the - execution environment. - -- Prevent exec statements. (Later, we could possibly make exec safe.) - -- Print statements always go to an output that is provided as a - global, rather than having an implicit sys.output. - -- Prevent try/except and raise statements. This is mainly because they - don't work properly in the presense of security proxies. Try/except - statements will be made to work in the future. - -No other special treatment is needed to support safe expression -evaluation. - -The implementation makes use of the `RestrictedPython` package, -originally written for Zope 2. There is a new AST re-writer in -`zope.security.untrustedpython.rcompile` which performs the -tree-transformation, and a top-level `compile()` function in -`zope.security.untrustedpython.rcompile`; the later is what client -applications are expected to use. - -The signature of the `compile()` function is very similar to that of -Python's built-in `compile()` function:: - - compile(source, filename, mode) - -Using it is equally simple:: - - >>> from zope.security.untrustedpython.rcompile import compile - - >>> code = compile("21 * 2", "<string>", "eval") - >>> eval(code) - 42 - -What's interesting about the restricted code is that all attribute -lookups go through the `getattr()` function. This is generally -provided as a built-in function in the restricted environment:: - - >>> def mygetattr(object, name, default="Yahoo!"): - ... marker = [] - ... print "Looking up", name - ... if getattr(object, name, marker) is marker: - ... return default - ... else: - ... return "Yeehaw!" - - >>> import __builtin__ - >>> builtins = __builtin__.__dict__.copy() - >>> builtins["getattr"] = mygetattr - - >>> def reval(source): - ... code = compile(source, "README.txt", "eval") - ... globals = {"__builtins__": builtins} - ... return eval(code, globals, {}) - - >>> reval("(42).__class__") - Looking up __class__ - 'Yeehaw!' - >>> reval("(42).not_really_there") - Looking up not_really_there - 'Yahoo!' - >>> reval("(42).foo.not_really_there") - Looking up foo - Looking up not_really_there - 'Yahoo!' - -This allows a `getattr()` to be used that ensures the result of -evaluation is a security proxy. - -To compile code with statements, use exec or single: - - >>> exec compile("x = 1", "<string>", "exec") - >>> x - 1 - -Trying to compile exec, raise or try/except sattements gives -syntax errors: - - >>> compile("exec 'x = 2'", "<string>", "exec") - Traceback (most recent call last): - ... - SyntaxError: Line 1: exec statements are not supported - - >>> compile("raise KeyError('x')", "<string>", "exec") - Traceback (most recent call last): - ... - SyntaxError: Line 1: raise statements are not supported - - >>> compile("try: pass\nexcept: pass", "<string>", "exec") - Traceback (most recent call last): - ... - SyntaxError: Line 1: try/except statements are not supported - -Printing to an explicit writable is allowed: - - >>> import StringIO - >>> f = StringIO.StringIO() - >>> code = compile("print >> f, 'hi',\nprint >> f, 'world'", '', 'exec') - >>> exec code in {'f': f} - >>> f.getvalue() - 'hi world\n' - -But if no output is specified, then output will be send to -`untrusted_output`: - - >>> code = compile("print 'hi',\nprint 'world'", '', 'exec') - >>> exec code in {} - Traceback (most recent call last): - ... - NameError: name 'untrusted_output' is not defined - - >>> f = StringIO.StringIO() - >>> exec code in {'untrusted_output': f} - - diff --git a/src/zope/security/untrustedpython/tests.py b/src/zope/security/untrustedpython/tests.py deleted file mode 100644 index 38c1b20..0000000 --- a/src/zope/security/untrustedpython/tests.py +++ /dev/null @@ -1,37 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Zope Foundation 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 python tests -""" -import unittest - - -def test_suite(): - import doctest - import re - try: - import RestrictedPython - from zope.testing import renormalizing - except ImportError: - return unittest.TestSuite() - - checker = renormalizing.RENormalizing([ - (re.compile(r"'ImmutableModule' object"), r'object'), - ]) - return unittest.TestSuite(( - doctest.DocFileSuite('builtins.txt', - 'rcompile.txt', - 'interpreter.txt', - checker=checker, - ), - )) |
