Xeoncross Posted February 22, 2008 Share Posted February 22, 2008 I need to figure out how to implement a user/group access control system. I started by creating roles (admin, mod, author, member) and then setting in a config file resources (like "add post") and the maximum level a user must be to access it. <?php if($resouce['level'] >= $current_user['level']) { allow; } else { deny; } ?> I made the "Admin" level "1" and everything else higher (mod = level 2 and so on). So if a resource demanded a level of a most "2" - then only mods and admins could access it. I figured I could store resources in a config file and just add to it whenever there was a new one. <?php $resouce = array('add post' => 2, 'edit post' => 2, 'read post' => 6); ?> I took a look at <a href="http://framework.zend.com/manual/en/zend.acl.html">Zend Framework</a> and found that while it was pretty much the same thing - it was a bit more structured. However, I didn't like the mess that it created: <?php require_once 'Zend/Acl.php'; $acl = new Zend_Acl(); require_once 'Zend/Acl/Role.php'; $acl->addRole(new Zend_Acl_Role('guest')) ->addRole(new Zend_Acl_Role('member')) ->addRole(new Zend_Acl_Role('admin')); $parents = array('guest', 'member', 'admin'); $acl->addRole(new Zend_Acl_Role('someUser'), $parents); require_once 'Zend/Acl/Resource.php'; $acl->add(new Zend_Acl_Resource('someResource')); $acl->deny('guest', 'someResource'); $acl->allow('member', 'someResource'); echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied'; ?> One object, two at most should be enough. Why there are 6 here is beyond me. However, since it is Zend I would expect them to know what they are doing. Now, how should I structure this system? should I try to store every resource and it's level in a DB table? What if there are 50 different resources? - I don't want to keep making calls to the DB every page. How should I build the user object? Does anyone have any ideas about this? Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 There is no easy answer to your question. Yes, Zend_Acl works fine, as long as you don't have too many "exception rules". As very short ACL goes a long way. As such, you can do something that I would normally (and do so in this case - but hey) frown upon: Serialized LOB. Just serialize the whole list and put it in the database. On every request you need to recreate it to check permissions and possibly modify it. I know, this ain't pretty, but the alternative you'll like even less. Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 Here is a basic ACL system I just plotted out. The basic idea is to check to see 1) is the user an ADMIN? 2) is the user level lower than the required level? (are they 1+ stronger) 3) if the user level is equal (allowed) -check to see if the author id is the same as the user id so that a runaway author doesn't destroy other authors work. Can anyone add to this? <?php ////////////////////////////////////// //We would need Three types of info to make a ACL //A list of resources $resources = array('plugin1' => array('edit' => 2, 'add' => 2, 'delete' => 1 ), 'plugin2' => array('view' => 4, 'add' => 3, 'delete' => 2 ) ); //A list of groups/roles $roles = array('', 'admin', 'mod', 'author', 'guest'); //a list of users $users = array('John' => 1, 'Jane' => 3); //We could make one global $user object that would have //the current users information. class user { //call a function here to fill this class with //the current users information (from a DB) var $data = array('id' => 4, 'name' => 'John', 'level' => 2); //Check the value of this users data function value($value) { return $this->$data[$value]; } function allowed($resource=null, $author_id=null) { //If they are admins allow anything if( ($this->data['level'] == 1) || //Or if the level of the user is less //than the level required. //(this lets them edit weaker users stuff) ($this->data['level'] < $resource) || ( //Or if the level of the user is equal //to the level required AND ($this->data['level'] == $resource) && //They are the author (only applies if author_id isset) (($author_id ? $this->data['id'] == $author_id : true)) ) ){ //print 'allow'; return true; } else { //print 'Deny'; return false; } } } //create the object $user = new user; if($user->allowed($resources['plugin1']['add'])) { print 'Allowed<br />'; } else { print 'Denied<br />'; } if($user->allowed($resources['plugin1']['delete'])) { print 'Allowed<br />'; } else { print 'Denied<br />'; } ?> The output if run is: Allowed Denied Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 You're going to run into a problem here: <?php //call a function here to fill this class with //the current users information (from a DB) var $data = array('id' => 4, 'name' => 'John', 'level' => 2); ?> Give it a try. I have the proper solution for you, but as I said, you're not going to like it. Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted February 22, 2008 Share Posted February 22, 2008 @Xeoncross: Then what would you do if you wished to add another group which has less rights than 'admin' but more rights than 'mod'? Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 You're going to run into a problem here: <?php //call a function here to fill this class with //the current users information (from a DB) var $data = array('id' => 4, 'name' => 'John', 'level' => 2); ?> Give it a try. I have the proper solution for you, but as I said, you're not going to like it. You call the DB $row of the authenticated user_id set in $_SESSION. then you place that row of data in the class - I already do it and it works fine. That way the current users data is only needed once for any plugin that wants it. @Xeoncross: Then what would you do if you wished to add another group which has less rights than 'admin' but more rights than 'mod'? This code is as much pseudo-code as it is real code. In reality you would use the group name instead of hard-coding the group number in, that way you COULD add more groups. <?php //A list of resources $resources = array('plugin1' => array('edit' => 'admin', 'add' => 'mod', 'delete' => 'admin' ), 'plugin2' => array('view' => 'guest', 'add' => 'aurthur', 'delete' => 'mod' ) ); ?> Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted February 22, 2008 Share Posted February 22, 2008 How would you do that? Your authorization check is based on checking if integers are greater or lower than another integer. Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 I admit, I didn't really examine your code. But, your title says you're using ACL, and you are in fact NOT, hence my misinterpretation. If 'John' was an 'admin' and admins get level 2, how do I dissallow anything that admins would be allowed? I think you need to look into ACL. Sure, you can make this work, but it's not ACL, and will never be as flexible. Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 How would you do that? Your authorization check is based on checking if integers are greater or lower than another integer. Perhapes it isn't ACL - but it is a User Permissions system. Can't you imagine a more complex array? <?php $resources = array('plugin1' => array('edit' => 'admin', 'add' => 'mod', 'delete' => 'admin' ), 'plugin2' => array('view' => 'guest', 'add' => 'aurthur', 'delete' => 'mod' ) ); //A list of groups/roles $roles = array('admin' => 1, 'mod' => 2, 'author' => 3, 'guest' => 4); if($user->allowed($roles[$resources['plugin1']['delete']])) { ?> Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 Again, you can make this work. In fact, I imagine you can make it even simpler with the same functionality. But it's not by far as flexible as ACL. Aside from my previously posted question, which you've avoided, let me ask you another, more pressing question: What if I request plugin9999999999999999? Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 Sorry, you had posted your last question after I had already requested the reply form. At any rate, would you re-fraze the question? I don't understand what you're saying. If 'John' was an 'admin' and admins get level 2, how do I dissallow anything that admins would be allowed? let me ask you another, more pressing question: What if I request plugin9999999999999999? What is the problem? go ahead and request it. If the value is not in the array (null/false) we will do a check and default to false. Also, would you mind sharing any links you have on ACL? Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 Sorry, you had posted your last question after I had already requested the reply form. At any rate, would you re-fraze the question? I don't understand what you're saying. Simple: if admins are allowed to edit plugin1, how do say that John, who is an admin, is not allowed to do so? What is the problem? go ahead and request it. If the value is not in the array (null/false) we will do a check and default to false. You're ignorant of the underlying issue. Doing so would would imply that I would have to explicitly define elaborate rules for EVERY resource available in the system. Imagine a system as populated as the PHPFreaks forums. If I need to establish rules for every post, that would result in a HUGE database and the processing time accompanied with it. You can add so called exception logic, as you did with by assigning special rights to authors, but again, this is not flexible. As I said, try and map it to the database. Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 Simple: if admins are allowed to edit plugin1, how do say that John, who is an admin, is not allowed to do so? "how do say that John" makes no sense to me If you asking "If admins are allowed to edit "plugin1"; how is it that "John" (who is an admin) is not allowed to do so?" The answer is that IF John is apart of the "Ultimate/admin/whateversuperuseriscalled" group - he can do anything. You're ignorant of the underlying issue. Doing so would would imply that I would have to explicitly define elaborate rules for EVERY resource available in the system. Imagine a system as populated as the PHPFreaks forums. If I need to establish rules for every post, that would result in a HUGE database and the processing time accompanied with it. For a system like SMF you would have three rules - hardly elaborate. Level to post posts Level to edit own posts Level to delete posts Then only users with the same id as the post id (or 1up in level from the level stated || or level "ADMIN") could edit/delete posts. I would imagine that this system would take about 30 rules for a complex site like this. As I said, try and map it to the database. Yes, that is the real test. CREATE TABLE `roles` ( `id` INT( 2 ) NOT NULL , `name` VARCHAR( 100 ) NOT NULL , `weight` INT( 2 ) NOT NULL ) CREATE TABLE `resources` ( `id` INT( 10 ) NOT NULL , `name` VARCHAR( 100 ) NOT NULL , `plugin` VARCHAR( 100 ) NOT NULL , `role` INT( 2 ) NOT NULL , PRIMARY KEY ( `id` ) ) The "plugin" column would be for something like "posts" that way you could group "edit", "add", and "delete" by "plugin" Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted February 22, 2008 Share Posted February 22, 2008 Simple: if admins are allowed to edit plugin1, how do say that John, who is an admin, is not allowed to do so? "how do say that John" makes no sense to me If you asking "If admins are allowed to edit "plugin1"; how is it that "John" (who is an admin) is not allowed to do so?" The answer is that IF John is apart of the "Ultimate/admin/whateversuperuseriscalled" group - he can do anything. He asked how you would deny John access despite the fact that he is in the admin group. Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 He asked how you would deny John access despite the fact that he is in the admin group. That is impossible. Why would you deny the highest level user? You are thinking about this too literally. Don't let the fact that I choose to call that group "admin" and the fact that other sites have groups called "admin" mess you up. You can call it "admin", you can call it "super user" you can call it whatever you want - but if they are in that group THEY control all. If John isn't trustworthy - place him in a group called "Site Admin" that is less than "Admin". Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted February 22, 2008 Share Posted February 22, 2008 It is possible, just not with your system. It doesn't matter whether it's the admin group, you could say it like this too: Group X has access to resource Y and Z. User A is part of group X, but should still not have access to resource Y. Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 Or, John is just a regular user, normally not allowed to view admin topics, but on this particular topic, he can view it. Quote Link to comment Share on other sites More sharing options...
Liquid Fire Posted February 22, 2008 Share Posted February 22, 2008 I never got the point of using a binary number to deterimine a permission level, it always seemed to be much more complicated than it needs to be. Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 Or, John is just a regular user, normally not allowed to view admin topics, but on this particular topic, he can view it. That is a good point and a valuable thing for complex sites. However, I don't think that average small sites would have that problem - and even if they did there are other ways of getting around it. In all my sites I know that I have never had that need. What if we just leave that part off for now? Unless of course that is the only thing separating my idea from a valid ACL...? Quote Link to comment Share on other sites More sharing options...
448191 Posted February 22, 2008 Share Posted February 22, 2008 Unless of course that is the only thing separating my idea from a valid ACL...? It is not. Your idea is conceptually different from ACL. You can add exception rules, but that doesn't make it nearly as flexible as ACL. EDIT: A word of advice: just use Zend_Acl and store the ACL serialized. It'll do what you want and more, no reason to reject it. Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 A word of advice: just use Zend_Acl and store the ACL serialized. It'll do what you want and more, no reason to reject it. It appears that Zend_ACL only works within the Zend environment. But I found a nice example here. EDIT: Cool, one hundred posts Quote Link to comment Share on other sites More sharing options...
Xeoncross Posted February 22, 2008 Author Share Posted February 22, 2008 Ok, I finally finished a working version of this idea. This is a Object based script that will demonstrate a basic Permission system. The only thing that I am worried about is the fact that I have to query the database for all the resources/rules. Which means it takes over .004 seconds for the whole script to run. To run this script: First, run tables.sql on your MySQL databse. Second, open db.php and add your db info. Third, browse to ../acl.php Let me know what you think Quote Link to comment Share on other sites More sharing options...
448191 Posted February 23, 2008 Share Posted February 23, 2008 It appears that Zend_ACL only works within the Zend environment. Hardly true. AFAIK, only dependency it has is Zend_Exception. And this is the WHOLE of Zend_Exception (minus docs): class Zend_Exception extends Exception {} Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.