2010-04-08

Securing Grails with Spring Security, Part 1


What?

In part one of this series I want to show how easy it is to secure your Grails apps with a current version of Spring Security. It deals with the now current version of Grails (1.2.2) and Spring Security (3.0.2).

Why?

Grails as well as Spring are highly agile environments. Sometimes so agile that it is difficult to find plugins for current versions.
Although there are several approaches to securing Grails apps using plugins I wanted to stick to Spring Security. I have been very happy with it since the ancient days when it was called Acegi Security.
Unfortunatelly the plugins available either use a very different approach (eg Stark Security) or provide rather old versions of Spring Security (eg Spring Security Plugin 0.5.2 which uses Spring Security 2.0.4 under the hood).
This posting should show you how easy it is to expand Grails functionality if you cannot or don't want to use plugins.
This first installment slightly updates Mattias Hellborg Arthursson's posting Spring Security For Real with Grails.

How?

As it turns out it is quite easy to integrate Spring Security in Grails. I'm going to show you how in some easy to follow steps.

1. Download

Get Grails 1.2.2 and Spring Security 3.0.2 from the corresponding website, install Grails and unpack Spring Security to a location of your liking.

2. Create a Grails project and test it

lugaru> grails create-app GSecurity
Welcome to Grails 1.2.2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grails

Base Directory: /home/lugaru
Resolving dependencies...
[...]
Created Grails Application at /home/lugaru/GSecurity
Now you can test it with
cd GSecurity
grails run-app
and browse to http://localhost:8080/GSecurity.

3. Install the web.xml template

Spring Security is based on an HTTP filter. These are normally configured in the web.xml, which we don't have in our Grails project, yet.
grails install-templates
creates some files and directories under src/templates. We only need src/templates/war/web.xml. You can safely delete src/templates/artifacts and src/templates/scaffolding.

Now edit src/templates/war/web.xml and add this after the last filter definition
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
and
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
after the last filter mapping. (Question: Is there a more grails-ish way?)

4. Install the libraries

Copy spring-security-config-3.0.2.RELEASE.jar, spring-security-core-3.0.2.RELEASE.jar and spring-security-web-3.0.2.RELEASE.jar from Spring Security to your Grails lib directory.

5. Configure the security filter

There are two ways to configure the security filter. Either you can declare your Spring beans in grails-app/conf/spring/resources.groovy or in grails-app/conf/spring/resources.xml (which you have to create first).
The following snipped uses the later option. It will password protect your whole application using basic authentication (the infamous password box). You can log in using one of the four users (user1, user2, user3, admin) with their corresponding password. We do not use their authorities/roles yet, but I'll need them in one of the later parts of this series.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    <http auto-config="true" use-expressions="true">
        <http-basic/>
        <intercept-url pattern="/**" access="isAuthenticated()" />
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_ADMIN"/>
                <user name="user1" password="user1" authorities="ROLE_GROUP1"/>
                <user name="user2" password="user2" authorities="ROLE_GROUP1,ROLE_GROUP2"/>
                <user name="user3" password="user3" authorities=""/>
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>
As you can see this is a standard Spring Security configuration.
Congratulations! You have done it.

But wait! This is not production ready at all. I have all my users and roles in an LDAP server. Can I use that, too?
Certainly!
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
             http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    <http auto-config="true" use-expressions="true">
        <http-basic/>
        <intercept-url pattern="/**" access="isAuthenticated()" />
    </http>

    <ldap-server url="ldap://localhost:389/dc=acme,dc=com" />
    <authentication-manager alias="authenticationManager">
        <ldap-authentication-provider user-search-base="ou=users"
                                      user-search-filter="(cn={0})"
                                      group-search-base="ou=groups"
                                      group-search-filter="(uniqueMember={0})"/>
    </authentication-manager>
</beans:beans>

Update: You'll also need to copy spring-ldap-1.3.0.RELEASE-all.jar and spring-security-ldap-3.0.2.RELEASE.jar to Grails lib directory.
The security namespace of Spring Security is very concise, this is the reason why I did not create the beans in resources.groovy. (Although I have to admit that I'm pretty new to Groovy and Grails and might have missed something which would have made it even more concise.)

What's next

From this point on it is almost trivial to expand the configuration to use remember-me, form-based authentication, session hijacking-protection and all the other fine things Spring Security has to offer. I strongly recommend to read the great documentation which comes with Spring Security.

In the next part of this series we will create a tag library which will allow you to show and hide information depending on user roles.

Disclaimer

This post would not have been possible without Mattias Hellborg Arthursson's Spring Security For Real with Grails which demonstrated that at least it is do-able.
I'm in no way an experienced Groovy or Grails developer. So all errors are mine.
The same goes for every funny phrase or wrong spelling. English is not my mother's tongue. I'm sure you've noticed that already. ;-)

9 comments:

Anonymous said...

Excellent post - thanks alot for showing how it's done.

Anonymous said...

thank you for this posting, this is a good starting point for securing a grails app. waiting for part 2 - how can i identify a user in my app?

Anonymous said...

great post, waiting for the rest in the series

Anonymous said...

Great how-to. Would love to see the next installment in the series!

Jeff Schmidt said...

Thanks to you and Mattias for pointing me in the right direction. I'm new to Grails, but I've using Spring Security in Java apps.

Anonymous said...

Hi,

I am following your posts about spring security in grails and loving them. However, I don't know if it is an error, but I have had problems with the configuration you provided.

I tried to create a taglib like you suggest in you next post, but kept getting null in the authentication object, suggesting not logged in even though I was logged in. The problem was the orders of the filters in web.xml. Apparently the sitemesh filter has to be AFTER the security filter, for everything to work.

Just so you know.

// Andréas

Dunand said...

I'm a little bit late on this one but you make my day.

thanks

Anonymous said...

awesome post.. You do not know how many times I am referring this post while implementing spring ldap security with grails.

BSK said...

Excellent!

Could you please describe me how to configure the Grails with CAS.

I configured the CAS and its working fine but now I want to configure my grails application with CAS by using the Spring-Security-CAS plugin but HOW?

Could you please describe me step by step how to implement this?

Regards,
BSK