[Zope-Checkins] CVS: Zope2 - restricted_module.py:1.1.2.1 security_in_syntax.py:1.1.2.1 testRestrictions.py:1.1.2.1
shane@digicool.com
shane@digicool.com
Tue, 24 Apr 2001 18:47:18 -0400 (EDT)
Update of /cvs-repository/Zope2/lib/python/RestrictedPython/tests
In directory korak:/tmp/cvs-serv10208/tests
Added Files:
Tag: RestrictedPythonBranch
restricted_module.py security_in_syntax.py testRestrictions.py
Log Message:
Created tests for the basic functionality of RestrictedPython.
--- Added File restricted_module.py in package Zope2 ---
def print1():
print 'Hello, world!',
return printed
def primes():
# Somewhat obfuscated code on purpose
print filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,20))),
return printed
def allowed_read(ob):
print ob.allowed
print ob.s
print ob[0]
print ob[2]
print ob[3:-1]
print len(ob)
return printed
def allowed_simple():
q = {'x':'a'}
q['y'] = 'b'
q.update({'z': 'c'})
r = ['a']
r.append('b')
r[2:2] = ['c']
s = 'a'
s = s[:100] + 'b'
s += 'c'
_ = q
return q['x'] + q['y'] + q['z'] + r[0] + r[1] + r[2] + s
def allowed_write(ob):
ob.writeable = 1
ob['safe'] = 2
def denied_getattr(ob):
return ob.disallowed
def denied_setattr(ob):
ob.allowed = -1
def denied_setitem(ob):
ob['x'] = 2
def denied_setslice(ob):
ob[0:1] = 'a'
def strange_attribute():
# If a guard has attributes with names that don't start with an
# underscore, those attributes appear to be an attribute of
# anything.
return [].attribute_of_anything
def order_of_operations():
return 3 * 4 * -2 + 2 * 12
def rot13(ss):
mapping = {}
orda = ord('a')
ordA = ord('A')
for n in range(13):
c1 = chr(orda + n)
c2 = chr(orda + n + 13)
c3 = chr(ordA + n)
c4 = chr(ordA + n + 13)
mapping[c1] = c2
mapping[c2] = c1
mapping[c3] = c4
mapping[c4] = c3
del c1, c2, c3, c4, orda, ordA
res = ''
for c in ss:
res = res + mapping.get(c, c)
return res
--- Added File security_in_syntax.py in package Zope2 ---
# These are all supposed to raise a SyntaxError when using
# compile_restricted() but not when using compile().
# Each function in this module is compiled using compile_restricted().
def overrideGuardWithFunction():
def _guard(o): return o
def overrideGuardWithLambda():
lambda o, _guard=None: o
def overrideGuardWithClass():
class _guard:
pass
def overrideGuardWithName():
_guard = None
def overrideGuardWithArgument():
def f(_guard=None):
pass
def reserved_names():
printed = ''
def bad_name():
__ = 12
def bad_attr():
some_ob._some_attr = 15
def no_exec():
exec 'q = 1'
--- Added File testRestrictions.py in package Zope2 ---
from string import rfind
import sys, os
if __name__=='__main__':
sys.path.append(os.path.join(os.pardir, os.pardir))
import unittest
from RestrictedPython import compile_restricted, PrintCollector
import security_in_syntax
def package_home(globals_dict):
__name__=globals_dict['__name__']
if __name__ == '__main__':
return os.getcwd()
m=sys.modules[__name__]
if hasattr(m,'__path__'):
r=m.__path__[0]
elif "." in __name__:
r=sys.modules[__name__[:rfind(__name__,'.')]].__path__[0]
else:
r=__name__
return os.path.join(os.getcwd(), r)
FunctionType = type(package_home)
def _getindent(line):
"""Returns the indentation level of the given line."""
indent = 0
for c in line:
if c == ' ': indent = indent + 1
elif c == '\t': indent = indent + 8
else: break
return indent
def find_source(fn, func):
"""Given a func_code object, this function tries to find and return
the python source code of the function. Originally written by
Harm van der Heijden (H.v.d.Heijden@phys.tue.nl)"""
f = open(fn,"r")
for i in range(func.co_firstlineno):
line = f.readline()
ind = _getindent(line)
msg = ""
while line:
msg = msg + line
line = f.readline()
# the following should be <= ind, but then we get
# confused by multiline docstrings. Using == works most of
# the time... but not always!
if _getindent(line) == ind: break
f.close()
return fn, msg
def create_rmodule():
global rmodule
fn = os.path.join(package_home(globals()), 'restricted_module.py')
f = open(fn, 'r')
source = f.read()
f.close()
# Sanity check
compile(source, fn, 'exec')
# Now compile it for real
code = compile_restricted(source, fn, 'exec')
rmodule = {'__builtins__':None}
for name in ('map', 'reduce', 'int', 'pow', 'range', 'filter',
'len', 'chr', 'ord',
):
rmodule[name] = getattr(__builtins__, name)
exec code in rmodule
create_rmodule()
class AccessDenied (Exception): pass
DisallowedObject = []
class RestrictedObject:
disallowed = DisallowedObject
allowed = 1
_ = 2
__ = 3
_some_attr = 4
__some_other_attr__ = 5
s = 'Another day, another test...'
__writeable_attrs__ = ('writeable',)
def __getitem__(self, idx):
if idx == 'protected':
raise AccessDenied
elif idx == 0:
return 1
elif idx == 1:
return DisallowedObject
else:
return self.s[idx]
def __getslice__(self, lo, hi):
return self.s[lo:hi]
def __len__(self):
return len(self.s)
def __setitem__(self, idx, v):
if idx == 'safe':
self.safe = v
else:
raise AccessDenied
def __setslice__(self, lo, hi, value):
raise AccessDenied
class TestGuard:
'''A guard class'''
def __init__(self, _ob):
self.__dict__['_ob'] = _ob
# Read guard methods
def __len__(self):
return len(self.__dict__['_ob'])
def __getattr__(self, name):
_ob = self.__dict__['_ob']
v = getattr(_ob, name)
if v is DisallowedObject:
raise AccessDenied
return v
def __getitem__(self, index):
# Can receive an Ellipsis or "slice" instance.
_ob = self.__dict__['_ob']
v = _ob[index]
if v is DisallowedObject:
raise AccessDenied
return v
def __getslice__(self, lo, hi):
_ob = self.__dict__['_ob']
return _ob[lo:hi]
# Write guard methods
def __setattr__(self, name, value):
_ob = self.__dict__['_ob']
writeable = getattr(_ob, '__writeable_attrs__', ())
if name not in writeable:
raise AccessDenied
if name[:5] == 'func_':
raise AccessDenied
setattr(_ob, name, value)
def __setitem__(self, index, value):
_ob = self.__dict__['_ob']
_ob[index] = value
def __setslice__(self, lo, hi, value):
_ob = self.__dict__['_ob']
_ob[lo:hi] = value
attribute_of_anything = 98.6
class RestrictionTests(unittest.TestCase):
def execFunc(self, name, *args, **kw):
func = rmodule[name]
func.func_globals.update({'_guard_init': TestGuard,
'_print_target_class': PrintCollector})
return func(*args, **kw)
def checkPrint(self):
res = self.execFunc('print1')
assert res == 'Hello, world!', res
def checkPrimes(self):
res = self.execFunc('primes')
assert res == '[2, 3, 5, 7, 11, 13, 17, 19]', res
def checkAllowedSimple(self):
res = self.execFunc('allowed_simple')
assert res == 'abcabcabc', res
def checkAllowedRead(self):
self.execFunc('allowed_read', RestrictedObject())
def checkAllowedWrite(self):
self.execFunc('allowed_write', RestrictedObject())
def checkDenied(self):
for k in rmodule.keys():
if k[:6] == 'denied':
try:
self.execFunc(k, RestrictedObject())
except AccessDenied:
# Passed the test
pass
else:
raise AssertionError, '%s() did not trip security' % k
def checkSyntaxSecurity(self):
# Ensures that each of the functions in security_in_syntax.py
# throws a SyntaxError when using compile_restricted.
fn = os.path.join(package_home(globals()), 'security_in_syntax.py')
f = open(fn, 'r')
source = f.read()
f.close()
# Unrestricted compile.
code = compile(source, fn, 'exec')
m = {'__builtins__':None}
exec code in m
for k, v in m.items():
if hasattr(v, 'func_code'):
filename, source = find_source(fn, v.func_code)
# Now compile it with restrictions
try:
code = compile_restricted(source, filename, 'exec')
except SyntaxError:
# Passed the test.
pass
else:
raise AssertionError, '%s should not have compiled' % k
def checkStrangeAttribute(self):
res = self.execFunc('strange_attribute')
assert res == 98.6, res
def checkOrderOfOperations(self):
res = self.execFunc('order_of_operations')
assert (res == 0), res
def checkRot13(self):
res = self.execFunc('rot13', 'Zope is k00l')
assert (res == 'Mbcr vf x00y'), res
def test_suite():
return unittest.makeSuite(RestrictionTests, 'check')
def main():
alltests=test_suite()
runner = unittest.TextTestRunner()
runner.run(alltests)
def debug():
test_suite().debug()
def pdebug():
import pdb
pdb.run('debug()')
if __name__=='__main__':
if len(sys.argv) > 1:
globals()[sys.argv[1]]()
else:
main()