I am using Pone 5.2.2 and want to achieve the following:
I've created a view every user can call (
permission="zope.Public"). That view retrieves some data through a GET request. Dependent on its value I want to call a different view in the context of an other user. The view to be called has the form of an usual HTTP request but the path is relative to the portal root.
Assume I want to call the view http://localhost:8080/mysite/secret.png/@@download in the context of the user "nicolas" but the original call is just an anonymous user with right GET request. How can I respond with
secret.png as long as
nicolas has the right permissions to see it?
I already tried this:
from plone import api
from AccessControl import ClassSecurityInfo, getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager, setSecurityManager
from AccessControl.User import Super
"""Unrestricted user that still has an id.
"""Return the ID of the user.
def executeAsUser(user, function, *args, **kwargs):
sm = getSecurityManager()
portal = api.portal.get()
tmp_user = UnrestrictedUser(
sm.getUser().getId(), '', api.user.get_roles(user = user), ''
# Wrap the user in the acquisition context of the portal
tmp_user = tmp_user.__of__(portal.acl_users)
# Call the function
return function(*args, **kwargs)
# If special exception handlers are needed, run them here
# Restore the old security manager
__call__ method of my view I then write this:
user = api.user.get(userid = 'nicolas')
if not user:
self.request.response.setStatus(401, reason = "Unauthorized. Access denied.", lock = True)
portal = api.portal.get()
lambda x: portal.restrictedTraverse(x).__call__(),
But this does not seem to work. I always get redirected to the login_form. I also tried an
unrestrictedTraverse() without the
executeAsUser but it also redirected me to the login form again.
In principle I want to make the outer view transparent to the user. I should simply call the other view in the context of a given user.
There's https://docs.plone.org/develop/plone.api/docs/api/env.html#plone.api.env.adopt_user that you use to switch user and then do a traverse etc.
I'm a bit confused on why you would want this. Unless you explicitly need the user
nicolas to end up in Z2 logs, I don't see why you cant simply allow View for Anonymous.
You also can use
portal.unrestrictedTraverse to get to the object?
Are you aware that the code inside a view is trusted? This means it can do anything unless this is explicitly protected (via calls to
validate check against the current user. To perform checks for a different user, you can either switch the user (with
newSecurityManager) or resolve the permissions into the roles granted this permission in the current context and then verify that the user has one of those roles.
If your purpose is not to check permissions for a different user but to allow a user to perform an operation (in a controlled context) for which he usually has not sufficient permission, you could use so called "proxy roles". You can setup proxy roles easily with
The idea behind that is that in the beginning Plone generates a temporary link which contains data which is secured using encryption and/or a signature. This link can be sent to anywhere, also to an other machine which knows absolutely nothing but that there is some data behind that link. If that link gets called Plone decrypts it and may has to impersonate a given user to access the requested data. This is just a second barrier where an admin could restrict access to the given object in between the creation of the link and when it finally gets opened.
That sounds promising. I will give it a try.
Even that was not possible and I don't know why.
I was not entirely aware of that. I remember I had to use the
executeAsUser method to call the
plone.api.content to move some objects around. But maybe these calls are protected by
Indeed. Moving, copying and (I think) deletion are some rare examples of functions with explicit internal security checks.
Interestingly this works:
But this does not:
I guess that the
__call__() makes the difference here. if you just want the object and change things
unregistrictedTraverse() is enough.