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.
In Confluence, a permission check is a question like does user U have permission to do action A to content C? The way we answer that question deserves a brief overview of the logical operations:
The logical operations involved in a "user and group check for user U" look like this, taking space permissions as an example:
The API used for performing all these checks is described in more detail below.
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:
1 2boolean canEdit = permissionManager.hasPermission(user, Permission.EDIT, page);
Or, if you want to know if user is permitted to comment on a page:
1 2boolean canComment = permissionManager.hasCreatePermission(user, page, Comment.class);
Permission
interface (javadoc). They are VIEW, EDIT, EXPORT, REMOVE, SET_PERMISSIONS and ADMINISTER.PermissionManager.TARGET_APPLICATION
- that represents Confluence itself and is used for checking global permissionsREMOVE
TARGET_APPLICATION
, or checking if you can administer a page. Checking a nonsensical permission will result in an IllegalStateException
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
.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.
confluence-administrators
group. If you want super-users to override your permission check, you have to do it manually.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
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:
VIEW
permissionSpaceType
for which the user has VIEW
permissionSpaceType
in which the user can create or edit pagesNote: These operations are still not cheap, especially in situations where the user being checked may be a member of a large number of groups.
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.
It might be difficult (or even impossible) to construct a required PermissionManager
call from velocity code, especially for calls to the hasCreatePermission()
method. For this reason there is an object called permissionHelper
(javadoc) in the default velocity context with a number of helper methods to perform common permission checks.
If you can not find an appropriate method on the PermissionHelper
, your best course of action is to write a Velocity context plugin to encapsulate your permission checking code (or if you're an Atlassian developer, obviously, just add it to the helper).
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 Struts 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 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.
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:
PermissionDelegate
to translate between a logical permission check, and the back-end implementation of that permissionTo make it possible to use a new type of object as the subject of a permissions check, you will need to:
PermissionDelegate
for that object's class.securityContext.xml
)DefaultPermissionManager
's delegates
property in securityContext.xml
PermissionDelegate
interface.PermissionDelegate
, implement your new method. Throw IllegalStateException
if the permission is not relevant to that delegate's objectPermission
interface to represent your permission (see the existing examples)UnsupportedOperationException
for bogus checks instead of IllegalStateException
hasCreatePermission(user, container, parent, klass)
could be usefulRate this page: