Friday, June 18, 2010

Using Spring-Security Database in Spring-Roo

Spring Roo is an excellent rapid development tool for Spring Framework based applications.
The current Spring Roo (1.1.0.M1) Security support is very basic and does not support databases out-of-the-box.
To integrate Spring Security with a database backed user and authorization storage, you currently need to set it up yourself.

For this to work, it is required that you already configured your persistence layer in Roo.

Step1: Add the Entities for Spring-Security
Note that in my approach, I avoid reserved SQL keywords for tables and columns.
Roo statements:

// domain.Roles (Spring Security Authorities)
entity --class ~.domain.Roles --testAutomatically
field string --fieldName nameDa --notNull --sizeMax 50 --class ~.domain.Roles

// domain.Users
entity --class ~.domain.Users --testAutomatically
field string --fieldName usernameDa --notNull --sizeMin 3 --sizeMax 30
field string --fieldName passwordDa --sizeMax 100
field boolean --fieldName enabledDa --notNull true
field set --fieldName roles --type ~.domain.Roles --cardinality MANY_TO_MANY --class ~.domain.Users

Step2: Create Web Tier Controllers (to manage roles and users)
controller scaffold --entity ~.domain.Users --class ~.web.UsersController
controller scaffold --entity ~.domain.Roles --class ~.web.RolesController

Step3: Setup security in Roo
Within the roo shell, type "security setup". This creates the security config file and adds needed dependencies to the main pom.xml file.

Step4: Configure Spring Security
File: applicationContext-security
Replace the authentication-manager with a dao based one.
Note the queries to check the user and to get the Authorities which reflects the non-standard table and column names:

<!-- Configure Authentication mechanism -->
<authentication-manager alias="authenticationManager">
<!-- DAO Based Security -->
<authentication-provider>
<password-encoder hash="md5"/>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT U.username_da AS username, U.password_da as password, U.enabled_da as enabled FROM users U where U.username_da=?"
authorities-by-username-query="SELECT U.username_da as username, A.name_da as authority FROM users U left join users_roles UA on U.id=UA.users left join roles A on UA.roles = A.id WHERE U.username_da=?" />
</authentication-provider>
</authentication-manager>

<!-- Security event logging -->
<beans:bean id="loggerListener"
class="org.springframework.security.authentication.event.LoggerListener" />


Step5: Initial Users and Roles
I recommend to start the application now, create your needed roles (e.g. "ROLE_ADMIN", "ROLE_SUPERVISOR") and at least an admin user with ROLE_ADMIN and ROLE_SUPERVISOR assigned. Afterwards secure the roles and users resources in the applicationContext-security.xml (so that only admins can access these controllers):

<intercept-url pattern="/users**" access="hasRole('ROLE_ADMIN')"/>

<intercept-url pattern="/roles**" access="hasRole('ROLE_ADMIN')"/>