I had a requirement for Anonymous Users to add content to a designated folder in my Plone site. They submit a form, then the form handling code validates and creates an object. Simple. Or maybe not.
Proxy Roles exist for PythonScripts in Zope 2, but my form was a zope3-style browser view, so that wasn’t an option.
I struggled a lot with this, and after much googling and help from folks on #plone, I came up with this approach, using the AccessControl module that comes with Zope 2.
Here’s what it looks like:
... from AccessControl.SecurityManagement import newSecurityManager, getSecurityManager, setSecurityManager from Products.CMFCore.utils import getToolByName ... class MyViewClass(SomeBaseViewClass): # without going into detail here, assume that __init__ is passed a context and request object # that are set as instance properties. def someProcessorMethod(self): # I've created a folder called "Special Folder" at the root of my Plone site. portal = getToolByName(self.context, 'portal_url').getPortalObject() owner = portal['special-folder'].getWrappedOwner() # stash the existing security manager so we can restore it old_security_manager = getSecurityManager() # create a new context, as the owner of the folder newSecurityManager(self.request, user) try: # make the content portal['special-folder'].invokeFactory('Document', 'anonymous-content-ftw', title='Anonymous Content FTW!') except: # we want to ensure that setSecurityManager gets called # in reality you should do more here! pass # restore the original context setSecurityManager(old_security_manager)
That’s all there is to it. The nice thing about this approach is that the user who owns the special folder
could change, and the code will still work.
Be careful not to do this without very seriously considering the security rammifications, and be extra careful about
where you allow the view to be used.
For example, if you had used self.context.getWrappedOwner, and the view was mapped to ‘*’, imagine
the mess that could be made if the wrong anonymous user hit the view on every level of your site. :)
Special thanks to Mario Orlandi for this post, which is where I snagged the idea to use getWrappedOwner(). :)
EDIT: After posting this in #plone, petschki pointed out that I should wrap the content creation in a try block to catch exceptions, so I added that to the example code. This way the security manager will be restored even if there’s an exception during content creation.