Search icon CANCEL
Subscription
0
Cart icon
Cart
Close icon
You have no products in your basket yet
Save more on your purchases!
Savings automatically calculated. No voucher code required
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
CakePHP 1.3 Application Development Cookbook

You're reading from  CakePHP 1.3 Application Development Cookbook

Product type Book
Published in Mar 2011
Publisher Packt
ISBN-13 9781849511926
Pages 360 pages
Edition 1st Edition
Languages
Toc

Table of Contents (17) Chapters close

CakePHP 1.3 Application Development Cookbook
Credits
About the Author
About the Reviewers
1. www.PacktPub.com
2. Preface
1. Authentication 2. Model Bindings 3. Pushing the Search 4. Validation and Behaviors 5. Datasources 6. Routing Magic 7. Creating and Consuming Web Services 8. Working with Shells 9. Internationalizing Applications 10. Testing 11. Utility Classes and Tools

Setting up Access Control Layer-based authentication


The more roles an application has, the more complex its Access Control Layer becomes. Luckily, one of the authentication schemes provided by the Auth component allows us to easily define which actions are accessible by certain roles (known as groups), using command-line tools. In this recipe, you will learn how to set up ACL on your application.

Getting ready

We should have a table to hold the roles, named groups.

If you do not have one already, create it using the following statement:

CREATE TABLE `groups`(
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY(`id`)
);

If you do not have any records in your groups table, create some by running the following SQL statement:

INSERT INTO `groups`(`id`, `name`) VALUES
(1, 'Administrator'),
(2, 'Manager'),
(3, 'User');

We must also have a users table to hold the users, which should contain a field (named group_id) to contain a reference to the group a user belongs to. If you do not have such a table, create it using the following statement:

CREATE TABLE `users`(
`id` INT NOT NULL AUTO_INCREMENT,
`group_id` INT NOT NULL,
`username` VARCHAR(255) NOT NULL,
`password` CHAR(40) NOT NULL,
PRIMARY KEY(`id`),
KEY `group_id`(`group_id`),
CONSTRAINT `users__groups` FOREIGN KEY(`group_id`) REFERENCES `groups`(`id`)
);

We also need to have the ARO / ACO tables initialized. Using your operating system console, switch to your application directory, and run:

  • If you are on a GNU Linux / Mac / Unix system:

    ../cake/console/cake schema create DbAcl
    
  • If you are on Microsoft Windows:

    ..\cake\console\cake.bat schema create DbAcl
    

How to do it...

Note

The following initial steps are very similar to what is shown in Setting up a basic authentication system. However, there are some differences between the two that are crucial, so make sure you go through these instructions carefully.

  1. 1. Create a controller for the User model (in a file named users_controller.php placed inside your app/controllers folder), which should contain the following:

    <?php
    class UsersController extends AppController {
    public function login() {
    }
    public function logout() {
    $this->redirect($this->Auth->logout());
    }
    }
    ?>
    
  2. 2. Create a file named login.ctp in your app/views/users folder (create the folder if you do not have one already), with the following contents:

    <?php
    echo $this->Form->create(array('action'=>'login'));
    echo $this->Form->inputs(array(
    'legend' => 'Login',
    'username',
    'password'
    ));
    echo $this->Form->end('Login');
    ?>
    
  3. 3. Create a file named app_controller.php in your app/ folder. Make sure it contains the following:

    <?php
    class AppController extends Controller {
    public $components = array(
    'Acl',
    'Auth' => array(
    'authorize' => 'actions',
    'loginRedirect' => array(
    'admin' => false,
    'controller' => 'users',
    'action' => 'dashboard'
    )
    ),
    'Session'
    );
    }
    ?>
    
  4. 4. Modify the UsersController class and add the following code before its login() method:

    public function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow('add');
    }
    public function add() {
    if (!empty($this->data)) {
    $this->User->create();
    if ($this->User->save($this->data)) {
    $this->Session->setFlash('User created!');
    $this->redirect(array('action'=>'login'));
    } else {
    $this->Session->setFlash('Please correct the errors');
    }
    }
    $this->set('groups', $this->User->Group->find('list'));
    }
    
  5. 5. Add the view for the action in the folder app/views/users by creating a file named add.ctp with the following contents:

    <?php
    echo $this->Form->create();
    echo $this->Form->inputs(array(
    'legend' => 'Signup',
    'username',
    'password',
    'group_id'
    ));
    echo $this->Form->end('Submit');
    ?>
    
  6. 6. Create a file named group.php and place it in your app/models folder with the following contents:

    <?php
    class Group extends AppModel {
    public $actsAs = array('Acl' => 'requester');
    public function parentNode() {
    if (empty($this->id) && empty($this->data)) {
    return null;
    }
    $data = $this->data;
    if (empty($data)) {
    $data = $this->find('first', array(
    'conditions' => array('id' => $this->id),
    'fields' => array('parent_id'),
    'recursive' => -1
    ));
    }
    if (!empty($data[$this->alias]['parent_id'])) {
    return $data[$this->alias]['parent_id'];
    }
    return null;
    }
    }
    ?>
    
  7. 7. Create a file named user.php and place it in your app/models folder with the following contents:

    <?php
    class User extends AppModel {
    public $belongsTo = array('Group');
    public $actsAs = array('Acl' => 'requester');
    public function parentNode() {
    }
    public function bindNode($object) {
    if (!empty($object[$this->alias]['group_id'])) {
    return array(
    'model' => 'Group',
    'foreign_key' => $object[$this->alias]['group_id']
    );
    }
    }
    }
    ?>
    

    Note

    Take note of the IDs for all the records in your groups table, as they are needed to link each group to an ARO record.

  8. 8. Run the following commands in your console (change the references to 1, 2, 3 to meet your own group IDs, if they are different).

    • If you are on a GNU Linux / Mac / Unix system, the commands are:

      ../cake/console/cake acl create aro root Groups
      ../cake/console/cake acl create aro Groups Group.1
      ../cake/console/cake acl create aro Groups Group.2
      ../cake/console/cake acl create aro Groups Group.3
      
    • If you are on Microsoft Windows, the commands are:

      ..\cake\console\cake.bat acl create aro root Groups
      ..\cake\console\cake.bat acl create aro Groups Group.1
      ..\cake\console\cake.bat acl create aro Groups Group.2
      ..\cake\console\cake.bat acl create aro Groups Group.3
      
  9. 9. Add the following code at the end of your UsersController class definition:

    public function dashboard() {
    $groupName = $this->User->Group->field('name',
    array('Group.id'=>$this->Auth->user('group_id'))
    );
    $this->redirect(array('action'=>strtolower($groupName)));
    }
    public function user() {
    }
    public function manager() {
    }
    public function administrator() {
    }
    
  10. 10. Create a view for each of these actions, and put some distinctive content on each one of them to reflect which view is being rendered. Therefore, you have to create three files:

    • app/views/users/user.ctp

    • app/views/users/manager.ctp

    • app/views/users/administrator.ctp.

    For example the contents for user.ctp could simply be:

    <h1>Dashboard (User)</h1>
    
  11. 11. We have to tell ACL about these restricted actions. Run the following commands in your console.

    • If you are on a GNU Linux / Mac / Unix system, the commands are:

      ../cake/console/cake acl create aco root controllers
      ../cake/console/cake acl create aco controllers Users
      ../cake/console/cake acl create aco controllers/Users logout
      ../cake/console/cake acl create aco controllers/Users user
      ../cake/console/cake acl create aco controllers/Users manager
      ../cake/console/cake acl create aco controllers/Users administrator
      
    • If you are on Microsoft Windows, the commands are:

      ..\cake\console\cake.bat acl create aco root controllers
      ..\cake\console\cake.bat acl create aco controllers Users
      ..\cake\console\cake.bat acl create aco controllers/Users logout
      ..\cake\console\cake.bat acl create aco controllers/Users user
      ..\cake\console\cake.bat acl create aco controllers/Users manager
      ..\cake\console\cake.bat acl create aco controllers/Users administrator
      
  12. 12. Finally, we have to grant permissions by linking each ARO (groups) to each ACO (controller's actions). Run the following commands in your console.

    • If you are on a GNU Linux / Mac / Unix system, the commands are:

      ../cake/console/cake acl grant Group.1 controllers/Users all
      ../cake/console/cake acl grant Group.2 controllers/Users/logout all
      ../cake/console/cake acl grant Group.2 controllers/Users/manager all
      ../cake/console/cake acl grant Group.3 controllers/Users/logout all
      ../cake/console/cake acl grant Group.3 controllers/Users/user all
      
    • If you are on Microsoft Windows, the commands are:

      ..\cake\console\cake.bat acl grant Group.1 controllers/Users all
      ..\cake\console\cake.bat acl grant Group.2 controllers/Users/logout all
      ..\cake\console\cake.bat acl grant Group.2 controllers/Users/manager all
      ..\cake\console\cake.bat acl grant Group.3 controllers/Users/logout all
      ..\cake\console\cake.bat acl grant Group.3 controllers/Users/user all
      

    We now have a fully working ACL based authentication system. We can add new users by browsing to http://localhost/users/add, logging in with http://localhost/users/login, and finally logging out with http://localhost/users/logout.

Users should only have access to http://localhost/users/user, managers to http://localhost/users/manager, and administrators should be able to access all those actions, including http://localhost/users/administrator.

How it works...

When setting the authorize configuration option of the Auth component to actions, and after adding Acl to the list of controller-wide components, CakePHP will check to see if the current action being accessed is a public action. If this is not the case, it will check for a logged-in user with a matching ACO record. If there is no such record, it will deny access.

Once there is a matching ACO for the controller action, it will use the bindNode method in the User model to see how a user record is matched to an ARO. The method implementation we added specifies that a user record should be looked up in the aros table by means of the group that the user belongs to.

After having both the matching ACO and ARO, it lastly checks to see whether there is a valid permission set up (in the aros_acos table) for the given ARO and ACO records. If it finds one, it allows access, otherwise it will reject authorization.

It is of vital importance that each record in the groups table has a matching ARO record. We set that association by issuing aro create commands to link each group ID to an ARO record of the form Group.ID, where ID is the actual ID.

Similarly, all controller actions that are not within the defined public actions should have a matching ACO record. Just as with AROs, we create the association between controller's actions and ACOs issuing aco create commands, setting the ACO name to be the action name, and making them child of an ACO which name is the controller name.

Finally, to grant the permission of an ARO (group) to an ACO (controller's actions), we issue acl grant commands, specifying as the first argument the ARO (Group.ID) and the second argument either a whole controller (such as controllers/Users), or a specific controller action (such as controllers/Users/logout). The last argument to the grant command (all) simply gives a further control of the type of access, and makes more sense when using ACL to control access to custom objects, or when using the crud authentication scheme.

There's more...

While developing an application, the task of matching each controller action to an ACO may be somewhat troublesome. Fortunately, several people in the CakePHP community felt the need for an easier solution. One of the solutions that I'd recommend is adopting acl_extras, a plugin developed by Mark Story, the lead developer of the CakePHP 1.3 release. By using this plugin, you will be able to continuously synchronize your controllers with the acos table. Find more about it, including its installation instructions, at http://github.com/markstory/acl_extras.

See also

  • Using prefixes for role-based access control.

You have been reading a chapter from
CakePHP 1.3 Application Development Cookbook
Published in: Mar 2011 Publisher: Packt ISBN-13: 9781849511926
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime}