Using AuthComponent and ACL in CakePHP 1.2

19 07 2007

The uniqueness issues and also an issue with inheritence has been solved in changset 5588

Important Update (2007-07-24) : Brian brought to my attention a problem with multiple actions that have the same name. This problem is due to an incorrect Sql query in db_acl.php. I have filed Trac Ticket #2976 which includes a patch, unit test and test fixtures.

So I’ve shown you how to create a User Model that can be used for ACL, but what is next?

The AuthComponent allows you to both authenticate and authorize your users in a relatively simple manner – once you know how. This took me a lot of source code digging, mail list browsing and googling to find the way that “just works”.

Setting up Aco’s, Aro’s and Permissions

First of, we need to have some Aro’s and Aco’s. Aro’s are the User model from above and are simple enough – you can get away with scaffolding if you want.

Aco’s took me a little longer to figure out. There are going to be controller action pairs, naturally, but the catch was how to put these into the database. It turns out that you need to have Controllers at one level, with actions children of there respective controllers. This might seem obvious but I was trying to save the actions with an alias of “controller/action” when they should just be “action”.

Your tree of Aco aliases should look like the following:

ROOT
|-Controller1
  |-index
  |-action1
  |-action2
|-Controller2
  |-index
  |-action1

Pretty straight forward once you know how. This way the path can be followed down (or up actually) by the AclComponent. It also allows you to create wholesale permissions such as denying a whole controller by setting the permissions on the controller level.

Then all you need to do is grant Users access to actions. Because we are using User models the easist way is with a series of commands like:

$this->Acl->allow(array('model' => 'User', 'foreign_key' => $id), 'Controller1/action');

Using AuthComponent for Authentication

The AuthComponent is a really great tool and is very flexible. This post will only show one way to use it, but there are many other ways to put it to use.

First up, we will use AuthComponent for authentication. This part is pretty straight forward, but requires a little configuration. The best place to do this is in AppController::beforeFilter().

You need to include the AclComponent and the AuthComponent in AppController.

var $components = array('Acl', 'Auth');

It is very import that you include the AclComponent before the AuthComponent otherwise you will get this funky error message.

Fatal error: Call to a member function check() on a non-object in /var/www/geoff/cake/cake/libs/controller/components/acl.php on line 87

The reason for this is that Components are started in the order they appear in the $components list, and the AuthComponent does all its magic at startup, so when Auth tries to use Acl::check() there is no Acl.

For authentication we need to set the loginAction and loginRedirect properties.

function beforeFilter(){
  if (isset($this->Auth)) {
    $this->Auth->loginAction = '/users/login';
    $this->Auth->loginRedirect = '/users/account';
  }
}

You can also set the fields that are used for authentication if your user model does not use the default of ‘username’ and ‘password’.

$this->Auth->fields = array('username' => 'login_name', 'password' => 'p4sswrd');

It is worth noting that the AuthComponent will hash the password for security reasons. This is default behaviour and it can not be overriden. Where I got caught out (again) was that I had a before save on my user model that hashed the password in the same manner as AuthComponent. Do not hash your passwords at the model level if you have included the AuthComponet at the AppController level. The AuthComponent will hash it before it gets to your beforeSave and you will end up with double hashed passwords in the database and therefore unable to login.

Another good config option is the userScope property. It allows you to add other conditions to the authentication query, such as checking a disabled field.

 $this->Auth->userScope = array('User.disabled' => 0);

Using AuthComponent for Authorization

So that was how to set your authentication. Setting up AuthComponet for authorization against ACL is actually easier. One extra line of code.

$this->Auth->authorize = 'actions';

This will use the User Aro’s created above that corresponds to the User just authenticated, and test it against the current controller and action. Surprisingly easy. :)

Final Result

The final AppController should look like:

class AppController extends Controller {
  var $helpers = array('Html', 'Javascript', 'Form');
  var $components = array('Acl', 'Auth');
  var $publicControllers = array('pages');
	
  function beforeFilter(){
    if (isset($this->Auth)) {
      $this->Auth->userScope = array('User.disabled' => 0);
      $this->Auth->loginAction = '/users/login';
      $this->Auth->loginRedirect = '/users/account';
      $this->Auth->fields = array('username' => 'username', 'password' => 'passwrd');
      $this->Auth->authorize = 'actions';

      if (in_array(low($this->params['controller']), $this->publicControllers)) {	
	    $this->Auth->allow();	
      }
    }
  }
}

$this->publicControllers allows you to assign controllers which do not require authentication or authorization. I mainly use it to grant access to the pages contoller.

About these ads

Actions

Information

73 responses

19 07 2007
Felix Geisendörfer

Yet another good post! Just added a you to my blogroll – keep up the good work ; ).

Question: Wouldn’t it make sense to have a root aco element like ‘Controllers’ and put all controllers in there? Because that way it would possible to grant Admins access to all controllers at once.

Also, any good ideas about how to manage Acl permissions in a multi-developer project where new actions / controllers are constantly being added? My current solution is to make Acl only display if it is blocking access or not rather then doing it while DEBUG > 0.

19 07 2007
Geoff

Hey Felix,

There is a ROOT Aco that I use at the top of the tree, for exactly the purpose of granting sitewide access.

As for the new Controller/actions problem, I have written a controller for managing these that I am currently refactoring into a component. It looks at all controllers, including plugin controllers, and grabs a list of all the actions. ATM these are displayed as a list with checkboxes and imported into ARO’s on submit. It is duplicate aware as well :). I also want to make a “Import/Update all” option. This way when you add some new functionality you can simply go to e.g. /permissions/import/acos/all

BTW most of the heavy lifting in the component is inspired by Marios phpGacl component.

Oh and thanks for the link :D

19 07 2007
francky06l

Great article Geoff,

I am impatient to use your component. I left some comment in the cakePhp group, I will post here if I have more..

Thanks

19 07 2007
PHPGeek » Using AuthComponent for Access Control in CakePHP

[…] why, when an article on AuthComponent for CakePHP came across the CakePHP mailing list this morning, I jumped on it. AuthComponent is the de facto […]

21 07 2007
PHPDeveloper.org

PHPGeek.com: Using AuthComponent for Access Control in CakePHP

21 07 2007
developercast.com » PHPGeek.com: Using AuthComponent for Access Control in CakePHP

[…] points out the solution he came across via another article from the “Another Cake Baker” blog (lemoncake) show how to use the component for ACL in […]

21 07 2007
Brian

How do you use Auth and ACL together and tie it into the parentNode association with Groups? I added the parentNode function from your previous example to my User model, and it never appears to be executed at all (checked by placing a ‘die()’ in the function). It’s looking for a User ARO with the foreign_key as User.id, rather than searching for Group and Group.id.

21 07 2007
Geoff

Brian,

Take a look at my Groups with ACL post. It explains how to put your users as children of groups allowing you to use group level access.

24 07 2007
Brian

I read your article, but the problem is that I didn’t understand that the parentNode() function was only executed when you modify the record, not just when you access it. So I got that part figured out, but here’s where I’m having some trouble…

I am using the groups, but when I go in to add new actions that I want to authorize, it’s authorizing the action for *all* controllers (authorizing users/index also authorizes groups/index, houses/index/, and otherstuff/index).

I’ve got a tree that looks just like the example you provide above, but even though this group is not authorized for the “users” controller, it still approves access because they ARE authorized for Groups/index. Am I structuring the ACOs incorrectly? I used the cake console to create the acos:

537 cake acl create aco / ROOT
544 cake acl create aco ROOT Groups
545 cake acl create aco Groups index
546 cake acl grant Administration Groups/index ‘*’

Then when you visit /users/index you SHOULD be denied, because the Users controller isn’t even an ACO. The following SQL executes (shown in the debug log):

SELECT Aco.* From acos AS Aco LEFT JOIN acos AS Aco0 ON Aco0.alias = 'index' LEFT JOIN acos AS Aco1 ON Aco1.lft > Aco0.lft && Aco1.rght < Aco0.rght AND Aco1.alias = 'Borrowers' WHERE Aco.lft = Aco0.rght ORDER BY Aco.lft DESC

You get three results:

+----+-----------+-------+-------------+---------+------+------+
| id | parent_id | model | foreign_key | alias | lft | rght |
+----+-----------+-------+-------------+---------+------+------+
| 5 | 4 | | NULL | index | 3 | 4 |
| 4 | 1 | | NULL | Lenders | 2 | 5 |
| 1 | NULL | | NULL | ROOT | 1 | 10 |
+----+-----------+-------+-------------+---------+------+------+

And it approves the page! Where am I messing up? How did you initially create your acos?

24 07 2007
Geoff

Brian,

This is an issue that I have recently run into as well. It appears that when you have multiple actions with the same name as children of different controllers, as in the index example, it messes up which parent it belongs to, and thereby stuffing up your ACL rules.

I believe it is a problem with the AclNode and as such the code in the tutorials *should* be accurate.

You’ll notice that your sql is looking for ‘Borrowers’ and getting ‘Lenders’. This sql statement is constructed in AclNode , which leads me to believe that the problem lies here.

I will investigate and reply ASAP.

Edit: See update at top of post

Geoff

30 07 2007
Gorka

How do you handle ‘Guest’ user’s permissons if they are not logged in?

Setting the controllers for public access or granting access on action level with Auth->allow($action1, $action2, …) doesn’t seem to work for me, and I can’t see how to set a ‘default’ ACO for this users… something like making an unidentified user belong to ‘Guests’ group should work, but how to do this?

30 07 2007
Gorka

…and I can’t see how to set a ‘default’ ACO for this users…

Sorry, of course I meant ARO, not ACO.

It’s absolutely great to have your articles as a starting point, but there are too many obscure points in the process. Or maybe it is just me being too idiot to get the thing working, but I’ve spent the last three days with this stuff and still can’t get it working right.

I know this is alpha stuff, but after reading all articles I’ve found, comments on the Google group, Cake API,… I just wish there was a complete reference on how to setup ACL+Auth for a working site, or some decent working example to start with. Wouldn’t mind to write one myself, if I knew how to make it work!

Anyway, thanks for your articles and keep up with them :)

30 07 2007
Geoff

HI Gorka,

$this->Auth->allow() should work in the beforeFilters() but make sure that you call parent::beforeFilter() as well.

An alternative is to create a PUBLIC Aro with all the base permissions and then have an AppController::beforeFilter similar to:

$publicUser = array('id' => '4');
if (!$this->Session->check('Auth.User')) {
$this->Session->write('Auth.User', $publicUser);
}
if (isset($this->Auth)) {
$this->Auth->userScope = array('User.disabled' => 0);
$this->Auth->loginAction = '/users/login';
$this->Auth->loginRedirect = '/users/account';
$this->Auth->fields = array('username' => 'username', 'password' => 'passwrd');
$this->Auth->authorize = 'actions';
if (!$this->Auth->isAuthorized()){
if ($this->Session->check('Auth.User') == $publicUser){
$this->redirect($this->Auth->loginAction);
}
}
if (in_array(low($this->params['controller']), $this->_publicControllers)) {
$this->Auth->allow();
}
}

As for complete reference on how to setup ACL+Auth I have heard that the new 1.2 manual has in the range of 100+ pages already. I think that ACL and Auth will be covered quite well.

30 07 2007
Brian

Well, this is just the “draft” version, but I put up a blow-by-blow account of how I got the ACL/Auth system work work. You can view it here.

31 07 2007
nate

Is it me, or should the parent node in the groups model instead return:

array(‘model’ => ‘Group’, ‘foreign_key’ => $data[‘Group’][‘parent_id’]);

to have things appropriately dump into the aros table?

31 07 2007
Geoff

Hi nate,

If you only pass an int it assumes that int is the foreign key and the model is taken from Model::name.

Both methods will work.

9 08 2007
links for 2007-08-09 « Richard@Home

[…] Using AuthComponent and ACL in CakePHP 1.2 « Another Cake Baker (tags: cakephp authentication howto tutorial security) Posted by Richard@Home Filed in […]

17 08 2007
jetpac

Hey thanks for the great posts on acl, very useful. I seem to have most of it up and running but I am having a difficult time granting an aro access over all actions in a controller. I have a ROOT -> Users -> test aco. I granted my aro access to the Users aco, and to the aco Users -> *, but I still need to create a test aco under Users and specifically grant access to that action.

It was my understanding that if someone has access to a parent aco then unless it is specifically denied access to a child aco then it can access it.

Any ideas? thanks

17 08 2007
jetpac

OK so this was driving me crazy for the last two days and then 10 minutes after I post the question I figure it out!

The problem is that the node has to exist in the tree. I guess it seems kind of stupid in retrospect but I figured if I gave the user access to the Users controller then cake would figure out that any actions under it were allowed. But of course an aco can be anything, not just a controller so by adding the test aco with a parent of Users but only granting access to the Users aco the user still has access to the test aco.

I’m slapping myself now!

26 09 2007
Loud Baking

How to use AuthComponent in CakePHP

Wherever I went – irc, trac, google groups and certain blogs – I noticed people complaining about either not knowing how to use the AuthComponent or having problems with it.
After reading the only tutorials available across all usual blogs I rely on fo…

4 10 2007
Adwin

what is the big difference auth system in 1.2 and 1.1 ?
I love this feature, (i use 1.1) …. they are very nice

9 10 2007
Karsten

Thank you for this NICE post!
I want to go a step ahead… I think, it is VERY usefull to set rights for each field. Only with this functionality it is possible to have the full control.
Often I need forms, where the user see some values, but can not edit them. In other ways, some field should not be visible in the form.
Did you see a solution on your ACL-base…???

9 10 2007
Geoff

This level of control is possible with ACL but you will have to do a LOT of extra work manually. Here is how I would approach it.

In Model::aftersave() add each field to the ACO tree manually.
In Model::afterFind() loop through each field and see if the current user has permissions and unset the Model::data[‘ModelName’][‘fieldname’] if they don’t have permission.

By putting the operations in Model::afterSave and Model::afterFInd it can all happen before it even gets to the controller. This is probably best done as a Behaviour as you probably wont want it to apply to every model.

Geoff

9 10 2007
Karsten

Hi Geoff,

thank you for this estimation.
The next step I’m thinking about is, how to implement this in the views!?
My first approach… Generating a view with ALL fields in it and to check each field, which right is specified. But how can I access the rights in a view? The other doubt – is THIS the right way, keeping MVC in mind?!? (properly not – to much logic in a view?)
The other approach… Let the controller do the work, delete invisible fields from the array to have a ‘clean’ view (MVC in mind…). At this point the controller sends an additional flag to inform the view, if a field should be editable or not.
I lean towards the second approach, but I’m not sure!?! Or is it me, that I don’t see the RIGHT (third?) way…?

Karsten

9 10 2007
Geoff

Keep it out of the view, and I would keep it out of the controller as well. That is why I suggested unsetting in Model::afterFind()

Remember…fat models ad skinny controllers. Controllers shouldn’t do much more than pass data from the model to the view and back and decide which view to show.

Geoff

10 10 2007
Extending ACL to per field « Another Cake Baker

[…] ACL to per field 10 10 2007 In some recent comments I was asked how I would expand ACL to incorporate rights at a per field level. I can see how this […]

16 10 2007
abba bryant

Karsten – If you wanted to keep it simple and only require one view then an easy solution would be to extend the various html output helpers ( Form comes to mind ) to check whether the current user is allowed to view the field.

The helper could then output an input field, the value as text or nothing at all depending on what you need. At least it keeps it down to one view file.

16 10 2007
Karsten

Hi Geoff, hi Abba,

my destination is, to generate forms based on group-rights (role-rights). We are all need those things continuously, isn’t it?
Keeping MVC and performance(!) in mind, I think about a solution, that generates the views if role-rights have been changed. The role-rights may be saved in a db-table.
…see Geoffs tip in “Extending ACL to per field”:
$this->render($role.’_’.$action)

CakePHP is IMHO the nicest PHP-Framework at this time. But we need strongly a mighty standardised(!) webbased admin-interface to handle ACL/AUTH. If there are longer so many open issues, the effect will be, that to many developers go their own ways. Look at the history HTML – too many “island-standards” over a (too) long time… :-/
I think, that must be avoid betimes…

It may be necessary, that masterminds like Geoff solve that problems basically – for a better cake-future…

I hope… :-)

Karsten

16 10 2007
Geoff

@abba – brilliant!! Now why didn’t I think of that…?

@Karsten – Work keeps getting in the way but I am working on a flexible role based user managment system. Once I have the ground work down I will be putting it out there for all to criticize and enhance.

28 10 2007
Loud Baking » Blog Archive » Conventional solution for the visitors + AclComponent

[…] different places where I read about ACL, a common question that always comes early in the comments is: Assuming […]

5 11 2007
VolCh

Thanks a lot :)

4 12 2007
15 01 2008
James

Can anybody help me out?

I have this working really well, so well in fact that I no longer have anonymous access. I tried using the pageDescriptions array and the anonymous user, but haven’t had any luck.

Any ideas?

22 01 2008
Jonern

Thanks a lot for these ACL tutorials! Just saved hours of work thanks to you =)

25 01 2008
Terrance

I’m really just beginning to work with ACL and AuthComponent and I’m having a little bit of a hard time with this. In general it feels like some steps may be left out, such as the cake console commands used to create the Aco tree?

I also went through the Using AclBehavior in CakePHP 1.2 post and found that the initdb command is deprecated. Also it doesn’t explain to create the user and group tables first, though that is pretty common sense.

Overall the article is helping quite a bit but I think it would be nice to have a little more explanation for how to create users/groups, maybe with an example login action shown.

25 01 2008
Terrance

A little help for some who might be running console v1.2.0.6311

https://trac.cakephp.org/changeset/6312

The string path needs to be added.

2 02 2008
rocky

hey geoff. i’ve been trying to use your plug for testing acl/auth func in my application. however i’m at my wits end trying to figure out what goes in the acos/aros/map/groups tables.

i mean whos who of what and where!!!!! :((

it will be REALLY nice if you could show a nice little dump with associations of these tables to aid the doc of this plug,

anticipating… and thanks much!

21 02 2008
Brade

Just want to point out that you can set up ACO’s in a similar fashion to ARO’s. In the model class you want to use as an ACO (and thus will use the acos table), use this:
var $actsAs = array('Acl'=>'controlled');

In the User and Group models, of course we’ve already used:
var $actsAs = array('Acl');
which is really just the same as:
var $actsAs = array('Acl'=>'requester');

“requester” and “controlled” are the only two options expected, as seen in the _typeMaps member array here: http://api.cakephp.org/1.2/libs_2model_2behaviors_2acl_8php-source.html#l00037

30 05 2008
Ophelia

First try, then trust ,

2 06 2008
Robert

This website is useful for individuals who are searching prayers and novenas and all.p

12 06 2008
Jason

To make permissions more complex for “visitors” to the site instead of only allowing “Pages” controller you can do the following (I added it in the beforeFilter() method for app_controller.php):

if ($this->Acl->check("Guest", $this->Auth->action($this->params['controller'].'/'.$this->params['action']), "read"))
{
$this->Auth->allow();
}

and create a “Guest” ARO then grant it to the controller/actions as appropriate

17 07 2008
indianairlines

you can simply use the auth code available there rather than putting up directly here on the site from there…good luck

28 08 2008
Manny Rodriguez

I need to know if you or anyone out there has successfully integrated phpGACL with cakePHP 1.2. Please let me know if you have as I am looking for a programmer to contract for this project.

30 10 2008
CakePHP Tutorials :: PseudoCoder.com

[…] – Using AclBehavior in CakePHP 1.2 lemoncake.wordpress.com – Using AuthComponent and ACL in CakePHP 1.2 bakery.cakephp.org – How to use ACL with Cake PHP 1.2.x? http://www.realm3.com – Setting Up User Groups […]

26 01 2009
php newbie

where da hell is ACL ?

28 01 2009
bakelord

var $publicControllers = array(‘pages’);
……………………..
if (in_array(low($this->params[‘controller’]), $this->publicControllers)) {
$this->Auth->allow();
}
…………………….

This way I can allow a full controller. But I need to allow some actions from different controllers. Supplse XControllers and YControllers are 2 controllers. X has 2 actions => x1 and x2. Y has 2 actions y1 and y2. I want to allow x1 and y1. What should I do?? Please let me know ASAP. It will be very helpful for me.

31 01 2009
Legal Hallucinogens

Great header! I love it :)

27 04 2009
hakki kekilli

I also went through the Using AclBehavior in CakePHP 1.2 post and found that the initdb command is deprecated. Also it doesn’t explain to create the user and group tables first, though that is pretty common sense.

25 06 2009
Nauman

Hi All,

I am trying to create a simple login process with auth and acl, from where i should start and what is admin routing

14 08 2009
Abhisek

excellent post. bookmarked!

23 08 2009
hoo

What about restricting specific data not just an action.

You have several customers and you only want them to see their own data.
ACL does not address this. Any good posts on using sessions to restrict user data with in the actions?

10 02 2010
CakePHP ACL Tutorial – What and How | KomunitasWeb

[…] Using AuthComponent and ACL in CakePHP 1.2 […]

9 04 2010
Kingfisher Airlines Booking

it will be REALLY nice if you could show a nice little dump with associations of these tables to aid the doc of this plug,

16 04 2010
Fly Kingfisher

Please some body help me in implementing it.

27 04 2010
JetAirways

This is really excellent post. I bookmarked this post

28 04 2010
john

yes you are true jetairways … http://www.ksrtconlinebooking.in

24 06 2010
London Paris Train

Are these scripts really working or they are just pasted? I dont know why and how these things are available but i have heard that they do really work. Thanks Ruan

30 07 2010
Paramount Airways

This is very nice and useful post.Keep updating the same information .

12 09 2010
Indigo Airlines

Nice information…….

12 09 2010
Flight Booking

It will surely help…..

15 09 2010
Yatra promotion Code

It will surely help the PHP platform workers….

16 09 2010
Bangalore Flights

It is a nice information.Can you give more information about AuthComponent…

6 10 2010
Yatra

This type of information always be useful for user who want such type of infomation.

6 10 2010
2010-10-06 ACL development for BSF’s CakePHP driven website | Broken Sidewalk Farm

[…] I really need to find a good way to integrate Digg and/or Delicious… Using AuthComponent and ACL in CakePHP 1.2 « Another Cake Baker http://lemoncake.wordpress.com/2007/07/19/using-authcomponent-and-acl-in-cakephp-12/ […]

24 02 2011
Eurostar Tickets

This is really informative post and will definitely help all readers. Keep sharing such a nice and wonderful article.

Kk

24 02 2011
Eurostar Tickets

Great post you have share with us. Keep writing.
Harry

17 07 2011
yatra.com

learner and i found your blog best because of information your shared !
Thnx fro sharing information!

24 11 2011
Promotion Code

Very great post..keep posting.

24 11 2011
Flight Ticket Booking

Informative posting.I had bookmarked it in my I pad…

17 12 2012
http://www.dieselmovies.com/

Icing or frosting is the creamy topping added to baked goods, such as cakes and cupcakes for decorating
purposes. Maybe you will find recipes for cakes other in the world.
From jungle to barnyard, Winnie-the-pooh, or under the sea, you can find a recipe that
will delight the soon-to-arrive bundle of joy.

2 07 2013
my review here

Wow that was strange. I just wrote an incredibly
long comment but after I clicked submit my comment didn’t appear. Grrrr… well I’m not
writing all that over again. Anyway, just wanted
to say wonderful blog!

12 07 2013
rensyu.com

I’m impressed, I have to admit. Seldom do I encounter a blog that’s
both educative and amusing, and without a doubt, you’ve hit the nail on the head. The issue is something not enough people are speaking intelligently about. I am very happy that I stumbled across this during my search for something concerning this.

14 09 2013
Http://blog.uin-Malang.ac.id/

Nice post. I learn something new and challenging on sites I stumbleupon everyday.
It’s always helpful to read articles from other writers and
use a little something from other web sites.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




Follow

Get every new post delivered to your Inbox.

%d bloggers like this: