Skip to content
nyeholt edited this page Nov 29, 2012 · 11 revisions

Getting started

  • Install the module
  • Add the extensions
  • Navigate to the node (SiteConfig, Page, or custom data object type) that you want permissions applied on.
  • On the Permissions tab, click "Add Access Authority"
  • Select the role to give the user. This will give them the permissions defined for this role in the Access Roles section of the CMS
  • Select which members or groups to grant this role for
  • Select whether to GRANT or DENY this permission
  • Click "Save"
  • Once the permission table refreshes, you will see all the permissions granted for that "Authority".

Preview Site

Preview site

Logins - admin:admin and editor:editor

If you login as admin, you'll see that the Site has been configured with the Content Authors group having the Editor role (View, Write, CreateChildren), meaning that editor (who is in that group) can edit any content in the site. However, if you then look at Home -> Child, you'll see that editor is explicitly denied write access on that page. If you login as editor, you'll see what this effect has.

Why?

This module is based around the idea that code such as the following

DataObject::get('MyObject');

is inherently insecure because it relies on the end-developer explicitly filtering the result set manually. This is similar in one respect to the problems of SQL injection, CSRF and XSS vulnerabilities - a framework should protect its end users from these problems as much as possible, and NOT rely on its end users (in a framework, end users being developers) to always do the Right Thing.

Secondly, it tries to address the problem that within Sapphire, writing code that does permission management at the moment is a very manual, inconsistent process. The CMS itself is a good example of this - it has explicit separate content relationships to manage access (ViewerGroups, EditorGroups etc) which are incompatible with other content types (eg File, custom data objects) and (I find from talking with clients) confusing in their behaviour. In addition to this, Sapphire has another layer of permission definition with the sectional access rights (eg Access to all CMS sections) which in some cases override content permissions and other times don't. This module solves the first issue of permission management on dataobjects, leaving the sectional access rights as they currently exist. As well as the capability of granting access to content trees, it allows the explicit denial of access for specific subsets (or individual) users that might have access granted at a higher level.

Finally, it introduces the concept of content ownership to the system, whereby someone who is the owner of a piece of content always has a specific set of permissions to content they own (but not the ability to publish it).

The basis of the module is that all code should be written with the idea that that permission checks be made against low level permissions such as

class DefaultPermissions implements PermissionDefiner {
	public function definePermissions() {
		return array(
			'View',
			'Write',
			'Delete',
			'CreateChildren',
			'Publish',
			'UnPublish',
			'ViewPermissions',
			'ChangePermissions',
			'DeletePermissions',
			'TakeOwnership',
			'Configure',
		);
	}
}

CMS administrators then have the ability to bundle these low level permissions into meaningful roles which can be applied to specific sections of the site. For example, an "Editor" role might only be able to View, Write and CreateChildren, whereas a Manager role might have permissions. A key point though is that these roles can be applied to different trees of a site, meaning a user can have the permssions given to a Manager in one tree, but no access to another part of the tree.

The module provides several different layers to help address these issues

  • Code wrappers around DataObject::get* methods to automatically perform permission checks before returning data object(sets)
    • singleton('DataService')->typeById($id)
    • singleton('DataService')->getAllType($filter)
    • singleton('DataService')->getOneType($filter)
  • Extension class (Restrictable) that adds canView/Write/Delete/AddChildren implementations which can be added to your own data objects. It also gives you the interface for managing permissions on that data object for free so you don't have to roll your own
  • Field level editing restrictions - Specify a permission required to edit a specific field. For example, the provided PageExtension specifies that only users who have "Publish" permission can edit the Title or URLSegment fields. You'll notice if you try the demo site as 'editor', these fields are unable to be edited. (this check is done on write, so it's not just a cosmetic effect)
  • A not fully fleshed out TransactionManager wrapper for executing a block of code with a specific set of user permissions, in a db transaction (supports closures)
  • Interface for creating and managing roles

FAQ

Can I specify a permission needed to view any object of a particular type?

Yes; you can set a static variable for a given class type called 'view_permission' which is the name of the permission a person needs to the object to be allowed to view it. If this is not set, the user needs the 'View' permission for viewing objects. Be aware that this only refers to items retrieved from the 'DataService' though!

[Getting Started] Performance Implications

Clone this wiki locally