Monday, May 3, 2010

Users, Permissions, and the ACL

With frameworks inevitably comes the need to authenticate users and control permissions. In Wax, this need must be very carefully planned out, since the dynamic nature of the system allows for (almost) any object to have permissions on almost any other object. Let's consider a simple example: We have a Users object and a Tickets object. Regular users can view a list of tickets, while Administrators can CRUD the tickets. We want to make sure that these are the permissions applied in the system.

Creating a Model that has Permissions

As much as I would love to say that there is no coding involved in the creation of a login system, there are a few things that need to be done to make the system work properly.

Creating an Object with rLoginIdentifier and rPermissionHolder

The Wax DDM (Dynamic Data Model) provides two roles, rLoginIdentifier and rPermissionHolder which give regular old dumb objects the ability to act as smarter, permission having objects. First, an object must be created in the DDM. The object must contain a 'Username' field and a 'Password' field. Besides that you could store user information, last login information, etc., but 'Username' and 'Password' are all that are required. Secondly, the object must implement rLoginIdentifier and rPermissionHolder:
class Users extends DDM implements rLoginIdentifier, rPermissionHolder {}

That's pretty much it for the Login system

Implementing the rLoginIdentifier also gives the Users object the 'login' action, which actives the resource: /Users/login - which is the front-end to the login system. The Login system allows you to turn a regular dumb object into something useful with only 1 line of code (the Users class definition). Normally, the DDM handles all actions directed at a dynamic model, but in this case, we've overridden the basic DDM and given the Users object all of the dynamic functionality but added some additional functions as well.

Using the ACL

Using the ACL is just as simple as setting up a login system. In fact, half of setting up the login system is actually setting up the ACL. The rPermissionHolder role exposes 3 methods which interface with the Dynamic Data Model which allow for Getting/Setting permissions on resources.

Getting a User's Permissions

The User information is stored in the PHP $_SESSION object, which allows you to access the actual user information very easily ($_SESSION['User']). Using this information, an actual model can be instantiated:
$user = new Users($_SESSION['User']);
The permissions of any resource can then be checked with IsAllowed or GetPermissions.
if ($user->IsAllowed("SomeModel/modify")) {    
    // success
}
else {    
    // InvalidPermissionsException
}
$permissions = $user->GetPermissions();
/**
* Permissions would be something like:
* Array(
*    [SomeModel/] => 1,        // User has access to all function of SomeModel
*    [SomeModel/delete] => 0   // But there is also an explicit DENY to SomeModel/delete
* )
*/
By default, all permissions are denied for all users. Each ACL entry represents an ALLOW permission for some resource. As shown above, explicit DENYs can also exist, which is useful when you want to grant all permissions EXCEPT for some action-- in the above case, Deleting the objects is not allowed.

No comments:

Post a Comment