best grammar app

Grails MongoDB Spring Security Getting Started

Submitted by Abhishek on Tue, 2013-09-17 17:38
mongodb.org/grails.org

I ran into issues getting my grails project setup for use with MongoDB and Spring Security for a Rules and BPM project - NumaHub. There are few articles (like this one from ET) which talk about it, and helped me get started with the exercise (as well as the article). But I kept on running into issues again and again. Finally I was able to get that up and running. I am sharing what I did and hope it is helpful for everyone.

For this article, I am using Spring Source Tools Suite. However, it should work well with command line Grails as well. If you are running from command line, do add “grails” before each issued command.

Step 1: Create a New Project

To create a new project, I started with

File -> New -> Grails Project

image

Added the name – NumaHub and hit 'Finish'.

Step 2: Install Plugin MongoDb

Then I installed MongoDB plugin:

install-plugin mongodb

A confirmation(see the screenshot below) was displayed, after the successful installation:

Loading Grails 2.2.3
| Environment set to development.....
| Warning The install-plugin command is deprecated and may be removed from a future
version of Grails.Plugin dependencies should be expressed in 
grails-app/conf/BuildConfig.groovy.
See http://grails.org/doc/2.2.x/guide/conf.html#pluginDependencies.
| Resolving plugin mongodb. Please wait...
| Installing zip mongodb-1.3.0.zip.....
| Installed plugin mongodb-1.3.0.....
| Plugin installed.

Step 3: Uninstall Plugin Hibernate

As I wanted to use only MongoDb, I got rid of Hibernate using the command given below:

uninstall-plugin hibernate

A confirmation was displayed:

Loading Grails 2.2.3
| Environment set to development.....
| Uninstalled plugin [hibernate]

Also, to remove it from your BuildConfig.groovy, I commented the line below the plugins:

        // runtime":hibernate:$grailsVersion"

Step 4: Install Plugin Spring Security Core

To install Spring Security, issue the command as given below:

install-plugin spring-security-core

Step 5: Run the QuickStart Command

I ran the s2-quickstart command to setup my Users and Roles:

s2-quickstart com.numahub User Role

This created the User and Role classes that I needed.

Step 6: Configure the User, Role and UserRole class

The Classes needed some changes, especially around how MongoDB handles Identities. Grails automatically assigns identities which are integer values, however a normal insert in MongoDB creates it as a BSON Object.

To make it work, I added object id into all out classes:

ObjectId id

Here are the three classes I created:

packagecom.numahub

importorg.bson.types.ObjectId;

class Role {
	ObjectIdid
	String authority

	staticmapping = {
		cachetrue
	}

	staticconstraints = {
		authority blank: false, unique: true
	}
}
packagecom.numahub

importorg.apache.commons.lang.builder.HashCodeBuilder
importorg.bson.types.ObjectId;

classUserRole implements Serializable {
	ObjectId id
	User user
…..

For the User class, I added a few more fields – Email, FirstName and LastName.

packagecom.numahub

importorg.bson.types.ObjectId;

class User {
	ObjectIdid
	transientspringSecurityService

	String username
	String password
	String firstName
	String lastName
	String email
	booleanenabled
	booleanaccountExpired
	booleanaccountLocked
	booleanpasswordExpired

	staticconstraints = {
		username blank: false, unique: true,size: 2..32,matches: "[a-zA-Z0-9_]+"	
		firstNameblank:false, size: 1..128
		lastNameblank:false, size: 1..128
		emailblank:false, size: 1..128, email: true
		password blank: false
	}

	staticmapping = {
		passwordcolumn: '`password`'
	}

	SetgetAuthorities() {
		UserRole.findAllByUser(this).collect { it.role } as Set
	}

	defbeforeInsert() {
		encodePassword()
	}

	defbeforeUpdate() {
		if (isDirty('password')) {
			encodePassword()
		}
	}

	protectedvoidencodePassword() {
		password = springSecurityService.encodePassword(password)
	}
}

Step 7: Override User Details Service

Now, I had to override the User Details Service. For this I created a new service called MongoUserDetailsService:

create-service com.numahub.MongoUserDetailsService

The contents looked like this:

packagecom.numahub

importorg.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
importorg.springframework.security.core.GrantedAuthority
importorg.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
importcom.numahub.User
importcom.numahub.UserRole

classMongoUserDetailsServiceimplementsGrailsUserDetailsService {

	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.
 */
	staticfinal List NO_ROLES = [
		newGrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)
	]

	@Override
	UserDetailsloadUserByUsername(String username, booleanloadRoles) {
		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")
				thrownewUsernameNotFoundException('User not found', 
username)
			}

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

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

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

			returncreateUserDetails(user, roles)
		}
	}

	@Override
	UserDetailsloadUserByUsername(String username) {
		returnloadUserByUsername(username, true)
	}

	protectedUserDetailscreateUserDetails(user, Collection authorities) {
		newGrailsUser(user.username, user.password, user.enabled,
				!user.accountExpired, !user.passwordExpired,
				!user.accountLocked, authorities, user.id)
	}
}

Step 8: Specify the Service

To make the service available, I added it into conf> spring >resources.groovy file

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

Step 9: Add a Default Role and User

To test the application I added a Default User and Role. Below is the code I added in the BootStrap.groovy:

classBootStrap {

definit = { servletContext ->
		defuserRole = newcom.numahub.Role(authority:"ROLE_USER").save(flush:true)
		def user = newcom.numahub.User()
		user.username = "abhishek"
		user.password = "password"
		user.email = "contact@constonline.com"
		user.firstName= "Abhishek"
		user.lastName="Mishra"
		user.enabled = true
		user.accountExpired = false
		user.accountLocked = false
		user.passwordExpired = false
		user.validate();
user.save(flush:true)
		newcom.numahub.UserRole(user: user, role: userRole).save(flush: true, 
insert: true);
		
		
    }
defdestroy = {
    }
}

Step 10: Add a Handler in index.jsp

To see if the Login functionality is working, I added the code below in index.gsp page:


You are now Logged in as

	
Login Here
	

Step 11: Start Mongo Server

Then I started the Mongo Server on my machine. You can find the instructions on the MongoDb site for the same.

Step 12: Launch the App

And then I launched the App:

Configuring Spring Security Core ...
... finished configuring Spring Security Core
| Server running. Browse to http://localhost:8080/NumaHub

Verifying The Details

http://localhost:8080/NumaHub

image

Clicked on 'Login here', entered username and password as specified in the BootStrap.groovy:

image

And saw a message like this:

image

Using a Utility that lets you see the Database, you can verify the how it gets saved.

The following Collections were created

image

The contents of the collections were:

The Role

{
  "_id": { "$oid" : "5235aebdc2e6b9cd860aa951" },
  "authority": "ROLE_USER",
  "version": 0
}

The User

{
  "_id": { "$oid" : "5235aec4c2e6b9cd860aa953" },
  "accountExpired": false,
  "accountLocked": false,
  "email": "contact@constonline.com",
  "enabled": true,
  "firstName": "Abhishek",
  "lastName": "Mishra",
  "password": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
  "passwordExpired": false,
  "username": "abhishek",
  "version": 0
}

And the User Role

{
  "_id": { "$oid" : "5235b0e3c2e6b107f99c44a0" },
  "role": { "$oid" : "5235b0e1c2e6b107f99c449e" },
  "user": { "$oid" : "5235b0e3c2e6b107f99c449f" }
}

Hope this is helpful for anyone getting started. Questions are suggestions are welcome. If you would like to see more articles on Grails, do let me know.


Abhishek Mishra
Good experience in working with BPM technologies like Savvion, JBPM. Founder and Chief Editor of BPMGeek.com. Founder of Savvion Business Manager Mobility Framework Savmobify| View my BPMGeek Profile
|
best grammar app

About BPMGeek

BPMGeek is an initiative to collaborate and communicate with the growing Business process management community out there. The goal is to help developers connect with experts, ask questions, post their learning and get understanding of BPM Concepts. Often tool specific knowledge of niche areas end up developers perplexed and confused - especially when there are very less number of resources available. We will be coming up several several new features. Have a look at our Roadmap here

BPMGeek is an independent entity not associated with any Product. All BPM product professionals are invited to contribute. The Logos and Names used across the site belong to their respective owners. The viewpoints mentioned by Individual contributors are their own. BPMgeek cannot be held liable for any issues arising out of it.


BPMgeek is promoting the Nounshoun English Grammar App - developed by Constellation Software.