Note: The permissions system and this document are still under development and are subject to change. All code in the permissions system has been tested and works, but may be refined in later versions
The Permissions system was designed to manage user access to content that is being displayed with the Locomotive. The API, implemented in the classes in the package org.locomotive.loco.perm, provides a set of objects which may be used together to create a sophisticated access management system. We'll start out by defining the various objects, then show how to create them and use them together to control access to a page or item to be displayed.
Uses of the Permissions libraries can be found in the Community, Publisher, and User Preferences modules which come with the Locomotive. The Community module, for example, grants a special permission to the admin User which allows the Admin user to access the community administration pages and modify Discussions, Categories and Topics. It also utilizes access control lists to restrict certain Categories from being viewed by groups of users.
In the last part of the chapter we'll take a close look at the use of permissions in the Community module, to provide an example of a working implementation. We'll show how the Community system grants a special permission to the admin User which allows the Admin user to access the community administration pages and modify Discussions, Categories and Topics, We'll also take a look at how the Community system utilizes access control lists to restrict certain Categories from being viewed by groups of users.
The Permissions library consists of five different objects: permissions, permission sets, roles, groups, and access control lists.
Permission objects have a unique name and a unique ID. The name is what is used by the permissions system to identify the permission; the ID is arbitrarily chosen by the database. Permission creation, modification, and access methods are provided in the Permission class. This class keeps a cache of all the permissions currently in the system, which allows for efficient access to all permissions by the permission system.
To create a new permission and store it persistently in the database, use the createPermission() call. For example:
Permission newPerm = Permission.createPermission(hd.conn,
"NEW_PERM");
This permission is created in the database and loaded in the cache. Note that permission names have to be unique; if there was already a permission named "NEW_PERM", a SQLException would be thrown.
Once a permission is created, it can be retrieved via the Permission.get() call:
Permission newPerm = Permission.get("NEW_PERM");
We'll get to what you can do with the object soon, but first, let's go over some other methods in the Permissions class. To display all the permissions in the system, you may use one of two calls:
Vector perms = Permission.getPermissions(hd.conn);
Vector names = Permission.names(hd.conn);
The first returns a Vector of permissions; the second returns a Vector containing the names of all the permissions as String. Notice that the first methods requires a database connection. It bypasses the cache and goes directly to the database to retrieve the permissions. While this may be more accurate if there may be issues with other applications updating the database, the second method call, which uses the cache, is more efficient and should probably be used instead.
View the javadocs for this class
Permission sets are basically bit sets associated with a userid, where each bit represents a permission. If the bit is set, then the permission is granted to the user who owns the permission set. The PermissionSet class provides a series of methods to set and clear bits on a permission set. for instance:
Permission newPerm = Permission.get("NEW_PERM");
PermissionSet pset = new PermissionSet(hd.user.getId());
if (! pset.isSet(newPerm))
pset.set(newPerm);
There are also a few methods which are useful for displaying a permission set.
pset.getSetPerms()
returns a vector of the names of the set
permission as Strings
pset.getPermTable()
returns a SortableTable of all the
permission names and whether
or not each permission is set in this permission set. This is
useful for displaying permissions for alteration on a page. The
UserPrefs module has an example of this.
Methods to get and store permission sets in the database can be found in the UserPerm class. Here's an example of how they may be used:
PermissionSet pset = UserPerms.getPermissions(hd.user.getId(), hd.conn);
Permission perm = Permission.get("SOME_PERM");
if (! pset.isSet(perm))
pset.set(newPerm);
UserPerm.setPermissions(perm, hd.conn);
There are also methods to query the database for users with a certain set of permissions.
UserPerms.usersWhoHave(Connection conn, String permName)
returns a vector of userids which identify the users who have
the specified permission.
UserPerms.usersWhoHaveAny(Connection conn, PermissionSet pset)
returns a vector of userids which identify the users who have
any of the permissions in the specified permission set.
UserPerms.usersWhoHaveAll(Connection conn, PermissionSet pset)
returns a vector of userids which identify the users who have
all of the permissions in the specified permission set.
Queries such as this can simplify and enhance user administration and access control.
View the javadocs for PermissionSet
View the javadocs for UserPerm
Roles are subclasses of PermissionSet which have all the functionality of permission sets, but don't have to be associated with a particular user. That allows a single role to be associated with many users. The Role class has only simple field access methods; the RoleManager class pro access to the database for Roles. Here's an example where a role is created, saved to the database, then associated with a user:
Role newRole = new Role("MY_NEW_ROLE");
Permission perm = Permission.get("ANOTHER_PERM");
newRole.set(perm);
RoleManager.addRole(newRole, hd.conn);
RoleManager.addRoleToUser(hd.user.getId(), newRole.getName(), hd.conn);
// now let's get the role that we just set-
// it will contain the new role we just created
Vector setRoles =
RoleManager.getRoleNamesForUser(hd.user.getId(), hd.conn);
Note here that the role was saved, using addRole()
,
before it was added to the user. This is necessary, as
addroleToUser()
will throw a SQLException if the role does
not exist.
View the javadocs for this class
Groups are objects which can be used to manage a list of users. Groups contain lists of the unique usernames of the users that are part of them The methods used to access groups and manipulate them are very similar to those of the Role and RoleManager classes. Here's an example of creating a group, adding a user to it, and saving it in the database.
Group newGroup = new Group("ADMINISTRATORS");
newGroup.addUser(hd.user.getUserName());
GroupManager.addGroup(newGroup.getName()), hd.conn);
Groups function primarily as ways to group users for convenient organization within a certain Access Control List.
View the javadocs for this class
Access Control Lists are objects that define permissions and the users and groups that can access that object by possessing those permissions. As an example in the Community Module, ACLs applied toward categories and topics. For example, a topic in the Community Module has an ACL that may contain the permission "COMM_READ", and for this permission there exists a list of users and groups associated with it. In addition to there being a set of users and groups associated with "COMM_READ", there is also something called polarity, which is simply a boolean flag.Therefore if the polarity is 'true', then the users and groups listed with this permission are allowed to read this topic, and all others do not have read access to that particular topic. If the polarity is 'false', then the users and groups associated with "COMM_READ" in this ACL are explicitly not allowed to read this topic, but all other users in the system can read the topic.