Grails Acegi (Spring Security) Plugin v0.5 Released

Version 0.5 went out yesterday. This was an interesting one to work on. There were a few relatively minor bug fixes, but there are four new features/enhancements and the plugin now works with Grails 1.1.


Probably the coolest new feature is being able to define security rules directly in the Controllers. Previously there were two ways to define the URL->Role mappings, in a static string (the standard Spring Security approach) or using Requestmap entries in the database. Now there’s a third – using annotations in controllers.

I’d written about using annotations previously and I used that approach. Annotations can be ugly, but I think here they’re great here since they’ll only ever have a fairly short list of values (roles plus special tokens like IS_AUTHENTICATED_FULLY, etc.). You can annotate individual actions and/or put an annotation at the class level and then all of the actions in the controller share those mappings, and if needed you can override that for individual actions. And they’re inheritable, so if you use controller base classes you can define them there and share rules throughout the hierarchy. For example, if you have an AbstractAdminController that all administrative controllers extend you could annotate just the base class with @Secured(['ROLE_ADMIN']) and restrict access to the entire admin hierarchy.

There are some notes here describing the new approach and the original two.

To better support stuff like administrative sections of a site, I added in an IP address filter so you can specify IP ranges (using Ant patterns or masks) for URLs. This way you can restrict access for your admin area to ’10.**’ or ‘192.168.**’ in addition to requiring specific roles to ensure that only users in the intranet or VPN have access.

I also added in support for ChannelProcessingFilter to allow defining which URLs require HTTPS and which require HTTP. With this addition there aren’t many Spring Security filters left that haven’t been mapped in the plugin – just ConcurrentSessionFilter, SessionFixationProtectionFilter, X509PreAuthenticatedProcessingFilter, and RequestHeaderPreAuthenticatedProcessingFilter.

Someone on the Grails user mailing list was talking about Facebook logins, and I’d been wanting an excuse to play with their API so I wired up support for that. It’s of limited use (like the OpenID support) since you don’t get much information from the authentication, so there would be a lot of manual work required in the app when setting up user information in the database. For example, you don’t even get the login name/email, only the numeric ID, so that has to be the username attribute in the User table.

Getting things going with Grails 1.1 was interesting. There was one real bug that I’d introduced in AuthenticatedVetoableDecisionManager – I think it’s a Groovy bug but I worked around it. I had named both a variable and a method deny, and it was trying to invoke deny() on the variable instead of the method. I changed it to denyCount which is more self-documenting and it was fine.

The plugin generates its own controllers and CRUD pages, so I needed to update those to use new 1.1 features. The allowedMethods map is now static so I changed those to avoid warnings at startup. Optimistic locking is now checked in controllers by adding an <input type='hidden'> form element in the GSP with the current domain instance version and checking it against the database after submitting updates, so I wired that up so the User/Role/Requestmap management pages work like non-plugin pages.

I also had to rework my automated testing due to the changes in the way plugins are installed in 1.1. I have an Ant task that creates a test project, installs the plugin, and configures the app for testing. Then I run a suite of automated tests using the WebTest plugin. Plugins are now global by default, so installing a plugin for a second app will share the plugin that the first app installed, which will save a bunch of space both locally and in source control. But I need the plugin to be local to the test app, and this is possible by overriding the default behavior and reverting to the 1.0 approach by setting grails.plugins.dir='plugins' in grails-app/conf/BuildConfig.groovy. And this doesn’t affect 1.0 since BuildConfig.groovy is ignored.

So check out the new release. There are no backwards compatibility issues, so upgrading is simple. Check out the fixes and enhancements here and the docs here.

8 Responses to “Grails Acegi (Spring Security) Plugin v0.5 Released”

  1. Nicolas says:

    I really like more and more the acegi plugin. Thanks a lot for the great work. I am really looking forward to use the annotation wich seems like a great new feature.

    FYI, I still need to customize it for my usage (I have the authentication done separetely from the application and I use the request.getRemoteUser to get the current user). To get this to work I need to use custom made a “pre-authentication” filter and overrides the filterNames and providerNames in SecurityConfig.

  2. Very nice plugin, and nice work. Thanks.

    I followed the steps in the ‘Basic Tutorial’ (twice) and found two problems:

    1. Selecting the ‘admin’ role for a user when creating it, doesn’t actually assign it. I checked in the database, and the ‘role_user’ table is empty.

    In this situation, when I attempt to login, it returns back ‘[testuser] wrong username/password.’ error message.

    2. If I add a row in the ‘role_user’ table (values 1, 1), I get ‘Sorry, you’re not authorized to view this page.’

    I figured I must have missed something, but deleting and redoing the ‘bookstore’ project came up with the same errors.

    Sorry to post this on your blog, but I mention this here to find out where the forum is for this plugin. Thanks again.

  3. Burt says:

    Sorry, I didn’t update the tutorial to adjust for the one backwards-compatibility issue introduced in 0.5.0/0.5.1.

    Previously you could only store role names in Requestmaps, so you’d work with the “natural” names and the generated UI would add in the suffix “ROLE_” and uppercase the whole name. Now however you can put any valid token (e.g. IS_AUTHENTICATED_FULLY) in the list of Requestmap role names/tokens, so you have to properly specify the full role name when creating them or using them in Reqestmap definitions.

    So in both the “create an ‘admin’ role:” and “create the mapping for SecureController:” steps, change “admin” to “ROLE_ADMIN”.

    I’ll update the docs today.

  4. markatharvest says:

    Thanks Burt, for wonderful plugin.
    I am using the latest 0.5.1 to secure the controllers with annotations in place of static settings.
    However, I am using a Settings plugin which has a Setting Controller in it, since I do not own that code, I do not want to touch it.
    How do I secure it, is there a way I can use the combinaton of annotation and securityconfig requestmapString. (I tried it does not work)
    Thanks again, for now I have added annotation manually

  5. Burt says:

    @Mark To support stuff like this and also non-controller URLs like for .css/.js there’s a ‘controllerAnnotationStaticRules’ attribute that you can set in SecurityConfig.groovy, e.g.

    controllerAnnotationStaticRules = [
    ‘/setting*’: [‘ROLE_ADMIN’],
    ‘/setting/**’: [‘ROLE_ADMIN’]
    ]

    You can omit the 1st entry if there’s no ‘index’ action. See the docs here for more info

  6. Dru says:

    You appear to know what your talking about so I thought I would ask you about my problem.

    I am running grails 1.1.1 and acegi 0.5.1 with java 6 on Ubuntu.

    First: When following the tutorials for storing the security mappings in the database and for the annotations. They would not create the link between the role and user correctly. I fixed that manually though so I could log in.

    Second: When trying to access the secure address it always tells me that I don’t have access. I have used a role of “admin” and “ROLE_ADMIN” with the request map being “ROLE_ADMIN”, “admin”, and “ROLE_admin” (I was trying anything to get it working) with none of them working.

    Third: Attempting to use the annotations I get an error that it can’t find org.codehaus.groovy.grails.plugins.springsecurity.Secured
    which I am guessing is not correct. I noticed that the plugins directory was not put in the project folder rather it was put in the ~/.grails/1.1.1/plugins directory.

    First I need to get the security fixed so I can secure my app. Then I would like to try the annotations because that method is very appealing to me.

    Any help suggestions are greatly appreciated.

  7. Steve Neal says:

    The image links on the tutorial page seem to be broken. This made following the tutorial pretty tricky.

    For anyone else trying this, make sure you:

    1) enter ROLE_ADMIN for the role name when instructed to create a role called ‘admin’

    2) make sure that the user account you create is enabled and that the role is assigned to that user by checking the appropriate checkbox.

    I’ve used ACEGI in other projects and its a great framework.

    Thanks for creating this Grails plugin so that I can continue using it!

  8. Baji Shaik says:

    Hi Burt,

    Myself I am very new to Grails, I just purchased your book “Programming Grails” and reading it.

    I got a new requirement like, I need to provide Grails applications with Single Sign On(SSO) by using Spring Security CAS plugin.

    I had implemented the same requirement with JAVA and Jasig CAS instead of Grails & Spring Security Cas but now I must implement with Grails.

    The application whatever I implemented is successfully redirected to CAS when I requested to Protected/secure page and successfully authenticated with CAS also but after authenticating it is redirecting me to the Spring Security Authentication Login page(http://localhost:8080/appone/login/auth?login_error=1) instead of rendering my requested page(http://localhost:8080/appone/home).

    Please find the below step by step approach which I followed to implement Grails applications with CAS

    Step-1: Open the command prompt and run the following command:
    D:\>grails CreateApp appone

    Step-2: Moved to appone folder
    D:\>cd appone

    Step-3: Added the plugins to “D:\appone\grails-app\conf\BuildConfig.groovy” file as follows

    plugins {
    runtime “:hibernate:$grailsVersion”
    runtime “:jquery:1.7.1”
    runtime “:resources:1.1.6”

    // Uncomment these (or add new ones) to enable additional resources capabilities
    //runtime “:zipped-resources:1.0”
    //runtime “:cached-resources:1.0”
    //runtime “:yui-minify-resources:0.1.4”

    build “:tomcat:$grailsVersion”

    compile ‘:spring-security-core:1.2.7.3’
    compile ‘:spring-security-cas:1.0.2’
    }

    NOTE: I just added only spring-security-core and spring-security-cas only, remaining are default ones

    Step-4: Added the following CAS server details to /conf/config.groovy file at the end of the file

    grails.plugins.springsecurity.securityConfigType = ‘InterceptUrlMap’
    grails.plugins.springsecurity.interceptUrlMap = [
    ‘/home/**’: [‘IS_AUTHENTICATED_REMEMBERED’],
    ‘/js/**’: [‘IS_AUTHENTICATED_ANONYMOUSLY’],
    ‘/css/**’: [‘IS_AUTHENTICATED_ANONYMOUSLY’],
    ‘/images/**’: [‘IS_AUTHENTICATED_ANONYMOUSLY’],
    ‘/*’: [‘IS_AUTHENTICATED_ANONYMOUSLY’],
    ‘/login/**’: [‘IS_AUTHENTICATED_ANONYMOUSLY’],
    ‘/logout/**’: [‘IS_AUTHENTICATED_ANONYMOUSLY’]
    ]

    grails.plugins.springsecurity.cas.loginUri = ‘/login’
    grails.plugins.springsecurity.cas.serviceUrl = ‘http://localhost:8080/appone/j_spring_cas_security_check’
    grails.plugins.springsecurity.cas.serverUrlPrefix = ‘https://Narsaiahs-win7:8443/icp-cas-server’
    grails.plugins.springsecurity.cas.proxyCallbackUrl = ‘http://localhost:8080/appone/secure/receptor’
    grails.plugins.springsecurity.cas.proxyReceptorUrl = ‘/secure/receptor’
    grails.plugins.springsecurity.logout.afterLogoutUrl = ‘https://Narsaiahs-win7:8443/icp-cas-server/logout?url=http://localhost:8080/appone/’

    Step-5: Run the application by the following command
    D:\appone>grails run-app

    It added the plugins successfully.

    Step-6: Create the Domain classes by using the following command

    D:\appone>grails s2-quickstart codeisdesign.example.sso.security User Role

    Step-7: Add Hibernate, tomcat plugins in application.properties file as shown below

    plugins.hibernate=2.0.4
    plugins.tomcat=2.0.4

    Step-7: Add the following code to BootStrop.groovy file. We also need same users to exist in the application which were in the authentication_database.txt. That is done in Bootstrap.groovy.

    import codeisdesign.example.sso.security.User;

    class BootStrap {

    def init = { servletContext ->
    new User(
    username:”admin”,
    password:”admin”,
    enabled:true,
    accountExpired:false,
    accountLocked:false,
    passwordExpired:false
    ).save(flush:true)
    }
    def destroy = {
    }
    }

    Step-8: Created a protected page by following command

    D:\appone>grails create-controller codeisdesign.example.sso.security.home

    class HomeController {

    def index() { render “Protected Page”}
    }

    Step-9: Run the application through the following command

    D:\appone>grails run-app

    Step-10: Navigated to Secure page

    http://localhost:8080/appone/home
    It successfully redirected to CAS when I requested to Protected/secure page and successfully authenticated with CAS but after authenticating it is redirecting me to the Spring Security Authentication Login page(http://localhost:8080/appone/login/auth?login_error=1) instead of rendering my requested page(http://localhost:8080/appone/home).

    Thanks,
    Baji Shaik

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.