Access permission to items

Contents

  1. Diagram of classes and methods
  2. The Keyring class
  3. The Permission enumeration
  4. Initialising permissions for an item
  5. Checking permission for an item
  6. Storing permissions in the database

See also

Last updated: $Date: 2009-04-06 14:52:39 +0200 (må, 06 apr 2009) $

1. Diagram of classes and methods

2. The Keyring class

The Keyring [API] class is the core class that is responsible for handling most permission checks in BASE. A keyring object is created when a user logs in using the SessionControl.login() method. The keyring holds information about:

The information in the keyring is reloaded by a timer at regular intervals specified by the permission.timeout setting in the base.config file. The default value of this setting is 10 minutes. The information can also be forced to be reloaded by a call to the SessionControl.reloadPermissions() method.

The keyring object is not available directly to the rest of the application. All access to the keyring is handled by the SessionControl. We do not list all methods for the Keyring class, since most of them are similar and have the same names as those in the SessionControl.

3. The Permission enumeration

The Permission [API] enumeration defines the permissions available in BASE. Each permission is represented by an integer value (grantValue()) that is used when saving permissions in the database. To combine several permission the values can be OR-ed together using the | operator. The values are also constructed in such a way that some permissions implicitly includes other permissions, for example the WRITE permission includes the READ, USE and RESTRICTED_WRITE permissions. See the Javadoc for the permission class for more information.

There is also a denyValue() associated with each permission. This value can be said to be the inverse of the grantValue() value, because the following calculation will effectively remove all denied permissions from those that have been granted: granted & ~denied (granted AND NOT denied). For example:

int granted = Permission.grant(Permission.DELETE); // granted = 31
int denied = Permission.deny(Permission.WRITE);  // denied = 120
int combined = granted & ~denied;  // combined = 7 --> Permission.RESTRICTED_WRITE

4. Initialising permission for an item

Each BasicItem [API] has an internal permissions variable which holds the logged in users permission to manipulate the item. This value is initialised based on the information in the keyring object. In theory, we could have done well without the permissions variable and always do permission checks directly with the keyring object, but for performance reasons we chose to cache the permissions in each item.

Since it is the DbControl [API] that is responsible for creating, loading, saving, deleting, etc. items from the database, it is also the DbControl that is responsible for initialising the permissions. This is done by a call to the BasicItem.initPermissions() method. The Item handling document includes code examples which shows exactly how the DbControl initialises the permissions.

The default implementation of the initPermissions() method in BasicItem will use the SessionControl.getRolePermissions() to find the permissions the logged in user has been granted based on role membership. The OwnedItem [API] class grants additional permissions if the logged in user is the owner of an item, and the SharedItem [API] class grants additional permission if the logged in user has an item or project key with permissions for the item. The ChildItem implementation assumes that an item has a SharedItem parent item and uses those permissions to get the permissions for the child item.

Subclasses that need to grant or deny additional permissions must override the initPermissions() method. For example the News [API] class will grant read access to everyone (even if no user is logged in) if the current date is between the start and end date of the news item. The Role [API] and Group [API] classes are other exemples which grant read permission if the logged in user is a member of the role or group.

As a general rule, if the subclass extends from the OwnedItem, SharedItem, ChildItem or some other subclass to those classes, it is usually not necessary to override the initPermissions() method. If it extends directly from the BasicItem it is more likely that the method must be overridden.

5. Checking permissions for an item

Checking the permissions for an item is very easy. Either use the hasPermission() or the checkPermission() method. The difference is that the checkPermission() method throws a PermissionDeniedException while the hasPermission() returns a boolean.

The two methods are implemented and tagged as final by the BasicItem class. This is because we don't want subclasses to override these methods. If a subclass needs to grant or deny permissions, the initPermissions() method should be overridden.

6. Storing permissions in the database

The various subclasses to the Key [API] class are used to store the actual permissions in the database. There are three subclasses:

Role keys

The database contains one role key for each item type, created during the initialisation of the database. The number of role keys remain fixed. No new ones can be created and they can't be deleted. Each role key may link a role to a permission code, effectively granting those permissions to all users that are members of that role.

// Grant CREATE permission for FILE:s to a role
Role r = ...
DbControl dc = ...
RoleKey rk = RoleKey.getByItemType(dc, Item.FILE);
rk.setPermissions(r, EnumSet.of(Permission.CREATE));
dc.commit();

Note that role keys are never assigned to a particular item. They always apply to all items of a given type. If the DENIED permission is set it overrides all other permissions.

Item keys

Item keys seem similar to role keys, but they are very different. To begin with an item key is assigned to a Shareable item using the Shareable.setItemKey() method, thereby granting users/groups access to that particular item. It is possible to specify the same item key to several items. In fact, once an item key has been created it can't be changed, so the core tries to avoid creating duplicate item keys (ie. item keys with exactly the same user/group/permission combination) by reusing existing item keys. The item key has no set methods to change the permissions. Instead you have to use the helper classes, UserPermissions [API] and GroupPermissions [API].

Project keys

Project keys work in exactly the same way as item keys, except that they share items to projects instead of to user and groups. To set the permissions you use a ProjectPermissions [API] object.

There is, however, another dimension to projects keys. Members of a project has a permission associated with that project, which is the upper limit for access to items in that project. For example, a user is a member of a project with USE permission (the recommended permission), and we have two items shared to the project, one with READ permission and the other with WRITE permission. The user's permissions to those items are READ and USE respectively. Another project member with DELETE permission in the project will get READ and WRITE permission to the items.

Project keys are only loaded for the currently active project which is set by calling the SessionControl.setActiveProject() method. And, if a project is active, the core will share new items to that project automatically.

MultiPermissions class

The MultiPermissions [API] class is not shown in the diagram. It is a useful helper class to modify lots of permissions to multiple items at the same time, while keeping those that has already been set, even if the logged in user doesn't have access to all other users, groups or projects.