15
Feb 06

Granting and Checking Permissions with LiveUser

I was reminded by maxi_million in the comments on one of my previous LiveUser tutorial entries that I never completed the promised third entry in that series. After the initial procrastination wore off and I initially turned my mind to writing this piece, my main project using LiveUser ended up being converted (for various reasons) into a drupal site, so my further use of the library has been quite minimal. But I do have a little code sitting around, so will try and draw together a few notes on how I was using Liveuser.

While many powerful authorization systems are purely role-based, something that can be achieved in LiveUser with the groups functionality covered in the previous entry on this subject, LiveUser also supports much more fine grained permissions. Each permission is its own entity, and permissions are grouped into areas. I created my areas directly in the database so won’t be covering that here. Once you have your area’s id in the variable $area_id and an instance of LiveUser_Admin in $admin you can call:

$right = $admin->perm->addRight(
  array('area_id' => $area_id,
    'right_define_name' => 'a name for your right'));

to create the right and capture its ID in $right.

You can then ‘grant’ that right to a user with:

$admin->perm->grantUserRight(
  array('right_id' => $right,
    'perm_user_id' => $perm_user_id));

Or grant it to a group with:

$admin->perm->grantGroupRight(
  array('right_id' => $right,
    'group_id' => $group_id));

Where I ran into problems was when I attempted to check those permissions. From the API documentation, it wasn’t clear how to check for a right given only its name, but after a little exploration I put together the following method (used within my wrapper class) that handles it. $this->user is an instance of LiveUser and $this->admin is an instance of LiveUser_Admin:

function checkRight($area_id, $right_desc) {
  if (empty($this->admin)) {
    $this->getAdminInstance();
  }
  $filter = array(
    "fields" => array("right_id"),
    "filters" => array(
      "area_id" => $area_id,
      "right_define_name" => $right_desc));
  $rights = array_keys($this->admin->getRights($filter));
  $right_id = $rights[0];
  return $this->user->_perm->checkRight($right_id);
}

You’ll note that the final line makes use of the _perm property. In PEAR coding conventions a preceding underscore means a method or property is private and should not be accessed from outside the class, but this was the neatest approach I was able to find in the time. If anyone can tell me how to do this within the approved public API I’ll happily update this entry.

Update: Be sure to check out the comments, where Lukas has been adding some very useful information.


15
Aug 05

LiveUser Documentation

It’s taking me a while to get to my next installment on LiveUser but in the meantime, readers may want to check out the updated documentation that Lukas published yesterday. It’s not yet a comprehensive introduction/guide to the package, but gathering together a lot of the available information is a huge step forward.


04
Aug 05

Getting Started with LiveUser Permissions

UPDATE (Aug 9th ’05): Thanks to feedback from Lukas Smith and Laurens Nienhaus I’ve made some updates which show better ways to get at some properties.


Having described in my ‘Configuring LiveUser’ entry how to configure and instantiate LiveUser it’s now time to talk about how we start connecting together our login system with more sophisticated permissions management.

This time around we’re going to be making use of the LiveUser_Admin module, which can be instantiated using the same configuration array as LiveUser, with:

$admin = LiveUser_Admin::factory($liveuser_config);

LiveUser keeps ‘authentication’ and ‘permissions’ distinct and in order to get started with permissions we must create entries for our users in the permissions system.

The LiveUser Admin API provides us with the method:

$admin->perm->addUser($user_to_add);

to add a user to the permissions system, where $user_to_add is an array with keys matching the fields of the liveusers_perm_users table. In particular we need ‘auth_container_name’ and ‘auth_user_id’. Unfortunately there is no method which will generate this array for the currently logged in user, but we can get at the instance variables directly to perform:

$user_to_add = array();
$user_to_add['auth_container_name'] = $live_user->getProperty('containerName');
$user_to_add['auth_user_id'] = $live_user->getProperty('auth_user_id');

$admin->perm->addUser($user_to_add);

Once we have a user we can start to create permissions and grant them those permissions, but before moving on to that I wanted to set up permission groups and add users to those groups (we can also grant permissions to groups and in general this is the facility I’m likely to use most).

To add a group we make use of the addGroup() method:

$admin->perm->addGroup($group_info);

Where $group_info is an array with the keys ‘group_define_name’ (string) and ‘is_active’ (boolean). I used it as:

$group = $admin->perm->addGroup(array(
'group_define_name' => 'admins',
'is_active' => 1));

Having set up the group we’ll want to add users to that group, which is achieved through the method:

$admin->perm->addUserToGroup($data);

Once again the parameter is an associative array with the keys ‘group_id’ and ‘perm_user_id’. The return value from addGroup will have given us the group ID, or we can retrieve it using the getGroups method:

$params = array(
'fields' => array('group_id'),
'filters' => array('group_define_name' => 'admin'));
$group_details = $admin->perm->getGroups($params);

which will return something like:

Array
(
[0] => Array
(
[group_id] => 2
)

)

Meaning we can add our user to the group using:

$group_info['group_id'] = $group_details[0]['group_id'];
$group_info['perm_user_id'] = $live_user->getProperty('permUserId');;
$admin->perm->addUserToGroup($group_info);

So there we have it, our ‘admins’ group is defined and our current user is a member of it. Next time I’ll cover how we use this to create, edit, grant, revoke and check rights.


29
Jul 05

Configuring LiveUser

For a current (PHP) project I need a highly flexible authentication and permissions management system. Having heard plenty of mentions on the various PEAR lists I decided to try out LiveUser, which seems to currently be the most comprehensive such system for PHP. It’s a large codebase that seems to cover most of the necessary permutations and includes a number of prominent coders amongst its developers.

What I hadn’t taken into account, of course, was the lack of documentation. I spent quite a while trawling through their wiki and googling before concluding that the best way to work LiveUser out would be to work through the code piece by piece. And since that’s a long, slow process it seemed worth documenting here. I’m going to do that step by step, starting today with configuration and instantiation.

LiveUser’s initial configuration is managed through a large associative array that should be passed to the factory in order to instantiate the core object. Unlike some of the other arrays used as arguments to functions, this one is documented inline, but it still took a while to pick apart.

Here’s an example:

$liveuser_config = array(

First up we have some core parameters for LiveUser

autoInit determines whether or not the class tries to instantiate the various ‘containers’ when it is first called

'autoInit' => true,

the login parameter allows us to specify whether login should be attempted off-the-bat and whether or not the session ID should be regenerated after a successful login.

'login' => array(
'force' => true,
'regenid' => true),

With the core parameters set, we can move onto the ‘containers’. LiveUser employs containers to allow for flexibility. Containers can be thought of as ‘plugins’ that allow access to any sort of authentication or permissions management system you want to connect.

First up I define my permissions container. There are three container types that come with LiveUser out of the box: ‘simple’, ‘medium’, and ‘complex’. I’m looking for as much flexibility as possible so am using ‘Complex’.

We then provide some ‘storage’ parameters. LiveUser provides several storage option for permissions (primarily PEAR::DB, MDB and MDB2) and you can add extras in. Here I am using PEAR::DB and so specify a DSN and the prefix I’m using for my tables.

If I already had a DB object instantiated, I could remove the ‘dsn’ parameter and replace it with ‘connection’ which would be a reference to my existing connection.

'permContainer' => array(
'type' => 'Complex',
'storage' => array(
'DB' => array(
'dsn' => $dsn,
'prefix' => 'liveuser_'))),

For me, one of the key draws of LiveUser for me was the fact that I could authenticate against multiple sources for one application. This application includes a directory for a membership-based organisation, and I want all members to be able to login. There are also a few administrators who are not members, but need to be able to log in to the site.

authContainers is itself an associative array, with the keys being the names by which you want to address the different authentication sources. In this case ‘members’ and ‘admins’. You can specify a few options that should be familiar to anyone who’s used PHP’s sessions and then a few others. I’m again using the PEAR::DB interface for my authentication so I specify type as ‘DB’.

Options for the DB container are then given in the ‘storage’ parameter. As with the permissions, ‘dsn’ can be replaced with ‘connection’. ‘alias’ is an array that maps the table (‘users’) and fields that LiveUser’s DB container uses by default to the table and fields that we have in our application.

'authContainers' => array(
'members' => array(
'type'            => 'DB',
'loginTimeout'    => 0,
'expireTime'      => 3600,
'idleTime'        => 1800,
'updateLastLogin' => false,
'allowDuplicateHandles' => false,
'allowEmptyPasswords'   => false,
'passwordEncryptionMode' => 'PLAIN',
'storage' => array(
'dsn' => $dsn,
'prefix' => '',
'alias' => array(
'users' => 'member',
'auth_user_id' => 'id',
'is_active' => 'status',
'handle' => 'username',
'passwd' => 'password'))),
'admins' => array(
'type'            => 'DB',
'loginTimeout'    => 0,
'expireTime'      => 3600,
'idleTime'        => 1800,
'updateLastLogin' => false,
'allowDuplicateHandles' => false,
'allowEmptyPasswords'   => false,
'passwordEncryptionMode' => 'MD5',
'storage' => array(
'dsn' => $dsn,
'prefix' => '',
'alias' => array(
'users' => 'admins',
'auth_user_id' => 'id',
'is_active' => 'id',
'handle' => 'username',
'passwd' => 'password')))));

With that array set up, LiveUser can easily be instantiated using:

$live_user = LiveUser::factory($liveuser_config, $username, $password);

or

$live_user = LiveUser::singleton($liveuser_config, $username, $password);

and we can check whether the user is now logged in with

$live_user->isLoggedIn() which returns true if login succeeded, false if it failed.

(NB: LiveUser’s own database schema is distributed within the examples that come in the PEAR package. It is provided as an MDB-compliant XML file)