IAM

ARTICLE

Kohana Access Control using Green

Green is an access control module for Kohana based on the authentication module Red. This article gives a brief introduction to its usage and concepts.

Update. The usage of the Kohana Green module is also demonstrated in the demo application presented here.

Introduction

After an Introduction to Kohana Authentication using Red, I want to present Green. Green is an access control module based on Red. It can be used to control access to controllers and ORM models (defined using the Kohana ORM module) based on a set of rules stored within a database. Before getting started with the SQL Scheme I want to point out some characteristics of Green. You may also jump right to the SQL Scheme or the Usage of the module.

The module is available on GitHub:

Green on GitHub

Green does not save permissions to each model within the object respectively model itself. Thus I would not categorize Green as usual ACL system. Instead Green could be considered as role-based access control system. By allowing a user to have multiple roles this system allows to realize complex rights systems within web applications.

SQL Scheme

In order to control access to models and controllers, a rule consists of a type - either model or controller -, a key and the rule itself.

-- -----------------------------------------------------
-- Table `rules`
-- -----------------------------------------------------
CREATE  TABLE `rules` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `type` VARCHAR(255) NOT NULL ,
  `key` VARCHAR(255) NOT NULL ,
  `rule` VARCHAR(255) NOT NULL ,
  PRIMARY KEY (`id`) )
DEFAULT CHARACTER SET = utf8;

For controller-rules the key contains the name of the controller the rule is applied on. For model-rules it will define the model and the method the rule is applied on in the following form: model_name.method_name.

Configuration

Green itself comes without any configuration options. But it can be used in combination with Yellow, a logging module based on Green and Red. Therefore, the module provides the following configuration options:

/**
* Green configuration.
*
* @package Green
* @author David Stutz
* @copyright (c) 2013 - 2014 David Stutz
* @license http://opensource.org/licenses/bsd-3-clause
*/
return array(

  /**
   * Options concerning the logger.
   * The logger can log each action allowed and denied on all models, controllers and actions.
   */
  'logger' => array(
    'model' => FALSE,
    'controller' => FALSE,
  ),
);

Yellow allows to log the access to controllers and the actions taken on models separately:

'logger' => array(
    'model' => new Yellow(Yellow::MODEL),
    'controller' => new Yellow(Yellow::CONTROLLER),
),

Rules

The rule itself is defined by a filter. Given the current context the filter evaluates to TRUE - meaning the rule grants access - or FALSE. Here, the current context is defined by the current user and the controller or the model and the method which is to be executed on the model. If Green is asked to grant access to a controller or to allow the execution of a method on a model, it fetches all rules defined for this context and calls the corresponding filters. For granting access at least one filter has to evaluate to TRUE. If no rules are found access will be denied.

Consider we have the roles user and admin. The following rules will keep the administration controller accessible only for administrators, whereas the profile controller is accessible for everyone. Note that two rules - one for the admin role and one for the user role - are needed because the set of all administrators must not necessarily be a subset of the set of all users as one would expect. In addition a user model can only be created and deleted by administrators.

type key rule
controller administration role:admin
controller profile role:admin
controller profile role:user
model user.create role:admin
model user.delete role:admin

The following section will explain the basic concept of filters and have a closer look at the role filter we already used in the examples above.

Filters

Filters are associated by their name and each filter may expect one additional parameter in the following form: filter_name:parameter.

The most basic filter is the role filter also seen above. It just checks whether the current user has the given role and evaluates to TRUE if so.

The usage of filters allows to create custom rules simply by implementing new filters. All filters have to implement the Green_Filter interface and must provide the method check(). As example we will have a look at the role filter:

/**
 * Green filter for checking whether the user has the appropriate role.
 *
 * @package     Green
 * @author      David Stutz
 * @copyright   (c) 2013 David Stutz
 * @license     http://opensource.org/licenses/bsd-3-clause
 */
class Kohana_Green_Filter_Role extends Green_Filter {
    
  /**
   * Check the condition represented by the filter on the saved user.
   * 
   * @return boolean  true on success
   */
  public function check() {
    $role = ORM::factory('user_role', array('name' => $this->_constraint));
        
    if (!$role->loaded()) {
      throw new Green_Exception('Filter_Role: Constraint \'' . $this->_constraint . '\' invalid. This role was not found.');
    }
        
    return Red::instance()->get_user()->has('roles', $role);
  }
}

$this->_item is the controller or model the rule is applied on. $this->_constraint holds the additional parameter if available.

Usage

The usage for controllers is quite simple:

if (!Green::instance()->can_proceed(strtolower($this->request->controller()))) {
  // The user is not allowed to proceed to the current controller, so redirect ...
}

This method is really straightforward. Alternatively, the proceed() method automatically uses the current controller, and throws a Green_Exception if the user is not allowed to access the current controller:

try {
  Green::instance()->proceed();
}
catch (Green_Exception $e) {
  // Access denied ... redirect ...
}

To control access to models there are two possibilities, too. First, an if statement actively checks whether the user is allowed to call a specific method on the given model:

if (Green::instance()->is_allowed($model, 'delete')) {
  $model->delete();
}

Alternatively, Green may also execute the method directly - if the user is allowed to call the specific action on the model - or throw a Green_Exception - if the user is not allowed to take this action:

try {
  // Will automatically call $model->delete().
  Green::instance()->allow($model, 'delete');
}
catch (Green_Exception $e) {
  // Not allowed ...
}
What is your opinion on this article? Let me know your thoughts on Twitter @davidstutz92 or LinkedIn in/davidstutz92.