Access-control lists
So far, Tor is wide open in terms of access. For example, anyone can
add, edit, or delete products, etc. It's time to lock down some of
this functionality. To do that, we will use CakePHP's ACL
functionality.
What is an ACL?
An ACL is, in essence, a list of permissions. That's all it is.
It is not a means for user authentication. It's not the silver bullet
for PHP security. An ACL is just a list of who can do what.
The who is usually a user, but it could be something like a
controller. The who is referred to as an access-request object
(ARO). The do what in this case is going to typically mean
"execute some code." The do what is referred to as an
access-control object (ACO).
Therefore, an ACL is a list of AROs and the ACOs they have access to.
Simple, right? It should be. But it's not.
As soon as the explanation departed from "it's a list of who can do
what" and started throwing all those three-letter acronyms (TLAs) at
you, things may have gone downhill. But an example will help.
Imagine there's a party going on at some nightclub. Everyone who's
anyone is there. The party is broken up into several sections
— there's a VIP lounge, a dance floor, and a main bar. And, of
course, a big line of people trying to get in. The big scary bouncer
at the door checks a patron's ID, looks at The List, and either turns
the patron away or lets him come into the section of the party to
which he has been invited.
Those patrons are AROs. They are requesting access to the different
sections of the party. The VIP lounge, dance floor, and main bar are
all ACOs. The ACL is what the big scary bouncer at the door has on his
clipboard. The big scary bouncer is CakePHP.
Creating the ACL
table
In CakePHP V1.1, ACL management worked like baking, via a PHP script
you called directly. In CakePHP V1.2, ACL management is part of the
Cake Console. Using the Cake Console, you can set up a database table
to be used to store ACL information. At the command line, from the
/webroot/app directory, run the following command:
../cake/console/cake schema run create DbAcl.
The Cake Console will warn you that it's going to drop tables (even if
they are not there), then ask if you want to create three tables
(Yes for both). When it's done, Bake will tell you it has made three
databases (see Figure 6): acos, aros, and aros_acos.
Figure 6. ACL shell output
That's all it takes to get started. Now it's time to start defining
your AROs and your ACOs.
Defining AROs
So you have the ACL database tables. And you have an application that
lets users self-register. How do you create the AROs for your
users?
It makes the most sense to add this to the registration portion of the
application. That way, when new users sign up, their corresponding ARO
is automatically created for them. This does mean you'll have to
manually create a couple AROs for the users you've already created,
but CakePHP makes that easy, as well.
Defining groups
In CakePHP (and when using ACLs, in general), users can be assigned to
groups for the purpose of assigning or revoking permissions. This
greatly simplifies the task of permission management, as you do not
need to deal with individual user permissions, which can grow into
quite a task if your application has more than a few users.
For Tor, you're going to define two groups. The first group, called
Users, will be used to classify everyone who has simply registered for
an account. The second group, called Dealers, will be used to grant
certain users additional permissions within Tor. You will create both of these groups using the Cake Console, much like
you did to create the ACL database. To create the groups, execute the
commands below from the /webroot/app directory.
../cake/console/cake acl create aro 0 Users
../cake/console/cake acl create aro 0 Users
|
After each command, CakePHP should display a message saying the ARO was
created.
New Aro 'Users' created.
New Aro 'Dealers' created.
|
The parameters you passed in (for example, '0 Users') are parent, and
node. The parent parameter would correspond to a group to which the
ARO should belong. As these groups are top-level, you passed in 0. The
node parameter is a string used to refer to
the group.
Adding ARO creation to
registration
Adding ARO creation to the user registration piece of Tor isn't hard.
It's just a matter of including the right component and adding a
couple lines of code. To refresh your memory, the register function
from users_controller.php should look
something like Listing 10.
Listing 10. Original register action
function register()
{
if (!empty($this->data))
{
$this->data['User']['password'] = md5($this->data['User']
['password']);
if ($this->User->save($this->data))
{
$this->Session->setFlash('Your registration information
was accepted');
$this->Session->write('user', $this->data['User']
['username']);
$this->redirect(array('action' => 'index'), null, true);
} else {
$this->data['User']['password'] = '';
$this->Session->setFlash('There was a problem saving
this information');
}
}
}
|
To start using CakePHP's ACL component, you need to include the
component as a class variable.
Listing 11. Including the components as a class variable
<?php
class UsersController extends AppController
{
var $components = array('Acl');
...
|
The $components array simply contains a list
of CakePHP components to include, by name. Components are to
Controllers as Helpers are to Views. There are other components
available, such as the security component, which will be covered in a
later tutorial. In this case, the only one you need is ACL.
Now you have access to all the functionality provided by the ACL
component. You can create an ARO by invoking the
create method on the ACL's
ARO object (that will be easier to read in
Listing 12). This method takes the same parameters you would normally
pass when you are calling the create method
from a model, which is essentially what you are doing. In this case,
you specify the name of the alias (the username), the model that the
ACL points to (user), the foreign_key for
the record (the new user's ID), and the
parent_id (the ID of the parent node
— in this case, the Users ARO group, which is found using the
findByAlias line below). To create the ARO
for your user, you also need to know what the user's ID is once it has
been saved. You can get this from
$this->User->id after the
data has been saved.
Putting it all together, your register
function now might look something like Listing 12.
Listing 12. Register function
function register()
{
if (!empty($this->data))
{
$this->data['User']['password'] = md5($this->data['User']
['password']);
if ($this->User->save($this->data))
{
$this->Session->setFlash('Your registration information
was accepted');
$this->Session->write('user', $this->data['User']['username']);
$parent = $this->Acl->Aro->findByAlias('Users');
$aro = new Aro();
$aro->create();
$aro->save(array(
'alias' => $this->data['User']['username'],
'model' => 'User',
'foreign_key' => $this->User->id,
'parent_id' => $parent['Aro']['id'])
);
$this->Acl->Aro->save();
$this->redirect(array('action' => 'index'), null, true);
} else {
$this->data['User']['password'] = '';
$this->Session->setFlash('There was a problem saving
this information');
}
}
}
|
You'll note that the ARO is not created until the save has
succeeded.
Try it out
That should be all you need to get your AROs up and running. To verify,
start back at the command line in webroot/app and ask the Cake Console
to view the ARO tree:
../cake/console/cake acl view aro. Your
output should look something like Figure 7.
Figure 7. Output from ACL shell view
ARO with empty list
Now go to http://localhost/users/register and sign up a new user. Once
you're done, rerun the
../cake/console/cake acl view aro command.
Your output should look something like Figure 8.
Figure 8. Output from ACL shell view
ARO with a user
From now on, whenever someone registers for a new account, he will
automatically have an ARO created for him. That ARO will belong to the
Users group.
Creating AROs for existing
users
Now that new Tor users are getting their AROs created, you need to go
back and create AROs for the existing users. You will do this with the
Cake Console, in almost exactly the same way you created the groups.
Start by using that user you just created to visit
http://localhost/users/knownusers to get a list of users that have
been created.
Figure 9. Output from ACL shell view
ARO with a user
Then, for each user, you need to execute the create ARO command like
you did for creating the groups. For parent, specify 'Users'. For
node, specify the username. For example, from Figure 9, to create an
ARO for dentarthurdent, you would execute
the following (again, from the /webroot/app directory):
../cake/console/cake acl create aro Users dentarthurdent.
Make sure you run these commands for each user in your
knownusers list, except for the user you
created to test ARO creation during user registration. Be sure that
you are specifying the right user ID and username for each user. When
you're done, the results of
../cake/console/cake acl should look
something like Figure 10.
Figure 10. Output from ACL shell ARO
with a user
You can get help on some of the other things Cake Console can do with
ACLs by running
../cake/console/cake acl help at the
command line.
|