[Zope] External Methods, Proxy Roles, and Executable Security
George Lee
georgeleejr at gmail.com
Sun Nov 20 12:47:51 EST 2005
Great, thanks much.
Is there much buzz about this in CMF developer land? It seems like
proper proxy roles handling, and like you said what Zope 3 security
will do to it, are pretty important and will come up quite often (all
I was doing, after all, was trying to move an object upon workflow
change!).
Peace,
George
On 11/19/05, Dieter Maurer <dieter at handshake.de> wrote:
> George Lee wrote at 2005-11-19 00:46 -0500:
> >In CMFCore 1.5.4:
> >
> >If a low-security-clearance user calls an external method that pastes
> >an object from a PortalFolder, he gets an error because the following
> >line in CMFCore.PortalFolder fails:
> >
> >if not sm.checkPermission(DeleteObjects, parent):
> > raise AccessControl_Unauthorized
> >
> >This is even the case if "sm.checkPermission" is changed to
> >"_checkPermission", which takes into account proxy roles. The external
> >method does not allow proxy roles attached, so I can't just add a
> >"Manager" proxy role.
> >
> >Because I called the pasting in an external method, I expected it to
> >go through without security problems! Is this a right expectation /
> >and a bug, or a wrong expectation?
>
> It is the fate induced by explicit security checks.
> It will get much worse when the Zope 3 security comes into
> Zope 2 land: then even trusted code will have to deal with
> security proxied objects.
>
>
> We currently work around the problem that trusted code
> cannot have proxy roles with the following class:
>
> class ProxyContext:
> def __init__(self, proxy_roles):
> self._proxy_roles = tuple(proxy_roles)
>
> def getOwner(self): return None
> getWrappedOwner = getOwner
>
> This class emulates an object with proxy roles and can be pushed
> onto the "SecurityManager"s "context" stack like so:
>
> sm = getSecurityManager()
> context = ProxyContext(proxy_roles)
> sm.addContext(context)
> try:
> # do something with "proxy_roles"
> ...
> finally: sm.removeContext(context)
>
>
> Note, that I had to fix (in a local copy) CMF's "_checkPermission"
> for this to work:
>
> It had decided to emulate Zope's proxy role checking only
> approximately -- incorrectly for a "None" owner.
>
> My fix looks like this:
>
> security.declarePrivate('_checkPermission')
> def _checkPermission(permission, obj):
> """ Check if the current user has the permission on the given object.
> """
> # this code is ported from ZopeSecurityPolicy.checkPermission
> roles = rolesForPermissionOn(permission, obj)
> if isinstance(roles, basestring):
> roles = [roles]
> context = getSecurityManager()._context
>
> # check executable owner and proxy roles
> # this code is ported from ZopeSecurityPolicy.validate
> stack = context.stack
> if stack:
> eo = stack[-1]
> owner = eo.getOwner()
> if owner is not None:
> if not owner.allowed(obj, roles):
> return 0
> # DM 2005-09-07: no reason to do it differently from Zope
> # It accepts "proxy_roles" even for a None owner
> ## proxy_roles = getattr(eo, '_proxy_roles', None)
> ## if proxy_roles:
> ## if obj is not aq_base(obj):
> ## if not owner._check_context(obj):
> ## return 0
> ## for r in proxy_roles:
> ## if r in roles:
> ## return 1
> ## return 0
> proxy_roles = getattr(eo, '_proxy_roles', None)
> if proxy_roles:
> if obj is not aq_base(obj):
> # DM 2005-09-07: do it as Zope does
> #if not owner._check_context(obj):
> if owner is not None and not owner._check_context(obj):
> return 0
> for r in proxy_roles:
> if r in roles:
> return 1
> return 0
>
> return context.user.allowed(obj, roles)
>
>
> If you are interested in using this approach, you
> should probably file another CMF bug report about the
> wrong handling of proxy roles in "_checkPermission".
> I explicitely allow you to attach the fix given above.
>
>
> --
> Dieter
>
More information about the Zope
mailing list