Grail's Jsecurity plugin HOW TO

How it works

This plugin is a Grails wrapper over the JSecurity framework. It integrates JSecurity with grails. There are two basic points of integration:

  • The "grails-app/conf/SecurityFilters.groovy".
  • The accessControl static closure on each controller.

Interesting: http://skillsmatter.com/podcast/java-jee/exploring-the-power-of-jsecurity-in-grails

Security Filters (filter level access control)

Its responsibility is to intercept requests and apply security rules to them. All security filters should be contained in the file "grails-app/conf/SecurityFilters.groovy", this filter container will need the same conventional structure as all other filter containers in grails configuration (grails filters).

Security filters will be provided with an accessControl() method wich will be invoked to check access control to the filtered resource. If a closure parameter exists on the call to accessControl() it will be executed and if the result of this execution was true the request will be granted access to the resource. If the result was false then the request wont be authorized to access the resource. If the closure parameter is null then the convention will check that the user has the required permission for the target controller/action.

Security filters have to perform security checkings on its before function otherwise no security will be applied. What allows the intercepted request to be granted access to a resource is the return value of the before function of the corresponding filter.

There is a configuration parameter that determines if authentication is required for accessControl() or not. By default it is required. The name of this configuration parameter is 'jsecurity.authc.required'.

If the user accessing a resource is not authenticated the accessControl() method behaviour defaults to redirect the user to the login page. However this can be changed by adding an 'onNotAuthenticated' method to the SecurityFilters class, this method will be called with the subject and filter parameters.

The plugin's quick start page suggests to use a SecurityFilters centralized authorization approach, but I think on any application with a minimum complexity on security control a controller based appoach is much better.

Controller based security (controller level access control)

When a controller centric security is wanted it is necessary to configure 'grails-app/conf/Config.groovy' with a jsecurity.legacy.filter.enabled setted to true. This will activate a plugins's internal filter, named JsecurityFilters, that checks the rules defined on the controllers' accessControl() method. By default this filter is not active.

By the way, this JsecurityFilters doesn't interfere with application's SecurityFilters instead it adds its security checks to the application ones. Thus, when both exist a request will have to succeed on both, the SecurityFilters custom checks and the JsecurityFilters controller checks, to gain access to a resource.

Note that JsecurityFilters does not forces the user to be authenticated, this should be done through SecurityFilters.

This example filter at SecurityFilters checks user authentication for all controllers and avoids the application of the convention

public class BookingController
{
    // ACCESS CONTROL ----------------------
    static accessControl = {
        // role required for a single action
        role(name:"BOOKING_USER", action:"book")
        // role required only for 'update' and 'cancel' actions
        role(name:"BOOKING_MANAGER", only:["update", "cancel"] ) 
        // role required for all actions of the controller
        role(name:"AGENT")
        // permission required for a single action
        permission(perm:"booking:customers:add", action:"addCustomers")
        // permission required only for some actions
        permission(perm:"booking:paymentMethod", only:["changePaymentMethod", "setCreditCard"] )
        // permission required for all actions
        permission(perm:"booking")
    }
 
    // actions...
}

Controller's accessControl

Any controller can contain a static accessControl closure property which defines the security requirements (based on roles and permissions) to access to its actions. Surprisingly, the syntax of the available methods for this accessControl function is different form the accessControl closure on SecurityFilters, which in turn is intented to be used to override controller's access control.

Authentication process

The authentication process starts at the AuthController.signIn() action. There the login task is delegated to the configured security manager. The jsecurity plugin adds an org.jsecurity.web.DefaultWebSecurityManager named jsecSecurityManager into spring's context, this security manager is the one which is autowired into the AuthController.

From the DefaultWebSecurityManager the task of authenticating is delegated to its authenticator, a ModularRealmAuthenticator, which in turn delegates to the JsecDbRealm. There the authToken is checked against the user's SimpleAccount using the configured credentialMatcher. The org.jsecurity.authc.SimpleAccount contains principal and credential and authorization information (roles and permissions) as instance variables. If the credentials do match, the new SimpleAccount is returned and it returns up to the DefaultSecurityManager. There a new DelegatingSubject with the AuthenticationToken and the SimpleAccount is created and binded to the application's session.

The default JsecDbRealm creates an instance of SimpleAccount with the user's username as the principal. This approach for me is too naive and I've prefered to modify JsecDbRealm to pass the whole JsecUser as the SimpleAccount's principal. This forces you to update the code of all JsecDbRealm methods to deal JsecUser principals instead of the username String, but I think it's worth to (you will agree it when using the <jsec:principal /> tag).

authenticationProcess.png

Taglib

The best is to check them on the plugin's 'grails-app/taglib/JsecTaglib.groovy' file. But here's a recopilation:

  • isLoggedIn: only displays its contents if the user is logged in.
  • isNotLoggedIn: only displays its contents if the user is not logged in.
  • authenticated: synonym for isLoggedIn.
  • notAuthenticated: synonym for isNotLoggedIn.
  • user: only displays its contents if the user is recognised, either via "remember me" or login.
  • principal: displays the current user's principal, e.g. username.
  • hasRole: only displays its content if the current user is authenticated and has the given role.
  • lacksRole: the inverse of hasRole.
  • hasPermission: only displays its content if the current user is authenticated and has the given permission.
  • lacksPermission: the inverse of hasPermission.

Several new tags related to "remember me":

  • <jsec:notUser> - Writes out the content only if the user is a guest, i.e. neither remembered nor authenticated.
  • <jsec:remembered> - Writes out the content only if the user is remembered (but not authenticated).
  • <jsec:notRemembered> - Writes out the content only if the user is a guest or is authenticated.

More tags related to roles:

  • <jsec:hasAllRoles> - Writes out the content if the user has all the given roles (specified in the 'in' attribute as a list).
  • <jsec:lacksAnyRole> - Writes out the content if the user has none of the given roles.
  • <jsec:hasAnyRole> - Writes out the content if the user has at least one of the given roles.
  • <jsec:lacksAllRoles> - Writes out the content if the user has none of the given roles.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License