Page 1 of 1

permissions system management

Posted: Thu Aug 28, 2008 5:45 am
by old_iron
Hi guys and girls,

I'm trying to rethink the way I do authentication in web apps, as so far I use a fairly 'clunky' system. Basically each action is a class which has a variable which defines which users can run this action and which not but that's just based off a numeric user level and sometimes that's not enough. plus it's not very manageable

I'm thinking of using a permissions system, the code would look like:

Code: Select all

 
class Controller {
   function run() {
       $permissions = new Permissions();
       if ($permissions->hasPermission($user, $action)) { 
          //$user, $action retrieved from request
          $action->execute();
       }
       else {
          //redirect to Error 401 page or something
       }
   }
}
 
I like the way this looks, but the problem is how to manage permissions. Different parts of the site will have different controllers (say a ForumController) and different permissions based on actions (i.e. DeletePost only available to admins, EditPost only available to admins or the owner of the post).

I was thinking every controller would have its own permissions object. So a ForumController would have a ForumPermissions object which had the logic for all the forum methods. I could store the permissions in a database but that would be fine for something like "Users with level x or higher can do action y" but in case of some actual logic (i.e. only an admin or the user who posts an article may edit that article - I can't store that in the database?).

Maybe I could define the permissions in XML files but that seems a bit insecure as they're just text files and viewable in a web browser.

Thanks in advance for any help, I see potential in this method but it's the management of it that I'm not sure how to handle.. :)

Re: permissions system management

Posted: Fri Aug 29, 2008 8:45 am
by ssssss
Here's what I do:

I have a users table with login info. I have a table called Permissions that has a row for every part of the site that someone may or may not be able to do. It's a table of strings like "Delete Post", "Add Post", "Edit Users", etc. And I have a cross reference table linking them together.

So when a user logs in, a user object is built and added to the session. The user object will have an array of Permission objects. It has a hasPermission() method. So to see if a user can do something, I write something like:
if($user->hasPermission(new Permission("Delete Post")) { ... }

It's basically string matching, and the Permission object is probably overkill. I'm interested in suggestions about how to handle that. In a couple of projects, the Permissions have categories that allow users to set other users as "Admin", "Regular", "Salespeople" etc. The code just adds or removes permissions from the cross ref table based on that selection. A user is never linked to a permission category in the DB.

I've found that most clients think of their users in a hierarchical way. So they usually start with some hierarchy like Regular Users, Managers, Admin Users. But they very, very often break that. One of their Regular Users will all of a sudden need to be able to see an Admin only report, but not something that Managers can do. They break the hierarchy all the time.

So this scheme allows for non-hierarchical permissions. The trade off is you end up with a lot of little permissions (often dozens). But it's very flexible and allows you to be very specific.

Let me know what you think.
- Scott

Re: permissions system management

Posted: Fri Aug 29, 2008 5:37 pm
by koen.h
You might want to look into role based access control. Zend Acl has a good documentation page of how you could implement that.

http://framework.zend.com/manual/en/zend.acl.html

Re: permissions system management

Posted: Sat Aug 30, 2008 2:13 pm
by old_iron
Koen, thanks, I saw Zend ACL and wanna do it much like that.

ssssss I like the way you do it as well, but if you don't have a hierarchy aren't things harder to manage?

Like if you have a 'view post' permission that anyone can use, you'd have to add like:
User | view post
Manager | view post
Admin | view post

But if it was like Admin extends Manager extends User (expressed in OO terms), you'd only have to do that once. You get the flexibility but that's a fair amount of redundant data isn't it? Plus if you need to change a permission you may need to change it in multiple places. If it works for you it's cool, but my first client had a system like that with lots of redundant data and it was a nightmare to fix..

I'm gonna do the cross referencing thing like you do, but am going to have a hierarchy like Zend_Acl. I think the one off exceptions when a User may have to see an Admin report can handled with an exception/assertion.

Like I'd have a
Admin | admin.view_report
User | admin.view_report (assert UserID = 'UserWhoCanLookAtAdminReports')

With the assertion, you could cover the case when a user has to see an otherwise admin-only report. And you could delete that particular permission at any point too. You could go a step further with the assertion to ensure that said user can only look at a particular report. (userId=xyz && reportId = 999 or whatever).

Re: permissions system management

Posted: Sat Aug 30, 2008 2:49 pm
by ssssss
The Zend ACL thing looks good, and if I had to do it all over again, I would look hard at that.

I ended up using my scheme because most of the systems I was working on were not hierarchical and those exceptions became overwhelming. Adding, removing and changing those exceptions required code changes and deployment. With my current scheme, all of the permission changes happen in the database, which means they can be made by the client in the UI somewhere. If the client wants to give some user an "extra" permission or deny them one, then they can go to the User Admin section of the site and check or uncheck a checkbox. The cross reference table is updated, and that's that.

There is a lot of data in the DB to do this. 10,000 users averaging 20 permissions gives you 200,000 rows in the cross reference table. But that's what databases are for! I like to think of the information as being very, very specific rather than redundant.

Just to explain the non-hierarchical nature of what I'm doing, assume you've got 6 features: A, B, C, D, E and F. And you've got 3 main user types (ignoring one-off exceptions).
Users of type 1 have access to features A, B and C.
Users of type 2 have access to features A, D and E.
Users of type 3 have access to features B, D and F.
In my world, some potential user will say, "I'd like features A, B, C and F, and I'll give you [my client] $1000 a month to use those features." So now I would have another user type to code in, because my client isn't going to turn down that offer. Before, that would mean going into all the code and the UI for those features and adding more IF statements, adding more where clauses to queries, etc. And, of course, all that had to be done immediately so that the client's client wasn't kept waiting.

Eventually they decide that type 2 should no longer have access to feature D. So that means some queries on the DB to figure out who all those users are and to delete rows from the cross reference table. But no code changes. Is that what you mean by "Plus if you need to change a permission you may need to change it in multiple places"?

Anyway, it works for me. Hopefully you're not in a situation where your user permissions shift around as much as mine tend to. I don't claim it's perfect by any stretch. If you look into the Zend ACL stuff, and it looks like it would handle the stuff I'm talking about, let me know and I'll definitely give it a longer look.

Re: permissions system management

Posted: Sat Aug 30, 2008 2:50 pm
by Christopher
You may want to try a little DI and allow Action controllers to implement methods that set or check Access Control.