Grails application with Spring Security and MongoDB


After we have fun with previous post Beginning Grails 2.0 with MongoDB , now it’s time to move on to create secure Grails application using spring security core to work with MongoDB.
Pre-requisites
– Grails 2.0.3
– MongoDB 2.0.6

1. Create new app and install mongodb plugin and remove hibernate

grails create-app example
grails install-plugin mongodb
grails uninstall-plugin hibernate
plugins {

//runtime ":hibernate:$grailsVersion"
 runtime ":jquery:1.7.1"
 runtime ":resources:1.1.6"

build ":tomcat:$grailsVersion"
 }

2. Edit configuration file in conf as you need
3. Install spring security core plugin and run the “s2-quickstart” script to initialize Spring Security and create your domain classes

grails s2-quickstart com.example User Role

4. Edit User domain class to look like this

package com.example
import org.bson.types.ObjectId

class User {
ObjectId id
def springSecurityService
String username
String password
String email
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set authorities

static transients = ["springSecurityService"]
static embedded = ['authorities']
static constraints = {
username blank: false, unique: true,size: 2..32,matches: "[a-zA-Z0-9_]+"
email blank: false, unique:true,email:true
password blank: false,size:6..64
}

static mapping = {
password column: '`password`'
}

def beforeInsert() {
encodePassword()
}

def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}

protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}

5. create MongoUserDetailService.groovy at /example/grails-app/services/ and add following code

import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.apache.log4j.Logger
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserDetailsService
import com.example.User
import com.example.UserRole

class MongoUserDetailsService implements GrailsUserDetailsService {

 private Logger log = Logger.getLogger(getClass())

 /**
 * Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least one role, so
 * we give a user with no granted roles this one which gets past that restriction but
 * doesn't grant anything.
 */
 static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]

 @Override
 UserDetails loadUserByUsername(String username, boolean loadRoles) {
 if(log.debugEnabled) {
 log.debug("Attempted user logon: $username")
 }
 User.withTransaction { status ->
 def user = User.findByUsername(username)

 if (!user) {
 log.warn("User not found: $username")
 throw new UsernameNotFoundException('User not found', username)
 }

 if(log.debugEnabled) {
 log.debug("User found: $username")
 }

 def roles = NO_ROLES
 if (loadRoles) {
 def authorities = user.authorities?.collect {new GrantedAuthorityImpl(it.authority)}
 if(authorities) {
 roles = authorities
 }
 }

 if(log.debugEnabled) {
 log.debug("User roles: $roles")
 }

 return createUserDetails(user, roles)
 }
 }

 @Override
 UserDetails loadUserByUsername(String username) {
 return loadUserByUsername(username, true)
 }

 protected UserDetails createUserDetails(user, Collection authorities) {
 new GrailsUser(user.username, user.password, user.enabled,
 !user.accountExpired, !user.passwordExpired,
 !user.accountLocked, authorities, user.id)
 }
}

6. Edit /example/grails-app/conf/spring/resource.groovy file to look like this

// Place your Spring DSL code here
beans = {
 userDetailsService(MongoUserDetailsService)
}

7. Edit BootStrap.groovy to create new Role and new User for testing

import com.example.Role
import com.example.User
class BootStrap {

def init = { servletContext ->
 def userRole = new Role(authority:"ROLE_USER").save(flush:true)
 def user = new User()
 user.username = "example"
 user.password = "password"
 user.email = "example@email.com"
 user.enabled = true
 user.accountExpired = false
 user.accountLocked = false
 user.passwordExpired = false
 user.authorities = [userRole]
 user.save(flush:true)

 }
 def destroy = { }
}

8. Add following tag to index.gsp


<sec:ifLoggedIn>
Welcome Back!
</sec:ifLoggedIn>

<sec:ifNotLoggedIn>
<g:link controller='login' action='auth'>Login</g:link>
</sec:ifNotLoggedIn>

9. Hooray! grails run-app to try our example application

Fork this project on github https://github.com/etcpe9/example.git
References
Spring security core plugin document
Gorm for Mongo document

Advertisement

7 thoughts on “Grails application with Spring Security and MongoDB

  1. David Castro

    I’m working through this tutorial and am about to give it a run now that all the code is in. Before I do, I wanted to point out that you lost some code in your step 8 code block. It lost the sec:ifLoggedIn and sec:ifNotLoggedIn opening and closing tags..

    Reply
  2. David Castro

    After a bit of work, I got the thing to work. I had used a nonstandard name for User, which caused some problems in the MongoUserDetailsService. Once I replaced “User” with “SpringUser,” everything works great. Thank you for putting this together. I looked for a similar tutorial about a year ago and didn’t find anything. I thought I was going to have to go with dual datasources just to use Spring Security! :-O

    Reply
  3. Abhishek Mishra

    Great Article. In Step 5, You are asking to create the service as MongoUserDetailService.groovy whereas the name of the class in code is MongoUserDetailsService i.e. there is an additional “s” in Detail. I had to struggle a bit to make it work. Thanks for this great post

    Reply
  4. Pingback: An Army of Solipsists » Blog Archive » Using MongoDB With Version 2.x of the Grails Spring Security Core Plugin

  5. Pingback: Spring Security Core and mongoDB Doesn't Authenticate - MongoDB Solutions - Developers Q & A

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s