Confluence Docs 3.0 : Confluence Permissions Architecture This page last changed on Dec 28, 2008 by rhartono.
| 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.
### Permissions checking overview 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: First, Confluence checks that the user is allowed to access the application. This involves user and group checks for user U against the defined global permissions. Second, Confluence checks space permissions. This involves user and group checks for user U against the space permissions for action A for the space containing content C. Finally, Confluence checks content level restrictions like page permissions. This involves user and group checks for user U against the content level permissions for action A on content C. If all three checks succeed, user U is permitted to do action A to content C by Confluence. The logical operations involved in a "user and group check for user U" look like this, taking space permissions as an example: First, Confluence retrieves all the space permissions for the space containing content C from the database. Next, it checks whether user U is one of the individual users that has been granted the permissions required to do action A. Next, it goes through the groups with permission required to do action A, and checks whether user U is a member of any of those groups. If the membership status of user U and the group isn't cached already, Confluence determines which user repository (database, LDAP, Crowd) owns the group. Confluence checks in the user repository whether user U is a member of the group, and caches the result for subsequent checks. If either check succeeds – that is, if either user U or one of the her groups has permission for the action – user U is permitted to do action A to content C by Confluence. The API used for performing all these checks is described in more detail below. ### The PermissionManager API 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: getPermittedSpaces – get all spaces for which a user has `VIEW` permission getPermittedSpacesByType – get all spaces of a certain `SpaceType` for which the user has `VIEW` permission getSpacesEditableByUser – get all spaces in which the user can create or edit pages getEditableSpacesByType – get all spaces of a certain `SpaceType` in which the user can create or edit pages 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. ### Checking Permissions from Velocity 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). ### 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: write a `PermissionDelegate` for that object's class. instantiate the delegate in Spring (delegates are defined in `securityContext.xml`) add that object to `DefaultPermissionManager`'s `delegates` property in `securityContext.xml` ### Adding New Permissions 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)" Add a new method to the `PermissionDelegate` interface. For each existing `PermissionDelegate`, implement your new method. Throw `IllegalStateException` if the permission is not relevant to that delegate's object 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 Nov 05, 2009 23:34