This page last changed on Dec 17, 2007 by jnolen.
These are guidelines related to the development of Confluence. The guidelines mainly apply to Atlassian employees, but reading them should provide insight for third-party plugin developers as well, so we decided to make them public.

The PermissionManager

The core API for checking permissions in Confluence is through the PermissionManager (javadoc). The two most important methods on this interface are:

  • hasPermission – does user U have permission P on object O?
  • hasCreatePermission – does user U have permission to create object of type T inside container C?

So, for example. If you have a page, and want to determine if a user is able to edit it:

boolean canEdit = permissionManager.hasPermission(user, Permission.EDIT, page);

Or, if you want to know if user is permitted to comment on a page:

boolean canComment = permissionManager.hasCreatePermission(user, page, Comment.class);
  • Permissions are defined as constants on the Permission interface (javadoc). They are VIEW, EDIT, EXPORT, REMOVE, SET_PERMISSIONS and ADMINISTER.
  • If the supplied user is null, the anonymous permission is checked
  • For the purpose of checking create permissions, the "containing" object is not the same as the parent. You test if a page can be created in a space, and a comment within a page, not within its parent page or comment.
  • There is a special object – PermissionManager.TARGET_APPLICATION – that represents Confluence itself and is used for checking global permissions
  • Some permission checks don't make sense, for example checking if you can REMOVE TARGET_APPLICATION, or checking if you can administer a page. Checking a nonsensical permission will result in an IllegalStateException
  • Similarly, if you check permissions against a type of object that the PermissionManager doesn't know how to check permissions against (i.e. it doesn't have a delegate for that class, see below), it will throw an IllegalArgumentException.

Permission Inheritance

The system does not cater for any inheritance of permissions. having Permission.ADMINISTER against an object does not imply that you also have Permission.EDIT.

However, certain permissions are considered "guard permissions". For example, permission to VIEW TARGET_APPLICATION is required to do anything in Confluence (it's generally referred to as "Use Confluence" permission). Similarly, permission to VIEW a particular space is required to do anything else in that space. If you are modifying Confluence permissions through the UI, removing a guard permission from a user or group will also remove any dependent permissions that user/group might have. If you are modifying Confluence permissions programatically, you are responsible for making sure they end up in a sensible state w.r.t guard permissions.

PermissionManager Quirks

  • The PermissionManager always checks to ensure a user is not deactivated, and that a user has the "Use Confluence" guard permission.
  • The PermissionManager does not check if the user is a member of the super-user confluence-administrators group. If you want super-users to override your permission check, you have to do it manually.

PermissionManager Implementation

For every type of target object (or container in the case of create permissions) there is a corresponding PermissionDelegate (javadoc) that performs the actual checks. The code should be reasonably self-explanatory

Shortcuts

Getting all viewable/editable spaces for a user

Finding all spaces for which the user has a particular permission is a common, and reasonably expensive operation in instances with large numbers of spaces. For this reason we have a number of shortcut methods on SpaceManager that go straight to the database:

Note: These operations are still not cheap, especially in situations where the user being checked may be a member of a large number of groups.

Searching / Lucene

The Lucene index contains enough information for searches to determine if particular results are visible to the user performing the search. So long as you're not going direct to the Lucene index yourself, and use one of Confluence's search APIs to find content, the content returned should not require any more tests for VIEW permission.

Other Permission-related APIs

PermissionCheckDispatcher

The PermissionCheckDispatcher allows you to check if a particular user has access to a certain Confluence URL. It will only work if the target of the URL is a WebWork action (it works by instantiating the action referred to by that URL, filling in all the relevant form values, and calling isPermitted on the action).

The PermissionCheckDispatcher used to be the preferred way of testing whether or not to display a link in the web UI. However, its use is being phased out because it can be very slow. Do not use the PermissionCheckDispatcher for new code. Instead, use the PermissionManager directly. If you are in UI code, use the PermissionHelper (javadoc), a convenience class that is placed in the Velocity context to make permission checks more Velocity-friendly.

SpacePermissionManager

The SpacePermissionManager is a low-level API for directly manipulating user permissions. You should not use the SpacePermissionManager for checking permissions, because it tightly couples your permission check to the internal representation of permissions in the database. Use the PermissionManager for all permission checks.

The SpacePermissionManager should only be used:

  • By a PermissionDelegate to translate between a logical permission check, and the back-end implementation of that permission
  • By permissions management code (i.e. granting, revoking or displaying user permissions)

Adding New Permissionable Objects

To make it possible to use a new type of object as the subject of a permissions check, you will need to:

  1. write a PermissionDelegate for that object's class.
  2. instantiate the delegate in Spring (delegates are defined in securityContext.xml)
  3. add that object to DefaultPermissionManager's delegates property in securityContext.xml

Adding New Permissions

  1. Ask if this permission is really necessary? For example a lot of things that look like they should be permissions are really "create" permissions (like "can comment on page" is really "can create (comment, page)"
  2. Add a new method to the PermissionDelegate interface.
  3. For each existing PermissionDelegate, implement your new method. Throw IllegalStateException if the permission is not relevant to that delegate's object
  4. Add a new constant to the Permission interface to represent your permission (see the existing examples)

To Do

  • Permissions checking on labels (add, remove) are broken, and still being done via page permission checks
  • We should probably throw UnsupportedOperationException for bogus checks instead of IllegalStateException
  • Currently create permissions are tested against container, not parent. a hasCreatePermission(user, container, parent, klass) could be useful
Document generated by Confluence on Jun 24, 2008 18:04