BeNOW Security API
Andrew Taylor <andy@benow.ca>
Overview
- Users
- Roles
- Permissions
Usage
Backends
Management
Javadoc
The Security API provides fine grained user access assertion and management.


Overview
The security api was designed to provide fine grained access permission to users. It was designed to be easy to use, develop, maintain and manage. The core of the api is Users, Roles and Permissions.

Users
Users are the code representations of people. A user has a name, password and email address. A user also has zero or more roles and zero or more permissions. There are two special types of users: the administrator and the default (anonymous) user. The administrator has access to everything... that is, there is no area to which access is denied. The default user has the lowest level of access.

Roles
Roles are definitions of types of users. A user may be a page administrator, a wiki administrator, an album contributor, etc. The role itself is nothing more than a named collection of permissions. Users are assigned roles according to what they will be doing. For example, Joe may be updating album database entries, so he's assiged the Album Contributor role, which contains permissions to create albums, modify albums, rename tracks, add artists, etc.

Permissions
Permissions are required for operations to be performed. It is guarenteed that after permission assertion, the user has the permission. There is no limit to the number of permissions that may be defined (the granularity). Before an operation is to take place to which only certain users should have access, the associated permission should be asserted. For example, in the addAlbum(Artist,String) method, the "org.my.music.Album.add" permission might be asserted. For more details on assertion, see Usage.


Usage
Declaration - Permission declaration is a good starting point for describing how to use the security api. Permissions are declared in code, usually in the class that contains the methods to be secured. For example:

package test.org.benow.security;
:
public class SomeOperation {
  public static final Permission PERM_INVOKE = Security.declareLocalPermission("invoke");
  :
}
That chunk of code uses the Security helper class to declare a permission named 'test.org.benow.security.SomeOperation.invoke'. The class name is inferred using the stack trace. That is it for permission declaration, any fancy stuff could be done behind the scenes in the active backend, but more on that later.

Once declared, the permission can be asserted before protected code, as such:

  public void doSomething() {
    PERM_INVOKE.assertPermission();
    System.out.println("User: "+Security.getCurrentUser().getName()
      +" has permission: "+PERM_INVOKE);
  }
So, the permission is asserted at the start of the doSomething() method. If the user (associated with the current thread) has the permission, execution continues. If the user does not have the permission, as java.lang.security.SecurityException is thrown and the sensitive code is not executed. The full class looks like this:

package test.org.benow.security;

import org.benow.security.Security;
import org.benow.security.permission.Permission;

public class SomeOperation {
  public static final Permission PERM_INVOKE = Security.declareLocalPermission("invoke");
	
  public void doSomething() {
    PERM_INVOKE.assertPermission();
    System.out.println("User: "+Security.getCurrentUser().getName()
      +" has permission: "+PERM_INVOKE);
  }
}
That is all there is to permission declaration and assertion, but in order for the assertion to take place, the current user must be tested. Before the user can be tested, the user itself must be fetched in a process called authentication... that is, the username and password must be specified and used to retrieve the user. If the password is incorrect, another SecurityException is thrown. An example of authentication follows:

  User user=Security.authenticate(userName, password);
We know the user, and now need to associate the user is associated with the secure code execution. The invocation of secure code is slightly different than normal code, in that the code must be associated with the user. This prepared invocation should take place whenever code that requires security is invoked. If code requiring security is executed without being associated with a user, a warning is issued and the user is assumed to be the administrator, so wrap it or anybody can do anything. An example of wrapped execution is:

  Object result=Security.associate(user, new PrivilegedAction() {
    public Object exec() throws Exception {
      return new SomeOperation().doSomething();
    }
  }).exec();
  System.out.println(result);
The final full invocation class looks like this:

package test.org.benow.security;

import org.benow.security.Security;
import org.benow.security.user.PrivilegedAction;
import org.benow.security.user.User;

public class SecurityTester {

  public static void main(String[] args) {
    if (args.length<2) {
      System.err.println("Usage: "+SecurityTester.class.getName()+"  ");
      System.exit(-1);
    }
    String userName=args[0];
    String password=args[1];
		
    try {
      User user=Security.authenticate(userName, password);
      Object result=Security.associate(user, new PrivilegedAction() {
        public Object exec() throws Exception {
          return new SomeOperation().doSomething();
        }
      }).exec();
      System.out.println(result);
    } catch (SecurityException e) {
      System.err.println("Insufficient permissions to execute action.");
      e.printStackTrace(System.err);
    } catch (Throwable e) {
      e.printStackTrace(System.err);
    }
  }
}
There is more to the security api, but not much more, from a casual developer perspective. Notibly, the Security class is the primary way of accessing security functions and objects and many of its methods are useful.


Backends
The security api is an abstract api, in that it specifies the way to do things, but does not do any low level underlying processing. Underlying processing (ie storing and fetching users, roles and permissions) is done by a SecurityAdministrator implementor. Typically security provision implementors extend the SecurityAdministratorImpl class and implement the required abstract methods. There are two active implementations of security administrators provided in other BeNOW projects:
  • RepositorySecurityAdministrator - repository - An administrator that uses a the object repository api (ie from a jdbc database) to provide security information. This backend features automatic table creation, automatic permission registration, fast performance, flexible persistence, easy development and administration and a few other tricks.
  • XMLSecurityAdministrator - benow-castor - An administrator that uses augmented castor to manage an xml file containing security information. It does the job, but it is best suited to quick development, but does not scale... not that it matters much for smaller multi user apps.
For larger projects, you probably want to use the RepositorySecurityAdministrator. To specify which administrator to use, the 'org.benow.security' configuration must be edited (probably as etc/config/org.benow.security.xml). Change the 'org.benow.security.Security.administratorClass' entry to indicate which administrator backend is to be used. By default, the RepositorySecurityAdministrator is used. See the repository project for details.


Management
User management is done at the backend level. That is to say, when using the RepositorySecurityAdministrator, security objects are stored in a database, and it is via fetching, modification and updating that objects are changed. The same is true of the XMLSecurityAdministrator, where security objects are modified by editing the xml configuration. There is, however, a nice set of web pages as part of the BeNOW web project which are actively maintained and make login, permission assignment and user management quite friendly when using the XMLSecurityAdministrator. Check out the web project for more details.


Javadoc
Javadocs can be built via 'ant javadoc'. Once built, they may be viewed here.