Grayda Posted January 7, 2009 Share Posted January 7, 2009 I'm building in some new security modules for my web application and need some help regarding a simple waterfall or path-building solution In my application, security is handled through a simple table like this: Username Access Group Edit Grayda somepage AdminGroup someotherpage guest [/td] BasePages BasePages main,header,footer AdminGroup main,header,footer [td]main,header,footer In this example, Grayda can access somepage and edit someotherpage and is also in the group "AdminGroup". Guest is a part of the group "BasePages". If you follow the table down, you will see the AdminGroup can access "main", "header" and "footer" and can also edit "main", "header" and "footer". "BasePages" is the same as "AdminGroup" but without the edit permissions. What I'm trying to build, is a function that will let me build a path from point A to B. For example if Grayda wants to access Main, and the path to Main is: Grayda -> AdminGroup -> BaseGroup -> CoreGroup -> Main then calling checkPermission("Grayda", "Main"); will return true because Grayda is in AdminGroup which points to BaseGroup etc. I've got simple one-level groups going on (eg. Grayda can access Main if it's only one level deep) but anything deeper eludes my knowledge. Can anyone give me some assistance or some ideas on where to start with this? Quote Link to comment Share on other sites More sharing options...
genericnumber1 Posted January 7, 2009 Share Posted January 7, 2009 The easiest way I can think of is to create a system in which permissions are given by the 1s and 0s (bits) in an integer. Take, for instance, these permissions: (binary added for clarity) <?php define('CREATE_POSTS', 1); // 0001 define('EDIT_POSTS', 2); // 0010 define('DELETE_POSTS', 4); // 0100 define('BAN_MEMBERS', ; // 1000 ?> Now that we have a few single action permissions, let's create permission groups. Say we want guests to have the ability to create posts, admins the ability to edit/delete posts (plus what guests can do), and super admins the ability to ban members (plus what admins can do)... <?php define('GUEST', CREATE_POSTS); // 0001 - Guests can create posts define('ADMIN', EDIT_POSTS | DELETE_POSTS | GUEST); // 0111 - Admins can edit posts, delete posts, and do what guests do define('SUPER_ADMIN', BAN_MEMBERS | ADMIN); // 1111 - Super admins can ban members, and do what admins do ?> Now we have a sample group of permissions, so let's try them out: <?php // Check whether the given user has the given permissions function hasPermission($user, $permissions) { return ($user & $permissions) > 0; } // Set the user to be a guest $user = GUEST; // Test our function hasPermission($user, CREATE_POSTS); // True - User can create posts hasPermission($user, EDIT_POSTS); // False - User can not edit posts // Set the user to be a super admin $user = SUPER_ADMIN; // Test our function hasPermission($user, BAN_MEMBERS); // True - User can ban members now hasPermission($user, EDIT_POSTS); // True - User can edit posts now hasPermission($user, CREATE_POSTS); // True - User can also create posts ?> Feel free to ask questions, and if you don't understand the bits with the | and & you may wish to look up how binary works and php's bitwise operators. Of course there are many other ways of doing this, but this is just the cleanest way for me to imagine it. Edit: For a little clarity and formatting. Quote Link to comment Share on other sites More sharing options...
Grayda Posted January 7, 2009 Author Share Posted January 7, 2009 Thanks for the information! I tried a sample implementation of your code and found that it was good for a fixed number of security levels and pages, but my application needed a little more dynamic-ness to handle custom pages and custom security levels. So I spent the last 3 hours poking around and came up with this which seems to work rather well so far: <?php // .. Some class code and variables here .. // Function checkPermission // $user = the username to check // $uAccess = the section the user is trying to access function checkPermission($user, $uAccess) { // This function fills up three variables: $this->access, $this->groups and $this->edit. // The data is pulled from the database and is split up using explode() $this->getPermissions($user); // First we loop through the groups we've got from the database for($i = 0; $i <= count($this->groups); $i++) { // I'm using ADOdb and some custom functions here. // This gets all the information related to the group in $this->groups[$i] (eg. AdminGroup or BasePages) $data = $this->database->getSQL("SELECT * FROM security WHERE Name = '" . $this->groups[$i] . "'"); // Now, we explode the information. First the groups related to $this->groups[$i] then access information then edit information $group = explode(",", @$data[0]["Group"]); $access = explode(",", @$data[0]["Access"]); $edit = explode(",", @$data[0]["Edit"]); // Now comes the magic. Looping! for($b = 0; $b <= count($group); $b++) { // If the groups aren't empty then: if(!empty($group[0])) { // Merge the results of $group and $this->groups $groupTemp = array_merge($this->groups, $group); // Then return only the unique groups. // When the loop goes back around, it will re-calculate count($this->groups) and keep going until we stop adding stuff to the array $this->groups = array_unique($groupTemp); } else { // But if the groups are empty, then we've come to the end of the line, so we // merge all the information we've got so far into our class variables obtained above $accessTemp = array_merge($this->access, $access); $this->access = array_unique($accessTemp); $editTemp = array_merge($this->edit, $edit); $this->edit = array_unique($accessTemp); } } // Same goes for the access for($b = 0; $b <= count($access); $b++) { if(!empty($access[0])) { $accessTemp = array_merge($this->access, $access); $this->access = array_unique($accessTemp); } } // And for edit for($b = 0; $b <= count($edit); $b++) { if(!empty($edit[0])) { $editTemp = array_merge($this->edit, $edit); $this->edit = array_unique($editTemp); } } } // Finally, once we have all the access, group and edit information we need, we check to see if $uAccess is in the arrays and if it is, then we return true, meaning they have access. PHEW! if(in_array($uAccess, $this->access) or in_array($uAccess, $this->edit) or in_array($uAccess, $this->groups)) { return true; } else { return false; } } ?> I tried it on some large group sets. (eg. guest -> blah1 -> blah2 ->blah3 ->blah4 -> blah5 -> main) and when I monitored the SQL calls through ADOdb, I got a series of calls to the right groups and at the end, it returned the data I was after. However, there might be some code optimizations I could make, and I should really test it with TONS of security objects. But for anyone out there looking for a way to do this kind of thing, this might be for you? Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 7, 2009 Share Posted January 7, 2009 Check out this ACL implementation I made: http://www.phreamp.org/trac/wiki/ACLUsage 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.