views:

579

answers:

2

Long story short: why does Zend ACL support multiple inheritance among roles and not resources?

I have a large tree of resources that I would like to be able to grant permissions on. In the past, what I have done to represent this is creating two different trees. The first one has a generic resource of each type in a tree. The second has all the instances of these types, arranged in the same manner. It would mean that if you were to super impose the trees you would find objects of the same type on the same level. Then, each object instance is set to have it's generic object from the first tree as an additional parent. This allows me to set default permissions for every type of object, so each instance will inherit them instead of me having to define them, but still gives me refined, specific access to each instance.

An example:

A site has 3 modules: users, where user profiles and whatnot are stored. forums, where lively discussions about current issues take place galleries, where users can upload photos of their pets

So, the generics tree mentioned above would look like this:

                        module
                    /     |     \
                  user  forum  gallery
                  /       |       \
               profile   topic    photo
                          |
                         post

And the instances tree would look like this:

                        module_1
        /     /     /      |           \        \           
    user1 user2 user3     forum     gallery1    gallery2
      |     |     |       /   \       /   \       /   \ 
profile profile profile  sub1 sub2  photo photo photo photo
                         |     / \
                     post1 post2 post3 

And in the ACL each user object instance would inherit from user in the first tree. So be default I want to make everything readable, so I allow read on module. Everything inherits from module, so it's all good. I also want users to be able to edit their profiles, so I grant edit to each user on their respective profile, the generics tree doesn't help here. Lets say my photo galleries are NSFW, so I want to deny read on them. With multiple inheritance, I can deny read on photo for any unregistered user, which is only one operation. Without multiple inheritance, I have to go through every photo and deny unregistered user the read privilege. If I have a lot of photos, this is bad news.

Does anyone know a way to do this? It provides the most flexible solution I can think of. If you can think of something better that can be implemented using Zend_Acl, please reply also!

Thanks very much.

A: 

I can't recommend anything directly from experience, I've done it the hard way a long time ago using several permissions per resource and it was a bit painful.

If I was writing ACL code now I'd probably take a look at this article on ACL resource types at http://codeutopia.net/blog/2009/02/11/zend_acl-part-2-different-roles-and-resources-more-on-access/ and perhaps parts 1 and 3 for inspiration.

Towards the end of the article there's talk of allowing read access across all resources and creating blanket allow/deny rules.

David Caunt
+2  A: 

Firstly, to answer you question re. multiple-inheritance of resources. Zend_ACL does not support that because your resources tree is designed to replicate the physical resources you are protecting. You simply can't have (for example) a file present in more than one parent directory.

So to provide you with a solution...

  • I assume your 'generics' tree is your resources.

  • Your roles should represent your user groups, so anonymous, registered, moderators, admins etc. Each more permissive role should inherit from the previous, so 'registered' would inherit from 'anonymous', 'moderators' from 'registered' etc. This allows each level to have all the rights of it's parent and then add some.

  • Assuming you use a structure like I have described, you would also use a privilege to assign the possible user actions. ie. 'view', 'edit', 'add' and 'manage' see link text

  • You need to assign 'view' rights to the anonymous role on 'module', there by giving read access to everyone.

  • You need to assign 'add' rights to the registered role on 'forum', there by giving both read (inherited from the anonymous role) and add to registered users.

  • You need to assign 'add' rights to the registered role on 'gallery', there by giving both read (again inherited) and add to registered users.

  • Rinse and repeat for moderators, admins etc etc.

  • To allow a user to modify their own profile, image uploads etc. you would not use ACL to handle interactions at this level. Simply create an isOwner method on any objects that represent resources (Image object, Profile object, etc) that will return a boolean based on whether the currently logged in user owns that item. This way you can then decide whether or not to allow that user to edit / delete / etc. that profile / image.

Hope this is useful!

antz29
Thanks for the answer! I see how a file can't belong to multiple directories, but there are instances in my application where resources belong to multiple parents. Is this bad practice? I have a community module in the application to add a little social networking spice, and they multiple and sometimes many administrators. I figured this would be better left to a simple ACL-stored-in-session check instead of rebuilding the list of allowed admins every time an edit action takes place. I'll agree that an isOwner method is simpler, but less flexible and I'd have to rewrite it for each module.
hornairs
Generally it would be seen as bad practice, but just because it could be a little confusing. If you would like to chat about your overall design maybe I might be able to help...
antz29
I still haven't gotten this to work. The requirements extend beyond the need for a simple isOwner method (or assertions) to blanket permissions for categories of posts. Do you think we could chat?
hornairs