Last updated by 5 years ago

Page: JSecurity Plugin, Version:0

JSecurity Plugin

JSecurity is a generic pojo security framework for authentication, access control, cryptography, and session management. It is fairly simple to use, but has a great deal of flexibility built in. This plugin attempts to make it even easier to use within a Grails project, while still retaining most of that flexibility.

For the impatient among you, or those who simply want a "drop-in" access control system for their web application, follow the Quick Start Guide

The plugin basically consists of two layers: rights management_, which determines whether a user has a particular role or permission, and _access control_, which restricts access to parts of an application based on required roles or permissions. Underpinning both of these is the role and permission system.

Of Roles And Permissions

What is a role? Commonly, it is simply a job or a set of responsibilities that a person can have. A question often asked in interviews by candidates is: what will my role be? In a security context, it is more specifically a name that represents what someone is allowed to do and what he is allowed access to. For example, "System Administrator" could be a role that allows a user complete, unfettered access to a system. A "User" role simply represents a normal user of a system, and would allow creation of user content for example, but would not allow adding users to the system. Alternatively, you could use something like "Security Level 1", "Security Level 2", etc.

What roles you have and what rights they imply depend very much on the system or application that you are securing. In the end, _you must specify which features/pages/whatever require which roles, and this is done in the access control layer.

The above describes a role-based access control system. However, roles can also be used within a _permission_-based system: in this case they are simply named collections of permissions. So what are permissions? They are fine-grained security primitives that represent single, atomic rights. You will be familiar with them if you have ever used the Java security API or Java Authentication and Authorisation Service (JAAS).

Take as an example {{java.io.FilePermission}}, which restricts access to files. It has two components: the location of the file, and a set of actions that can be taken with a file. Whenever a Java application is running with the security manager enabled and it tries to open a file, the security manager first checks whether the application has the required permission: an instance of FilePermission with the action of "read" or "write", whichever is appropriate. So how does the security manager know? It reads a policy file that contains details of the assigned permissions.

When working with permissions, it is important to understand this difference between a permission in its incarnation as a requirement and in its incarnation as an assigned right. Confusion can easily creep in because the same class is almost always used for both. Note also that a permission in JSecurity is incredibly flexible because the only requirement of it is to provide an {{implies()}} method. This means that your permissions can contain any information you want: a resource location, a set of actions, a controller name, a project code, or any combination of these for example.

In fact, the plugin comes supplied with a ready-made permission: {{org.jsecurity.grails.JsecBasicPermission}}. It is fairly simple, containing just a "target" property and a set of actions. However, this is sufficient for many needs and is particularly well matched to controllers: the "target" can represent the name of the controller, while the "actions" represent the controller actions. In this way, you can allow or deny access on a action-by-action basis.

Here are a couple of examples of permissions, minus the {{implies()}} implementation:

/**
 * With this permission, the actual class provides some context information,
 * i.e. that this permission deals with files and file access.
 */
class FilePermission implements Permission {
    /** 
     * Represents the resource that this permission applies to. It could
     * for example be a file path indicating the location of the file or
     * directory that the permission instance applies to.
     */
    String resouce;

/** * The actions that this permission represents, for example "read" * and "execute". */ Set actions;

/** The actions supported by this permission. */ private static final Set possibleActions = [ 'read', 'write', 'execute', 'delete' ] as Set }

/** * This permission does not apply to particular resources, and its class * does not indicate the 'type' of the permission. Instead, the 'type' is * a property. In addition, the permission has a 'project' property that * indicates which project the permission applies to. This is useful for * any system that has projects or modules in which users can have different * permissions. */ class ProjectPermission implements Permission { /** * This is the type of the permission - it may for example refer to * the name of a single part of the system, such as an audit log. * Note that the actions supported by the permission depend on what * the type is. */ String type;

/** The unique ID of the project that this permission applies to. */ String projectCode;

/** The actions that this permission represents. */ Set actions; }

JSecurity itself does not interpret the permission in any way: it is the application itself that determines its meaning. So how does it work? Permission requirements are specified in the access control layer, while the permission checks are performed in the rights management layer. Both layers are coded by _you_, so JSecurity has no need to understand the meaning of individual permissions.

Subjects and Principals

Before moving on to access control and rights management, there are two concepts that first need to be explained.

A subject represents a real person accessing the system. Actually, it doesn't have to be a real person, but commonly it is. Note that the subject may or may not be known by the system, but that doesn't matter: as soon as a user accesses the system, an associated {{org.jsecurity.subject.Subject}} instance is created. Subjects can be in one of three states:

  • Unknown: The system has no idea who the user is.
  • Remembered: The system remembers the user from a previous session.
  • Authenticated: The user has successfully entered their credentials, so the system knows who the subject is and has confirmed that he is who he says he is.
Note that the second state can only occur if the "remember me" feature is being used.

A principal is an identity, such as a name or a driving licence number. The most common principals in use by online applications seem to be e-mail addresses and usernames. As I am sure you have guessed already, a subject can have many principals but there is often only one primary principal. The Quick Start Guide, for example, works with a username.

The concept of a principal is particularly important when we cover realms.

Rights Management

Some part of the application must decide whether a particular user has permission to do something or not. JSecurity delegates this responsibility to _realms_. You can have as many realms as you like, although each one would normally work with a different system. For example, you may have one realm for handling LDAP authentication, another for GPG key authentication, and another for plain database authentication and rights management.

Realms are created in the directory {{grails-app/realms}} and by convention their names end with "Realm". There are no other requirements, but they should implement at least some, if not all, of these properties and methods:

class MyRealm {
    /**
     * The authentication token supported by this realm. This is
     * often UsernamePasswordToken, in which authentication is
     * performed via a given username and password. An alternative
     * might be a GpgAuthToken that encodes the user's GPG key
     * information.
     *
     * If this property does not exist, the realm does not take
     * part in authentication, even if {{authenticate()}} exists.
     */
    static authTokenClass = org.jsecurity.authc.UsernamePasswordToken

/** * Authenticates a user via the given authentication token. The * token will be an instance of 'authTokenClass'. Should return * a principal or {{org.jsecurity.authc.Account}} instance if * the authentication succeeds, or throw an * {{org.jsecurity.authc.AuthenticationException}} if it does not. * * If this method is not present, the realm does not take part * in authentication. */ def authenticate(authToken)

/** * Determines whether a user has a particular role or not. It * should return {{true}} if the user has the role, or {{false}} * otherwise. {{principal}} is the principal returned by the * {{authenticate()}} method, while {{roleName}} is simply a * string. */ def hasRole(principal, roleName)

/** * Determines whether a user has a particular permission or not. */ def isPermitted(principal, permission) }