|

CakePHP ACL and Auth Tutorial: Database Setup

View full index of ACL Tutorial Articles

This article describes the initial steps used to created the sample website I created to demonstrate real-world usage of CakePHP and the Auth and ACL Components.

Get the source code for that sample website here.

This is more of a practical step-by-step tutorial than my previous tutorials on the ACL Component. I recommend reading those articles as well as the official Cake documentation if you want a broader overview of what ACL is.

This part of the tutorial will show the steps required to create and configure some basic ACL and Auth related elements in your database. I should point out from the start that this configuration will only work with the Auth Component in ‘crud’ mode. Although, the alternative ‘actions’ mode isn’t totally incompatible, you should read more about the differences between the two modes before creating your real application:

  • aros, aros_acos, and acos tables used by the ACL Component
  • a table to store names of groups
  • a table in to store usernames and passwords and a column value to connect each user to a group
  • an aros table populated with values that correspond to values in the group and user tables
  • an acos table populated with rows representing your app’s controllers
  • a superuser who will have all access to all pages in the site

Obviously, you first need to have a working install of the latest nightly build of Cake. Also, take the time to make sure you are familiar with how to use the cake console.

1. Initialize ACL Component DB Tables

On the command line, navigate to your app’s root directory (usually one step up from the app directory), and run the following command:

cake schema run create DbAcl

If this command runs with success, it will create 3 tables in your database. Here are the MySQL schema for these tables.

2. Create tables for Users and Groups

The application I am creating will organize it’s users into groups. Most permissions will be assigned to groups, and users will inherit access permissions based on their group membership. Exceptions will be possible, so that in some cases a user might get permission to something that other users in the same group do not have access to.

To make this possible, we will create the database tables which will hold data for Users and Groups. Users will be assigned group membership through a foreign key ‘group_id’.

In the case of this application, I will store the user’s login name in a field called “username” and store the password in a field called “passwd”. I am making the field length of “passwd” 255 characters long, because it will be holding a hashed version of the user’s password. By default this will be an sha1 hash, but PHP 5 allows even more secure hashes like SHA256 and Whirlpool, so I am making it extra long just in case.

CREATE TABLE `users` (                                                                
`id` int(10) unsigned NOT NULL auto_increment,                                      
`username` varchar(50) NOT NULL default '',                                         
`passwd` varchar(255) NOT NULL default '',                                          
`name` varchar(50) NOT NULL default '',                                             
`email` varchar(100) NOT NULL default '',                                                                 
`group_id` int(10) unsigned NOT NULL default '0',                                   
`active` tinyint(1) unsigned NOT NULL default '0',                                            
`created` datetime NOT NULL default '0000-00-00 00:00:00',                          
`modified` datetime NOT NULL default '0000-00-00 00:00:00',                         
PRIMARY KEY  (`id`),                                                                
UNIQUE KEY `username` (`username`),                                                                                             
KEY `group_id` (`group_id`)                                                         
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `groups` (                                                               
`id` int(10) unsigned NOT NULL auto_increment,                                      
`name` varchar(50) NOT NULL default '',  
`parent_id` int(10) default '0',                                                    
`created` datetime NOT NULL default '0000-00-00 00:00:00',                          
`modified` datetime NOT NULL default '0000-00-00 00:00:00',                         
PRIMARY KEY  (`id`)                                                                 
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

4. Create Starter Groups and a Superuser

The following MYSQL commands will manually create your intial groups:

INSERT INTO `groups` SET 
    `id` = 1, 
    `name` = 'users', 
    `parent_id` = null;
INSERT INTO `groups` SET 
    `id` = 2, 
    `name` = 'editors', 
    `parent_id` = 1;
INSERT INTO `groups` SET 
    `id` = 3, 
    `name` = 'superusers', 
    `parent_id` = 2;

To manually create a user with a password, you will need to get the security salt used by your application. Look into your app/config/core.php file and get the salt value from a line like this:

Configure::write('Security.salt', 'welcometomykitchen');

In this case the salt is “welcometomykitchen”. Your salt should be randomized and unique. This salt is combined with the user’s password string for extra security. So, to manually create the first superuser for your site, keep the salt handy.

The following will create a superuser for your site. Use your own salt value in place of mine, and add your own email address. The code below will give the ‘pherme’ the password of ‘ILikeCake’.

INSERT INTO `users` SET 
    `id` = 1, 
    `username` = 'pherme', 
    `passwd` = SHA1("welcometomykitchenILikeCake"), 
    `name` = 'Pierre Herme', 
    `email` = 'pherme@nonexistant.com', 
    `group_id` = 3, 
    `active` = 1;

5. Add The Groups and Superuser to ARO Tree

Now that we have the basic database tables set up, we can build our intial ARO Tree. This tree will allow us to assign permissions in such a way to allow an efficient use of inheritance. Both groups and users will be in the tree. However, as mentioned above, most permissions will ultimately be assigned to groups, with users inheriting most of their rights from the group they belong to.

After this intial setup, the ACL Behavior will manage this type of synchronization between the aros, users, and groups tables.

Here are the ACL commands to set up your groups and one user:

cake acl create aro root users
cake acl create aro users editors
cake acl create aro editors superusers
cake acl create aro superusers pherme

For the first group ‘users’ I am using the magic parent “root”, which gives the ARO node a parent_id value of null.

If you do:

cake acl view aro

You should now see something like this:

[1]users
    [2]editors
        [3]superusers
            [4]pherme

This indicates that editors will inherit permissions from users, and so on down the tree.

The Cake Console only creates alias values in the aros table. In order for the ACL Behavior to work, however, the rows of the aros table have to have ‘model’ and ‘foreign_key’ values properly set.

The ‘model’ field should correspond to the CamelCase name of the model which the record belongs to — either Group or User, while the ‘foreign_key’ field represents the id of that record. Again, ACL Behavior will take care of this later on, but for now we will manually create them with the following MySQL commands:

UPDATE `aros` SET 
    `model` = 'Group', 
    `foreign_key` = 1 
    WHERE `alias` = 'users';
UPDATE `aros` SET 
    `model` = 'Group', 
    `foreign_key` = 2 
    WHERE `alias` = 'editors';
UPDATE `aros` SET 
    `model` = 'Group', 
    `foreign_key` = 3 
    WHERE `alias` = 'superusers';
UPDATE `aros` SET 
    `model` = 'User', 
    `foreign_key` = 1 
    WHERE `alias` = 'pherme';

6. Create Basic ACO Elements

Before assigning permissions, we must also have some values in the acos table.

This table should contain a list of entries with alias values that correspond to CamelCase names of your application’s controllers. It is also helpful to organize these under a parent node, which I call “Site”.

cake acl create aco root Site

In this example, we will eventually have controllers named Users, Usermanager, Groups, Articles and SecretRecipes, so we need to add corresponding ACO nodes:

cake acl create aco Site Users
cake acl create aco Site Usermanager
cake acl create aco Site Groups
cake acl create aco Site Articles
cake acl create aco Site SecretRecipes

Note how all of these have the parent of Site.

7. Assigning Permissions

First lets give full access to our superusers group. We do this with the following command. By granting permission to the parent ACO named ‘Site’, the superusers will continue to have all permissions on any future ACO created whose parent is Site.

cake acl grant superusers Site *

All our users should get ‘read’ access on all acos:

cake acl grant users Site read

Except that we actually want to block users from accessing Usermanager:

cake acl deny users Usermanager *

8. “Check” Your Work

Let’s make sure everything was set up correctly by running the check command (the expected responses are indicated by the arrow):

cake acl check pherme Articles create
		--> pherme is allowed
cake acl check pherme Usermanager delete
	    --> pherme is allowed
cake acl check editors Articles read
	    --> editors is allowed
cake acl check users Usermanager create
	    --> users is not allowed
cake acl check users Usermanager read
	    --> users is not allowed

In Conclusion

Spend some time now taking a look at your database tables. I have already written an example of how to dissect these tables. Take some time to understand the way the lft and rght values are used to represent the permission trees in BOTH the acos and aros tables. Also take a look at the aros_acos table and spend some time understanding how the permissions are granted and denied through the use of the ‘_create’, ‘_read’, ‘_update’, and ‘_delete’ columns.

You now have a good foundation in your database from which to now build out your application with more users and more permissions.

Again, to skip some steps and just see what all this looks like as a final website:
download the source code here

[EDIT: May 26, 2008] Made references to sample site source code.

Sunday May 18, 2008

Thank you so much for putting this all together! This is very helpful.


Yura    May 21, 06:44 AM    #

Hi there, Thanks for the tutorial… I have been battling with various ACL and Auth tutorials for days now…

I think there is an error in the way that you set out your ARO table. Basically the group users should have children editors and normalusers or something like that. Then another top level group should be called superusers instead of superusers being a child of editors. The way i understand it – if superusers is a child of editors then you will not be able to grant “read only” access to all users and then grant all access to superusers because it is under the users group. Please verify!! thanks…


Dan Spencer    Jul 25, 02:16 AM    #

@Dan: The bottom line is that a superuser should not have any children. So it can either be at the bottom of the tree or be it’s own node.

Either way it works, because the permissions granted to the superusers override any more restrictive settings granted to the superusers parents.

I think it is instructive to have the superuser at the bottom of the tree, because it helps illustrate how inheritance works. But for simplicity, it does make a lot of sense to add a separate superuser node that is not part of any tree.


Aran    Jul 30, 09:47 AM    #

Outstanding!Fantastic!!

Thanks a lot.


— Pahlowan    Aug 11, 11:44 PM    #

Hi Aran,

Many, many thanks for this tutorial, this is the only one that has make me understand very clearly how the ACL component works !! but I still have one unresolved question: how do you manage access to controller actions different from CRUD actions ? for example, if I have on a controller an action called viewNewPosts, which isn’t a CRUD action, how should I manage it’s authorization ?

Thanks.


— Juan    Aug 27, 12:23 PM    #

I am wondering how I can have a “scope” for any particular action. either in actions mode or in CRUD mode. By scope, I mean I can edit my own articles, but not other peoples articles.

for example a user has a profile that really only they and admins might have control over.

By this I mean that the system would imply this automatically – I would not have to explicitly set a particular permission for user Luke or bettycrocker and so on.


Luke    Sep 8, 08:29 AM    #

Name

E-mail (will not be published)

Your Website

Message

Textile Help


|

rss feed iconRSS / Atom

Aran World

I'm Aran Johnson and I make websites.

I primarily use: PHP, MySQL, SubVersion, CakePHP, TextPattern, Cream Text Editor, and Addi Turbo Needles

Contact Me

My website portfolio

Recently

New York Times Chocolate Chip Cookie Modification

Hostway and Overselling

Drill and Burn Republicans

Frames Are Bad For Business

GlaxoSmithKline Give Canadians The Facts; Keeps Americans In the Dark

CakePHP Tutorials

CakePHP ACL and Auth: Sample Website

CakePHP ACL and Auth Tutorial: Database Setup

CakePHP ACL Tutorial: Introduction

CakePHP ACL Tutorial: Usage With Auth Component

CakePHP ACL Tutorial: Initial Setup

CakePHP ACL Tutorial: Auth Component Example

CakePHP ACL Tutorial: How To Check Access

Cake PHP ACL Tutorial: The Database Tables

My Knitting

My Flickr

Favorite Favicons

Wishlist

All content © Aran Johnson