I want to run some tests on a live site (e.g. to test configurations, user problems that only seem to appear on the live site, etc.). For this I have a browser view, that is typacally called by an admin user. But some problems have to do with security, and I want to test under a different user id. Also, code in browser views normally is unrestricted, so security doesn't really apply.
Inspired by kiorky in #plone@freenode and a somewhat related article I came to the following solution:
#inspired by http://lionfacelemonface.wordpress.com/2010/06/17/securitymanager/ from AccessControl.SecurityManagement import newSecurityManager, setSecurityManager, getSecurityManager from Products.CMFCore.utils import getToolByName from AccessControl.ZopeGuards import guarded_getattr, get_safe_globals, safe_builtins from RestrictedPython import compile_restricted def callAsUser(site,userid,code): #remember the current SecurityManager current = getSecurityManager() #switch to the selected user acl_users = getToolByName(site, 'acl_users') user = acl_users.getUserById(userid) newSecurityManager(None,user) #set the globals to somewhat safe values (that also do security checks) globals = get_safe_globals() globals['__builtins__'] = safe_builtins globals['_getattr_'] = guarded_getattr globals['site']=site #we want to allow printing in the code newcode = code + '\n\nprintresult=printed' #the ... magic! compiled = compile_restricted(newcode,'<string>','exec') exec(compiled,globals) #go back to original security manager setSecurityManager(current) #variable set in the code are in the returned dict, including printresult return globals
This would be used like this:
code = """ site.manage_changeProperties(title='foobar') print site.title x = 1 """ output = callAsUser(site,'SomeUser',code) output['x'] == 1 output['printed'] == 'foobar\n'