Skip to content
Share this..

Getting Started with ACL in CakePHP

2009 March 23
tags: , ,
by Eddie

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.

What is ACL?

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.

Why ACL?

Unless you want access to be all or nothing, then you need to consider ACLs. This allows some users here, and other users there.

How to get started with ACL

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.

The ACL Basics

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.

Migrating an Existing Site to ACL

First grab yourself a sheet of paper. Think about this…
The whos and whats of your site.  A simple example may look like this;

The Whos

Keeping it simple, we have users and admins.

---------------------------------------------------------------
  [1]users
 
    [4]Test
 
    [5]Jesse
 
    [6]Sister
 
  [2]administrators
 
    [3]Eddie
 
---------------------------------------------------------------

The Whats

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!

Now the Code to put it all together – acos, aros and aros_acos

This is a simple controller I roughed out to help implement ACL in one of my existing sites.

  • Start by initializing the tables with action initAcl.
  • Next assign permissions (connecting the who and whats)
  • Finally test out permissions
<?php
/*
 * Created on Mar 22, 2009
 *
 * @Author Eddie Webb
 * 
 * Set up basic ACL tables based on existing users
 * based on my readings of the book at cakephp.org 
 * 
 */
 class AclprepController extends AppController {
 
	var $name = 'Aclprep';
	var $uses =array('User');
	var $components =array('Acl');
 
 function initAcl()
	{
		//FIRST
	/*
	 * creat tables by running cake schema run create DbAcl
	 */
 
 
 
	/*
	 * Define our main user groups, to keep it simpel i have users and admins
	 */	
	 //always declare an Aro object to create and save
		$aro = new Aro();
 
	//iterate through groups adding to aro table
	$groups = array(
		0 => 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 <User/Model> <x> access <Model> ,<action>
		// 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

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');

Making Changes to ACO or ARO tables from the Database

Couldn’t resist huh, just had to know what the underlying tables looked like? Good for you. If your none too familiar with hierarchical structures in referential DB tables your probably wondering, what the deal with lft and rght, and why doesn’t just changing a parent ID move things around. (You may have discovered this trying to move yourself from users to administrators through the DB.)

For all the lovely details, may I suggest Nested Trees in CakePHP (though the article really applies more generally to nested lists in any referential Database)

21 Responses leave one →
  1. Anonymous permalink
    March 27, 2009

    Bless you. This was exactly the information I was looking for.

  2. Dan permalink
    April 14, 2009

    Thanks for the article. I learned a lot from it.

    I’m also trying to steer clear of the Auth component. Its very cool but coding my own feels better for a few reasons. It would be great to see a blog post from you on the workings of your own custom authentication system. I’m working on one now and would love some ideas on implementation.

  3. Eddie permalink*
    April 15, 2009

    @Dan
    Thanks for the feedback!

    I have been trying to think of a new article, and that is a great idea. Keep an eye out for it in the next few days, or subscribe to my RSS.

  4. Dan permalink
    April 17, 2009

    Sounds good Eddie. I’m looking forward to your post!

  5. Mark permalink
    June 11, 2009

    Nice article, Eddie. I partially understand the usefulness of this ACL component from, perhaps, a high-level. But I guess my question really is, “Why use these extra ARO/ACO and permissions tables when I can just execute a query that basically says, ‘Give access to the logged in user for all records with foreign key “user_id” that match the logged in user’?” It *almost* seems like duplicate work to store these extra entries when there is other data in tables that would produce that. I think it would be most helpful for individual record “DENY” entries for either a particular user or group.

    Does that make sense? Thoughts?

  6. Eddie permalink*
    June 14, 2009

    @Mark
    to be sure I understand,
    Your asking why you can’t just use the existing User and Posts table (for example) and track the allow/denies using those ids in a third table(permissions), eliminating the need for the two ACO and ARO tables.

    If so, I guess I have two answers. First you may want to control access to posts, comments, and proiles which all might have overlapping IDs, so any control table would need to understand which model is being checked. (it is Post 337 or comment 337?) Second the ACO and ARO tables allow for hierarchical information. Rather than assigning each admin the rights to edit you can just say that all admins have this right.
    Hope that answered your question

  7. May 3, 2010

    Thanks a lot for this ACL code. I was searched for this, its help me a lot.

    Thanks and Regards,
    Arya

  8. January 22, 2011

    Good tutorial. Might move to ACL now. Thanks for your work.

  9. Theodoro permalink
    August 12, 2011

    Excellent works.

    helped a lot..

    thanks

  10. Lesego Thekiso permalink
    September 25, 2011

    hi
    this has helped me this far,but now i want to see this in action,what other things do i need to add to my application for it to start denying the user access to pages,deleting or editing certain things.

  11. January 17, 2012

    I am trying to understand Acl with Cakephp, this article has helped a lot but I am still lost on some aspects. I understand the ARO, this to be pretty simple. It is with the ACO’s that I get lost on. Cake’s documentation doesn’t do justice to the ACO making it look like a flat tree. You actually add levels to it in this article which I think I like. So my question begins with do you have to list all models in this type of tree? For instance do I have to list the models that only the superuser (has access to the entire site) has access to? If so where would they end up in the tree (under entire site at the same level you have main_models and aux_models)?

    Next question is there an easy way to update permissions for users, or does this have to be done at he command line or through a function in a controller that is run from a browser? How do you go about changing a user from general user to admin?

    And lastly, do you know if the code supplied above works in version 2.x? Thanks for your time on this matter as I am finding it difficult to grasp the total concept of the Acl.

Trackbacks and Pingbacks

  1. Understanding Nested Lists in CakePHP | Edward A. Webb (.com)
  2. CakePHP Digest #11 - Food Metaphors | PseudoCoder.com
  3. Hello CakeWorld! » Blog Archive » CakePHP ACL
  4. CakePHP - Configuring ACL, Setting User Groups integration with Auth - Mark Evans - Web Consultant
  5. 13 excellent CakePHP tutorials | blogfreakz.com
  6. 2010-10-06 ACL development for BSF’s CakePHP driven website | Broken Sidewalk Farm
  7. 13 excellent CakePHP tutorials | WOPLL
  8. cakephp tutorial | Creative Star
  9. 20 Collection CakePHP Tutorials You Should Know | Daily Syntax
  10. Simpler role-based access control for CakePHP – jonisalonen.com

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS