The ACL component of CakePHP can be a daunting undertaking for those new to CakePHP or ACLs. Once you take the plunge though you’ll never look back. The flexibility and power of the ACL component are worthy of your site, I promise. In order to help some fellow bakers into the water I wanted to offer some advice.
ACL, or Access Control List is a common means to control access to applications or sites at a granular level. The basic premise is simple, you have ‘whos’ and ‘whats’. The combination determines who can access what.
Unless you want access to be all or nothing, then you need to consider ACLs. This allows some users here, and other users there.
The first thing I find is that a lot of people seem to think ACL and Auth are useless with out each other. Although they compliment each other very nicely, the use of ACL does not require the use of Auth. To illustrate this point I’ll admit that I don’t even use Auth. :O But don’t tell anyone, they’ll take away my Baking degree. In fact I have developed a rather robust User model that handles authorization, registratoin, etc, etc quite nicely., but I am getting off topic. Just remember ACL determines who can do what, Auth determines how they get in.
I strongly suggest you check out the ACL section of the CakePHP Manual. If you can tolerate all the reference to Lord of The Rings, you’ll find the information you need. Just know that you want the Database method as appose to ini files.
First grab yourself a sheet of paper. Think about this… The whos and whats of your site. A simple example may look like this;
Keeping it simple, we have users and admins.
[1]users
[4]Test
[5]Jesse
[6]Sister
[2]administrators
[3]Eddie
This is where you need to really spend some time planning. Think about commonalities across models or areas of your site. Creating the right heirarchy will save alot of hassle down the road.
[1]Entire_Site
[2]Main_Models
[4]Users
[5]Toolboxes
[6]Items
[3]Aux_Models
[7]Actions
[8]Priorities
[9]Settings
[10]Botchecks
The key in my example is that Users should be able to create and read instances of the main models, but only read the auxiliary models. By collapsing these in a tree format I can just declare that explicitly at the Main and Aux levels, and let the sub-models inherit those permissions, neat!
This is a simple controller I roughed out to help implement ACL in one of my existing sites.
array( ‘alias’ => ‘users’ ), 1 => array( ‘alias’ => ‘administrators’ ), );
//Iterate and create ARO groups
foreach($groups as $data)
{
//Remember to call create() when saving in loops...
$aro->create();
//Save data
$aro->save($data);
}
/*
* next we add our existing add users to users group
* ! adds all users to user group, you may add some logic to
* ! detemrine admins based on role, or edit manually later
*
* the **whos**
*/
$aro = new Aro();
//pull users form existing user table
$users=$this->User->find('list');
debug($users);
$i=0;
foreach($users as $key=>$value){
$aroList[$i++]=
array(
'alias' => $value,
'parent_id' => 1,
'model' => 'User',
'foreign_key' => $key,
);
}
//print to screen to verify layout
debug($aroList);
//now save!
foreach($aroList as $data)
{
//Remember to call create() when saving in loops...
$aro->create();
//Save data
$aro->save($data);
}
/*
* now on to *whats* can they access
*
* for my layout I have the entire site as a parent, two sub groups that contain all models.
*
*/
$aco = new Aco();
//admin can access whole site
$controllers = array(
0 => array(
'alias' => 'Entire_Site'
),
);
//Iterate and create ARO groups
foreach($controllers as $data)
{
//Remember to call create() when saving in loops...
$aco->create();
//Save data
$aco->save($data);
}
$aco = new Aco();
//users have different permissions on Main and Auxilary models
$controllers = array(
0 => array(
'alias' => 'Main_Models',
'parent_id'=> '1'
),
1 => array(
'alias' => 'Aux_Models',
'parent_id'=> '1'
),
);
//Iterate and create ACO objects
foreach($controllers as $data)
{
//Remember to call create() when saving in loops...
$aco->create();
//Save data
$aco->save($data);
}
/*
* now the more details ACOs and their parents (refer to tree in post above)
*/
$aco = new Aco();
//Here's all of our sub-ACO info in an array we can iterate through
$controllers = array( 0 => array( ‘alias’ => ‘Users’, ‘model’ => ‘User’, ‘parent_id’ => 2, ), 1 => array( ‘alias’ => ‘Toolboxes’, ‘model’ => ‘Toolbox’, ‘parent_id’ => 2, ), 2 => array( ‘alias’ => ‘Items’, ‘model’ => ‘Item’, ‘parent_id’ => 2, ), 3 => array( ‘alias’ => ‘Actions’, ‘model’ => ‘Action’, ‘parent_id’ => 3, ), 4 => array( ‘alias’ => ‘Priorities’, ‘model’ => ‘Priority’, ‘parent_id’ => 3, ), 5 => array( ‘alias’ => ‘Settings’, ‘model’ => ‘Setting’, ‘parent_id’ => 3, ), 6 => array( ‘alias’ => ‘Botchecks’, ‘model’ => ‘Botcheck’, ‘parent_id’ => 3, ), );
//Iterate and create ACO nodes
foreach($controllers as $data)
{
//Remember to call create() when saving in loops...
$aco->create();
//Save data
$aco->save($data);
}
die; exit;
}
function assignPermissions()
{
//give admins rights to everything!(top aco)
$this->Acl->allow('administrators', 'Entire_Site');
//give users right to create and read main models
//updates and deletes are set at a user level (so only owners can edit or delete their items)
$this->Acl->allow('users', 'Main_Models','create');
$this->Acl->allow('users', 'Main_Models','read');
//let them use (read) aux, but nothing else!
$this->Acl->allow('users', 'Aux_Models','read');
die('done');
}
function checkPermissions()
{
//These all return true:
echo $this->Acl->check('administrators', 'Settings');
echo $this->Acl->check('users', 'Items','create');
echo $this->Acl->check('users', 'Actions','read');
//Remember, we can use the model/foreign key syntax
//for our user AROs
// think can access , // can User 2356 acsess Weapons
//$this->Acl->check(array('model' => 'User', 'foreign_key' => 2356), 'Weapons');
echo 'and dissallows...';
//But these return false:
//users can not delete or edit auxilary models (inherited) echo $this->Acl->check(‘users’, ‘Actions’, ‘delete’); echo $this->Acl->check(‘users’, ‘Actions’, ‘create’); //nor can they edit or delete main models (until we assign that on an individual basis) echo $this->Acl->check(‘users’, ‘Items’, ‘delete’); echo $this->Acl->check(‘users’, ‘Items’, ‘update’); die(‘done’); } } ?>
The final touches will come as you update or create your model actions. WHen a user creates a new Toolbox (for example) you will immediately grant that user update and delete privileges for that toolbox.
//example code when a user creates a model //let user with id 1234 update toolbox with id 5678 $this->Acl->allow(array(‘model’ => ‘User’, ‘foreign_key’ => 1234), array(‘model’=>‘Toolbox’,‘foreign_key’=>‘5678’), ‘update’);
Next time around you can use ACL to verify those rights to prevent anyone else the same privilege.
//example code when a user attempts action a model //can user with id 1234 in fact update toolbox with id 5678? $this->Acl->check(array(‘model’ => ‘User’, ‘foreign_key’ => 1234), array(‘model’=>‘Toolbox’,‘foreign_key’=>‘5678’), ‘update’);