LCMS Roles and Rights Proposal 1

From Dokeos

Jump to: navigation, search

Contents

Introduction

This proposal is based on the roles & rights system as implemented in the LCMS-based CMS Skorpiuz by HansDeBisschop

Location within the LCMS

The rights-application would be an elementary application within the LCMS and therefore it would be located within the root of the project:

  • /admin
  • /application
  • /classgroup
  • /common
  • /files
  • /main
  • /plugin
  • /rights
  • /repository
  • /users

General Structure

  • /install
    • rights_installer.class.php
  • /lib
    • /data_manager
      • /database
        • databaselocationresultset.class.php
        • databaserightresultset.class.php
        • databaseroleresultset.class.php
      • database.class.php
    • /rights_manager
      • /component
        • editor.class.php
      • rightsmanager.class.php
      • rightsmanagercomponent.class.php
    • location.class.php
    • right.class.php
    • rightsdatamanager.class.php
    • role.class.php
    • rolerightlocation.class.php

Concepts

Role

A user role, in Skorpiuz the available roles are:

  • Anonymous Visitor
  • Registered User
  • Content Provider
  • Content Reviewer
  • Content Remover
  • Administrator

They categorize users into virtual groups. Rights are applied to roles instead of individual users to make configuration easier (not to mention quicker).

Right

The 4 basic rights available throughout the system:

  • View
  • Add
  • Edit
  • Delete

Location

The current location of the user within the system

Classes

The rights-application has the same basic structure as the repository, meaning that it contains a manager, a datamanager, several databaseresultsets, components and a few basic classes. All of these are built in the same way as their repository counterparts, but with specific functionality for managing and checking roles and rights.

Database

The rights-database contains 4 tables, 3 of which represent roles, rights and locations respectively and a 4th one which is basically the relation between these 3. It contains a numeric reference to the role, right and location as well as a 0 or 1 depending on whether or not the user has the right.

Interaction with applications

The main goal of the system is to be able to control what people can and cannot see on the platform. One of the applications running on top of the Skorpiuz repository is the news-section. For this example I'll be using that section as a basis. The news-application lets users publish news articles, publication is possible in 3 ways thanks to the publisher-class:

  • Create a new object and publish it
  • Browse for a new object and publish it
  • Search for an object and publish it

In all 3 cases the publication is basically an entry into the news_publication table which contains a numeric id and the object id. (as well as the publisher's id, publication date and to/from date, but those are not relevant here.) But not everyone should be able to publish things within this application, so the system has to check whether or not the currently logged on user (if the user is logged on) can publish an object.

This check starts when the News-class makes and runs an instance of the creator-component of the application. When the component is run, it will execute the following code first:

if (!$this->is_allowed(RightsManager :: ADD_RIGHT))
{
	$this->display_header($breadcrumbs);
	Display :: display_error_message(get_lang("NotAllowed"));
	$this->display_footer();
	exit;
}

So what we do is ask whether or not we are allowed to add something within this application. If this is not the case, we display the appropriate message and halt the script. If not the rest of the script is executed.

The is_allowed function is defined as follows within the News-class:

function is_allowed($right, $locations = array())
{
	$user = $this->get_user();
	
	if (is_object($user) && $user->is_platform_admin())
	{
		return true; 
	}
	
	if (count($locations))
	{
		$location_string = self :: APPLICATION_NAME . '|' . implode ('|', $locations);
	}
	else
	{
		$location_string =  self :: APPLICATION_NAME;
	}
	$location = RightsManager :: get_location_id_from_short_string($location_string);
	
	if (is_object($user))
	{
		$role_id = UserManager :: get_user_role_id($user, $location);
	}
	else
	{
		$role_id = RightsManager :: ANONYMOUS_VISITOR_ROLE;
	}
	
	return RightsManager :: is_allowed($right, $role_id, $location->get_id());
}

The additional $locations parameter was added to define an even more particular location. E.g. different news-categories, one may be allowed to publish news in categories, but that doesn't mean he or she can add new categories. In both cases the right involved is the add-right, but in the first case it's on the top-level of the application and in the second case it's on the category sublevel. This sublevel is achieved by passing on an extra location to the is_allowed function.

First we get the user object, if the user is a platform admin we return true by default as the platform admin is allowed to do anything within an application. Then we check whether or not any extra locations were passed on an we build the location string accordingly. We then ask the RightsManager to lookup that specific location. Once this has been returned the only other thing we need is the role the user is on for this location.

First we check whether $user is an object. $user will always be an object when the user has succesfully logged in. The CMS allows anonymous viewing so if the $user-variable is not an object we automatically assign the unidentified user to the ANONYMOUS_VISITOR_ROLE. For all other users we ask the UserManager to give us the role the user is on for the specified location.

Now that we have the right (passed on by the component), the role and the location, we can ask the RightsManager to check whether or not the role is allowed that particular right in the specified location.

The is_allowed function of the RightsManager is as follows:

function is_allowed($right, $role_id, $location_id)
{
	$rdm = RightsDataManager :: get_instance();
	$rolerightlocation = $rdm->retrieve_role_right_location($right, $role_id, $location_id);
	return $rolerightlocation->get_value();
}

What this basically does is retrieve the true or false from the aforementionned table in the database. This value then goes all the way back to the component which will allow you to publish something if the returned value is true or display an appropriate message is the returned value was false.

Defining Roles, Rights and Locations

Roles, rights and locations are defined within the Rights-application and are available throughout the entire LCMS platform. In Skorpiuz' case there are, as mentionned before, 4 basic rights which cover he entire system. There is no possibility to define extra rights for specific locations. While this may seem inconvenient at first, it forces developers to carefully consider the available rights so they can in fact cover the entire system. The fact of course remains that e.g. the ADD-right may be a straightforward add in the repository (for a new version) but might be a publish in an application. This is a matter of semantic and not so much a conceptual matter. There is no way to really force someone to use the ADD-right (or any other right) exactly that way. The most important thing is that this specific right (whatever it's name might be) combined with a specific role and a specific location, will (not) grant the user access to some specific functionality or will allow him or her to do or not do something with an object.

Rights are configured by means of a simple true (green) or false (red) interface:

Image:SkorpiuzRolesRights.jpg

Observations

  • The system does not implement locations as a tree, but as simple strings seperated by a |. E.g. platform|news Moving from one storage format to another should not affect how this works, it would only affect how the locations are retrieved.
  • This system does not implement inheritance to avoid unwanted problems due to oversights (e.g. in general the Add-right is always true, so when you forget to set it to false for a specific location people will have access to places they shouldn't have access to, in Skorpiuz it's the other way round: no access unless the rights say differently). Inheritance could be achieved by adding an inherit flag to each location in the tree.
  • Every bit of code in the is_allowed-function in the news-class after the formation of the location-string could (and probably should) be moved to the RightsManager is_allowed-function. It's unclear why it's not there to begin with.
  • No roles and rights implementation for objects yet, Skorpiuz does not really need it, so we thaught it'd be better to wait and see how things develop within the LCMS project and to then implement them afterwards.
  • Once a location tree has been implemented, an extra option should be added to "lock" a right on a certain level, making it impossible to grant or ungrant that same right on a lower level.
Personal tools