I guess I'm doing something similar. At least as far as having
resource specific permissions. But I've chosen to implement this using
context factories. So the
resource_id = int(request.matchdict["resource_id"])
resource = DBSession().query(Resource).get(resource_id)
if not resource:
raise NotFound()
code which you have in the view is in my case part of the context
factory. Additionally, the context factory attaches a trivial __acl__
attribute to the context (allowing or denying the current user) to
make the standard authorization policy work.
On Thu, Aug 30, 2012 at 4:47 PM, Vlad K. <[email protected]> wrote:
>
> Hello all,
>
>
> I have an app with relatively complex security/permissions requirements and
> I decided to build it modeled after SELinux.
>
> The default Pyramid authz policy revolves around checking if a user belongs
> to a group, or has certain principal, the check of which is facilitated per
> view (with `permission` argument).
>
> In my app I have several roles and each role can only access some resources,
> and only perform some actions upon those resources (read, write, delete,
> ...), and the permission is not static per view, but depends on data
> retrieved from database according to some identifier given through
> matchdict.
>
> For example, "regular" users can create new and edit only own content of
> class X, Y, Z. Users belonging to a "editor" role can view other people's X,
> Y, Z but can't modify them except some properties thereof (like
> active/inactive). Perhaps editors can't write their own content, so they
> would only have `read` permission. Users belonging to a "billing" role can
> only view billing data of users, create invoices, activate/deactivate
> profiles, but not view or change their content, etc....
>
>
>
> I decided to make a class which I reify as request.permits property (via
> config.set_request_property()), then do a following check:
>
>
> @view_config(route_name="some_route", ...):
> def some_view(request):
> resource_id = int(request.matchdict["resource_id"])
>
> resource = DBSession().query(Resource).get(resource_id)
> if resource and not request.permit(resource, read=True):
> raise Forbidden()
>
> if not resource:
> raise NotFound()
>
> ...
>
>
> The permit() method is a __call__ method of the policy class. It does
> several things:
>
> 1. Checks the type of first parameter (the "tcontext" in SELinux lingo)
> 2. According to its type (isinstance), delegates check to a private method
> responsible for that resource class (content classes, menu links, ...)
> 3. The private method does whatever check required to see if the user
> (authenticated in the system with some principal like ID, the "scontext" in
> SELinux lingo) has access to the resource for given action (read, write,
> delete)
>
> Example checks (which would be policy rules in SELinux):
>
> # request.userauth is also an object created with
> config.set_request_property()
> if resource.owner_id == request.userauth.user_id and (read or write):
> return True
> if "required_role" in request.userauth.roles and (read and not write):
> return True
>
>
> etc... The default, of course, being no permission at all. It can be more
> DRY if the `permits` callable threw Forbidden() automatically, but I need it
> in the templates to return True or False which defines parts to be rendered.
> Alternatively I can supply a `nothrow=True` kwarg to return False instead of
> raising Forbidden().
>
> This way I maintain the policy in single file, the policy can be "pluggable"
> if required (instantiate different policy depending on configuration) and it
> can even be compounded with the view_config's permission argument, and the
> custom authorization policy factory which implements the proper interface.
>
>
> Too complicated? Overkill? Anyone doing something similar?
>
>
>
> --
>
>
> .oO V Oo.
>
>
> Work Hard,
> Increase Production,
> Prevent Accidents,
> and
> Be Happy! ;)
>
> --
> 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.