In Django, there is no concept of "ownership"... You either have access
to edit objects or you don't... There is also no concept of read-only
permissions. (But I have a patch for this, that I'm testing now...)
So... does anyone have any thoughts on how to implement "ownership" in
Django? What would define "ownership"? (Any object you create and any
object you're granted permissions to edit? Do we need to track ownerhip
at the object level? How should we track 'sharing' permissions?
I'm kinda sad that Zope has what I need in this department, but I
prefer Django's object-relational mapping code. Are there any great
books on this topic? Or other projects to borrow ideas and learn from?
Would an ACL library (like phpGACL) solve my problem in this case?
Sorry, lots of questions here... Feel free to pick and choose and only
answer 1 of my questions if you have the time.
I was going to pull it out and re-use it in the project I am working
on, but I figure it is worth posting the concept in this thread to see
if people like it enough to explore generalizing it for Django.
Here is a quick overview of the structure of the code:
- Applications have Organizations (e.g. projects, forums, folders)
- Resources belong to Organizations (e.g. bug in project, topic in
forum)
- Resources have States (e.g. locked, pending, closed, public)
- Users have roles within Organizations (e.g. manager, admin,
moderator)
- Users have relationships to Resources (e.g. owner, editor,
chairperson)
- Policies are defined by Role, Relationship and State combination
allowed or disallowed
- Policies has an "is_allowed" method that takes a User and Resource
object and returns true or false based on its role/rel/state rules.
Here is an example of how to "build" a policy using the Policy API...
but this probably can be abstracted to a config file somehow (these are
the rules for a topic display view for a forum app that has both
private and public forums):
policy = Policy(name="Topic Display Policy")
policy.add_allowed(Roles.Administrator)
policy.add_allowed(Roles.Member)
policy.add_allowed(state=States.PublicView)
policy.add_allowed(Roles.RegisteredUser,
relationship=Relationships.Owner,
state=States.PublicPost)
And then:
policy.is_allowed(user, topic)
would return true if any of the following are true:
- The user is an Admin of the Forum
- The user is a Member of the Forum
- The resource has a "public view" state which it actually figures out
by asking the forum
- The wacky case of a forum that allows "public posting" but only
viewing by those who create the post (for a private forum that
outsiders can post into, but only see the topics they start)
That's all, if there is any interest in this little project, let me
know... I think it could fit in along side of the current ACL
solution... although it is definitely more complex. If it could be
pushed into Middleware somehow, I'd love to do that as well... I just
can't figure out how to do that.
thanks-
Ian
Right, I think my original use case is common to lots of people, and
I'm looking for help on the simplest way to solve it... Django
already provides core code for users, groups, and permissions... I'm
now looking for concrete examples and solutions on how to cleanly and
simply "fill the gap" between what Django provides and how to solve my
particular case. I hope I can do this without having to wait for a
rewrite of the Django auth system.
Without implementing a full blown ACL system... I have done a simple
"row level security" scheme in my Django views... Right before I
retrieve an object from the db, I append an additional where clause
criteria ('created_by__exact='bob') ... This is how I ensure that Bob
can only retrieve the things he created. But this scheme doesn't yet
cover the case where Finance creats objects for Bob. This way of adding
additional where clause criteria in the view is probably close to what
Robert Wittams suggested I do anyway (instead of looking to an ACL
system as my savior).
I'm kinda left with the impression, though, that with the web
frameworks I've recently had experience with (Rails, CherryPy, and now
Django), fine-grained authorization is left to the developer to figure
out... And those developers try in their own ways to come up with a
workable solution and maybe post a half-working example to the project
wiki. (I've seen this already for Rails and CherryPy.) But I know that
"security is hard" and I'm sure I'll be missing something if I hack
together my own solution, too.
-jason
> I don't think it is a maybe for django users/developers. If Django wants
> to take off it is going to need some type of ACL otherwise people are
> just going to develop their own and you will end up with a bunch of
> different implementations
Sorry, but that's a strawman. Django _has_ taken off without a
complicated ACL. It might not take off with you personally, but it did
in a broad scale. Hey, it's already flying for two years without fine
grained permissions.
I'm much with rjwilliams here: please don't go down the route of
full-blown ACL systems. It's ugly, icky and allmost allways not worth
it. Most ACL systems are tied to the logged in user - he's in a group
and that group has rights. But that's wrong more often than right:
users can have rights to objects based on some model state, but not
necessarily just because they are in some group. Think of company
resources, the boss and his second guy: the boss has all access to all
resources. The second guy has all access if the boss is not around. Put
_that_ down in Zope ACLs or try to model a ACL system that can take
stuff like that into account!
No, I think what would be needed is a simple framework that makes
permission calculation easier, but that still should be activated by
the model and the views. Preferreable by the model, because then the
automatic admin can take advantage by it.
So don't build a full blown ACL system, build a library of ACL
functionality, instead. In a way that makes it a just-one-call to check
wether a given user has a needed permission, so that you can use _that_
in your model code to make checks. And add some predefined Exceptions
that will be understood as "not authorized", so that the model
functions can throw that when they discover some situation where a user
is wrongly there - that way the automatic admin can show messages
accordingly.
Add to that a good request/response based transaction support and you
can just bail out and rollback if you discover that the user reached
areas that where not allowed to him.
That would be much more helpfull than hooking some ACL monster into all
of djangos machinery.
bye, Georg
Regards,
Laurent
Okay, I'm hearing lots of arguments and assertions without proof (from
anyone). Let's try to tone down the emotion here. I simply have a
business requirement that I need to figure out, and I'm kind of stuck
on how to proceed. Nothing more, nothing less.
A restatement of my original problem:
1) Bob has full access to "his" expense reports? (How do we define what
"his" reports are?)
2) Pam (A project manager) has view access to Bob's reports.
3) Fran (A finance department clerk) can create reports on behalf of
Bob. (After they're created, the reports are 'owned' by Bob.
4) Anyone in the AccountPayable group has full access to Bob's reports.
5) Bob only has view access to his reports if they are submitted. (This
is object-state dependent... and yes, perhaps ACL can't handle this.)
6) Here's another "really-nice-to-have" preference. I'd like to be able
to edit my fine grained permissions through the Django admin site. This
way, a security administrator wouldn't have to edit source code if/when
some new group needed access to someone's objects. And Bob could use
the web interface to select additional users that have access to his
reports.
Perhaps it's better if I write up some Django model code and then we
dissect *that*... Instead of dissecting the theory of ACL vs model
methods... If doing the auth in the model is easier to setup, use,
*and* maintain, then I'll do it... But, as you can tell because I asked
the original question... I need some help on *how* to do it. I started
with ACL because that is the "pattern" I can find the most
documentation on and the most real-world examples of. If there are
better examples, I'd like to *see* them.
-Jason
Would this be trickier if I want to allow a particular user or a group
to have access?
> 6) needs a little refinement - do you want to be able to change
> permissions on *anything* (in which case universally applying an ACL
> system to this particular app would work) or just on particular model
> classes?
I was thinking that it would be nice if Bob could "delegate" or "grant"
some rights that he has to others... If he can edit expense report #3,
he should be able to "grant edit" on #3 to a
> > Perhaps it's better if I write up some Django model code and then we
> > dissect *that*...
>
> Maybe if you stuck a model up on the wiki we could hash out the best way
> to do this.
>
> Note that I don't believe that it will necessarily be "nice" doing it in
> any way right now : the point of this exercise is to see how to extend
> django to make this stuff possible without burdening every app.
Hmmm... I might hold off on posting my model just yet... After some
more googling, I think I may have found what I'm looking for:
Fine Grained permissions with mod_authz_svn:
http://svnbook.red-bean.com/en/1.1/ch06s04.html#svn-ch-6-sect-4.4.2
A Python implementation of mod_authz_svn for the Trac project:
http://projects.edgewall.com/trac/wiki/FineGrainedPermissions
http://projects.edgewall.com/trac/ticket/157
http://projects.edgewall.com/trac/changeset/1450
The fine grained permissions configuration is relatively simple.
See the doctests for how easy it is to setup and use the scheme:
http://projects.edgewall.com/trac/browser/trunk/trac/versioncontrol/tests/svn_authz.py?rev=1450
I'm wondering what it would take to make this available as standalone
Python library... If it was standalone, I could use it (or not) in my
Django code, but I could also use it in my CherryPy code... or even
Plone!
-Jason