This sounds like a variation of record-specific permissions. I
structured it slightly differently in my application, which has both
advantages and disadvantages, but it might help.
My problem was that most users have read-only access to all incidents,
a few can read only certain incidents, and a few can create and edit
them. There's also another level of objects below them, and they may
have read or read-write access tot that.
All the principals are based on the user object. It has booleans and
role strings that imply certain principals, and integer arrays
(PostgreSQL ARRAY) telling which incidents they have incident-specific
permissions on. That might be analogous to a shared calendar. The user
object has a method, 'get_auth_groups()'. This returns a list of
principal strings, which includes groups like 'g:foo' and
'g:incident-1234-contrib'.
My authentication pollicy has a 'groupfinder' function that looks up a
user by ID, calls its '.get_auth_groups()' method, and returns the
result. I cache the result in Redis with a 15-minute TTL, but that's
optional.
The application uses URL Dispatch but has a small resource tree for
ACLs. From memory the code is something like this:
class Resource(object):
def __init__(self, parent, name):
self.__parent__ = parent
self.__name__ = name
class RootResource(Resource):
__acl__= [
(Allow, "g:responder", "view"), # View all incidents
]
def getitem(self, key):
return IncidentResource(self, key)
class IncidentResource(Resource):
def __acl__(self):
ret = []
principal = "g:incident-{}".format(self.__name__)
ret.append((Allow, principal, "incident") # View this incident.
principal = "g:incident-{}.contrib".format(self.__name__)
ret.append((Allow, principal, ("post.create", "post.edit"))
# Create and edit posts in this incident
def get_root(request):
return RootResource(None, "")
The top-level root factory is 'get_root'. Routes pertaining to a
particular incident have an "{incident}" routing variable (incident
ID), and their views are configured with 'traverse="/{incident}". The
net result is is that when the user goes to an incident URL or under
it, the context is for that incident ID. The user is granted
"incident" permission if they have the the global "g:responder"
principle or the incident-specific "g:incident-1234" principal.
The disadvantages of this approach is that you're doubling up on the
meaning of the "incident" permission, and it's cumbersome to parse
principal strings to determine which incidents to show links to. I ran
into both problems. My menu bar showed some items if the request has
"incident" permission, but that turned out to be wrong with
limited-incident users because they shouldn't have those menu items.
The home page also wants to show links to permitted incidents, and I
highly oppose parsing things out of strings unnecessarily (i.e., the
permitted incident IDs from the principals). So for those things in
the home page and layout, I go directly to the lower-level 'user'
attributes to determine which links to show, bypassing the Pyramid
principals. They should be the same if the code is correct because the
views use the user attributes, and 'get_auth_groups' uses the same
user attributes to calculate the principals.
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to
pylons-discus...@googlegroups.com.
> To post to this group, send email to
pylons-...@googlegroups.com.
> To view this discussion on the web visit
>
https://groups.google.com/d/msgid/pylons-discuss/1c20670e-6a5e-41b4-91c7-f0bc0d7f9071%40googlegroups.com.
> For more options, visit
https://groups.google.com/d/optout.
--
Mike Orr <
slugg...@gmail.com>