It works as follows: I register context factories per route (as named
utility in the registry) and also use the route names as permission
names. The only thing the context factories need to compute
permissions is the logged-in user which is attached to the request and
the context object which they will either retrieve from the db
according to the request's matchdict or lookup as attribute on the
request. So to compute whether a user has permission to edit task 1,
I'd retrieve task 1 from the db, lookup the context factory for
'task.edit', attach the task object to the current request (possibly
to route task.index) and check the permission for this artificial
request.
The code I use looks similar to below (i've stripped out further
complicating details). The concrete authorization context for
'task.edit' would subclass AuthzContext, setting __object_class__ to
Task, and actually implement the allow_if method.

class AuthzContext(object):

    implements(IAuthzContext)
    __object_class__ = None

    def __init__(self, request):
        self.request = request
        self.object = None

        # make sure the reified attribute 'user' is instantiated
        self.user = request.user

        #
        # while it is the main responsibility of a AuthzContext to determine
        # the correct context object and attach ACEs to it, there's a shortcut
        # which allows passing in the context object as attribute of the
        # request. this mechanism can be used to compute permissions
"in advance"
        # i.e. without actually preforming a request. this allows us to keep
        # view permissions and links in sync.
        #
        if getattr(request, 'authz_object', False):
            self.object = request.authz_object
        else:
            self.object =
self.__object_class__.get(int(request.matchdict['id']), default=None)

        if not self.object:
            raise HTTPNotFound()

        self.object.__acl__ = []#[(Allow, 'group:admin', ALL_PERMISSIONS)]

        #
        # call the convenience methods which may be used to set ACEs:
        #
        if self.allow_if():
            self.allow()
        else:
            self.deny()

    def allow_if(self):
        return False

    def allow(self, permission=None):
        if self.request.user:
            self.object.__acl__ = [(Allow, self.request.user.login,
permission or getattr(self, 'name', 'none'))]
        else:
            # no user logged in but we still have to allow access:
            self.object.__acl__ = [(Allow, Everyone, permission or
getattr(self, 'name', 'none'))]

    def deny(self, permission=None):
        if self.request.user:
            self.object.__acl__ = [(Deny, self.request.user.login,
permission or getattr(self, 'name', ALL_PERMISSIONS))]
        else:
            self.object.__acl__ = [(Deny, Everyone, permission or
getattr(self, 'name', 'none'))]

def context_factory(authz_context):
    """We must make sure a new AuthzContext instance is created for
each request.
    Since __init__ must not return anything, we must use a helper function to
    mediate.
    """
    def context(request):
        _authz_context = authz_context(request)
        return _authz_context.object
    return context


def has_permission_on_object(permission, request, object_):
    """Compute object-specific permissions ahead of time, i.e. without
the object
    being determined from the request's properties. We still use the context
    factory to assign the same __acl__ to the object as would happen
with a "real"
    request. Thus, use this function to check whether a user (detemined by
    request) will have access to a specific action (determined by permission) on
    an object_.
    """
    context = request.registry.queryUtility(IAuthzContext,
name=permission, default=None)
    if context:
        request.authz_object = object_
        res = has_permission(permission,
context_factory(context)(request), request)
        request.authz_object = None
    else:
        res = has_permission(permission, RootFactory, request)
    return res




On Thu, Feb 16, 2012 at 8:44 PM, Mike Orr <[email protected]> wrote:
> On Thu, Feb 16, 2012 at 8:45 AM, Robert Forkel <[email protected]> 
> wrote:
>> My context factories can be used in a hybrid way. As regular context
>> factories they retrieve the object according to matchdict. But they can be
>> passed the object as well and then just compute the permission. So in the
>> Index i'd loop over all possible tasks and ask the factories for each route
>> whether the User gas this permission.
>
> How do you do this?
>
> --
> Mike Orr <[email protected]>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "pylons-discuss" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group at 
> http://groups.google.com/group/pylons-discuss?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.

Reply via email to