Recently at work I have been working on a project that has made me have to think about project flexibility in a whole new way. The project involves a service we are creating which companies will be able to purchase and label as their own. We plan on accomplishing this by making use of the Smarty Templating Engine and some server-side magic so that we only have one code base for infinite iterations of the service.
For the most part all of the underlying logic is identical, but Access Control has to be configurable on an individual company basis. Our company has three access levels which map basically to “Basic”, “Pro”, and “Premium”, but Company A may only have “Basic” and “Pro” while Company C may have “Basic”, “Pro”, “Premium”, and “Super-Epic-AwesomeTown”. To complicate matters further, the access levels are not strictly hierarchical. A user who registers on a site may have purchased the “Basic” package and the “Premium” package while opting not to purchase “Pro” or “Super-Epic-AwesomeTown”.
After researching PHP Access Control libraries for a while, I discovered nothing that seemed to meet my needs in an easy to use and flexible way. So, like any good nerd I decided to write and Open-Source my own.
Introducing PHP-Bouncer
PHP-Bouncer uses the idea of roles to manage permissions, so in the above examples “Basic”, “Pro”, “Premium”, and “Super-Epic-AwesomeTown” would map to roles each of which would give access to specific sets of pages. Each role also has the option to override a page from any other roles, so if “Pro” gives you access to a page called “Buy Premium”, Premium may override that page and send you to “Premium Home”. Roles are defined Like this:
$bouncer = new Bouncer(); // Add a role Name, Array of pages role provides $bouncer->addRole("Public", array("index.php", "about.php")); // Add a role Name, Array of pages role provides $bouncer->addRole("Registered User", array("myaccount.php", "editaccount.php", "viewusers.php")); // Add a role Name, Array of pages role provides List of pages that are overridden by other pages $bouncer->addRole("Admin", array("stats.php", "manageusers.php"), array("viewusers.php" => "manageusers.php"));
With our roles defined, we can now create some users and give them roles (NOTE: The User class in this example extends the BouncerUser class, which provides basic role management functionality and is totally optional):
// Here we add some users. The user class here extends the BouncerUser class, so it can still do whatever you // would normally create a user class to do.. $user1 = new User(); $user2 = new User(); $user3 = new User(); $user1->addRole("Public"); $user2->addRole("Registered User"); $user3->addRole("Admin");
And now, we take our users and our roles and check to see if they would have access to certain pages:
$bouncer->verifyAccess($user1->getRoles(), "index.php"); // True! $bouncer->verifyAccess($user1->getRoles(), "viewusers.php"); // False! User 1 does not have access to this page. $bouncer->verifyAccess($user2->getRoles(), "index.php"); // True! $bouncer->verifyAccess($user2->getRoles(), "viewusers.php"); // True! $bouncer->verifyAccess($user3->getRoles(), "index.php"); // True! $bouncer->verifyAccess($user3->getRoles(), "viewusers.php"); // False! As an Admin, viewusers.php has been replaced // with manageusers.php
This provides a good demo of how PHP-Bouncer works, but a better real-world example might be to include the following code in an include file on every page of your site:
$bouncer = new Bouncer(); $bouncer->addRole("Public", array("/index.php", "/test/test.php")); $bouncer->addRole("Private", array("/smartyTest.php")); $bouncer->addRole("Admin", array("/admin.php"), array("/smartyTest.php"=>"/admin.php")); $bouncer->addRole("Observer", array("/observer.php")); $publicOnly = array("Public"); $privateOnly = array("Private"); $observerOnly = array("Observer"); $adminOnly = array("Admin"); $allAccess = array("Public", "Private", "Admin", "Observer"); if(!$bouncer->verifyAccess($adminOnly, $_SERVER["PHP_SELF"])){ echo "Permission denied for page ".$_SERVER["PHP_SELF"]; exit; }
PHP-Bouncer is (at the time of this writing) only about 3 days old, and far from perfect/complete, so feel free to check out the Google Code page for additional documentation and to download bouncer!