Archive

Archive for the ‘DATADOC’ Category

Hashing passwords in Spring Security

July 8, 2012 1 comment

Passwords should not be stored in clear text. It is a best practice to have a one way hash created before storing it. Spring Security provides a very easy way to accomplish this. Just add a passwordEncoder to the authentication-provider in the spring security configuration.
An easy way to this in Spring 3 and later is to have the following config. This uses a SHA-256 algorithm and the username is used to salt the hash.

<authentication-manager>
 <authentication-provider user-service-ref="customUserDetailsService">
 <password-encoder hash="sha-256">
 <salt-source user-property="username"/>
 </password-encoder>
 </authentication-provider>
 </authentication-manager>

In order to use hashed passwords, it becomes necessary that we store them hashed too. In order to this in the application, we can have the SignUp class hash the passwords before storing it in the datasource. (in our case MongoDB).
Here is an excerpt from my class …

@RequestMapping(value = "/signUp", method = RequestMethod.POST)
 public String home(Locale locale, Model model, @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName) {
 MongoOperations mongoOperation = (MongoOperations)mongoTemplate;
 User user = new User(username, passwordEncoder.encodePassword(password, username), firstName, lastName);
 user.setRole(2);

 logger.debug(user.toString());
 mongoOperation.save(user, "user");
 logger.debug("Adding the user to the database");
 model.addAttribute("user", user );
 return "signUpSuccessful";
 }

The following bean is used in the mongo-config.xml class to support the signUp process.

<bean id="passwordEncoder"
 class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
 <constructor-arg value="256"/>
</bean>

Spring security provides one iteration of the hash by default. In order to provide Key Stretching we can provide more iterations by using the following config instead.

<bean id="passwordEncoder"
 class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
 <constructor-arg value="256"/>
 <property name="iterations" value="1000"/>
 </bean>

The authentication-manager in the security config file can be used to reference the same bean so that the same number of iterations are performed at authentication.

<authentication-manager>
 <authentication-provider user-service-ref="customUserDetailsService">
 <password-encoder ref="passwordEncoder">
 <salt-source user-property="username"/>
 </password-encoder>
 </authentication-provider>
 </authentication-manager>

References:
Spring Source Doc

Advertisements

MongoDB Spring Data and Spring Security with custom UserDetailsService

July 8, 2012 12 comments

In a earlier write up we saw how we can setup basic spring security. In this one we will see how to make a custom UserDetailsService instead of using the credentials in the configuration file. We will use MongoDB as a datasource.

We will use the project from the Spring Security project we created earlier and add the MongoDB config details and user service to provide the capability. See my previous blog for setting up MongoDB Spring Data.

Add the following to the mongo-config.xml file in the location WEB-INF/mongo/

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mongo="http://www.springframework.org/schema/data/mongo"
 xsi:schemaLocation="http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.1.xsd
 http://www.springframework.org/schema/data/mongo
 http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

 <!-- Default bean name is 'mongo' -->
 <mongo:mongo host="localhost" port="27017" />

 <bean id="mongoTemplate"
 class="org.springframework.data.mongodb.core.MongoTemplate">
 <constructor-arg ref="mongo" />
 <constructor-arg name="databaseName" value="codesilo" />

 </bean>

 <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
 <context:annotation-config />

</beans>

Add the Spring Data dependencies in the pom.xml file

<dependency>
 <groupId>org.mongodb</groupId>
 <artifactId>mongo-java-driver</artifactId>
 <version>2.7.2</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
 <version>1.1.0.M1</version>
 </dependency>
 <dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>2.2</version>
 </dependency>

Add the mongo-config.xml file to the contextConfigLocation on web.xml. The context param will look like this

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/spring/root-context.xml
 /WEB-INF/spring/security-app-context.xml
 /WEB-INF/mongo/mongo-config.xml
 </param-value>
 </context-param>

We will now create a CustomUserDetailsService class that implements UserDetailsService. We will add the implementation of loadUserByUsername method. The CustomUserDetailsService is as follows. The getUserDetail method queries to get the user object from MongoDB (it is assumed that the data is already there).

package com.wordpress.codesilo.model;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class CustomUserDetailsService implements UserDetailsService {

private MongoTemplate mongoTemplate;

 public UserDetails loadUserByUsername(String username)
 throws UsernameNotFoundException {
 User user = getUserDetail(username);
 System.out.println(username);
 org.springframework.security.core.userdetails.User userDetail = new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),true,true,true,true,getAuthorities(user.getRole()));
 return userDetail;
 }

@Autowired
 public void setMongoTemplate(MongoTemplate mongoTemplate) {
 this.mongoTemplate = mongoTemplate;
 }

 public List<GrantedAuthority> getAuthorities(Integer role) {
 List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
 if (role.intValue() == 1) {
 authList.add(new SimpleGrantedAuthority("ROLE_USER"));
 authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
 } else if (role.intValue() == 2) {
 authList.add(new SimpleGrantedAuthority("ROLE_USER"));
 }
 return authList;
 }

 public User getUserDetail(String username){
 MongoOperations mongoOperation = (MongoOperations)mongoTemplate;
 User user = mongoOperation.findOne(
 new Query(Criteria.where("username").is(username)),
 User.class);
 System.out.println(user.toString());
 return user;
 }

}

We will also create a user POJO which is as follows.

package com.wordpress.codesilo.model;

public class User {

public String username;
 public String password;
 public String firstName;
 public String lastName;
 public String email;
 public int role;

public User() {
 }

public int getRole() {
 return role;
 }

public void setRole(int role) {
 this.role = role;
 }

public User(String username, String password, String firstName,
 String lastName) {
 this.username = username;
 this.password = password;
 this.firstName = firstName;
 this.lastName = lastName;
 }

public String getUsername() {
 return username;
 }

public void setUsername(String username) {
 this.username = username;
 }

public String getPassword() {
 return password;
 }

public void setPassword(String password) {
 this.password = password;
 }

public String getFirstName() {
 return firstName;
 }

public void setFirstName(String firstName) {
 this.firstName = firstName;
 }

public String getLastName() {
 return lastName;
 }

public void setLastName(String lastName) {
 this.lastName = lastName;
 }

public String getEmail() {
 return email;
 }

public void setEmail(String email) {
 this.email = email;
 }

@Override
 public String toString(){
 return "First Name:" + this.firstName + " Last Name:" + this.lastName + " Username:" + this.username ;
 }

}

As a last step we will change the security-app-context.xml to have the customUserDetailsService bean and user-service-ref in the authentication provider.

<beans:bean id="customUserDetailsService" class="com.wordpress.codesilo.model.CustomUserDetailsService"/>

 <authentication-manager>
 <authentication-provider user-service-ref="customUserDetailsService"/>
 </authentication-manager>

Now when we try to login to the application it will use the MongoDB to get the credentials.

We can also use the Security Context to get the principal and display the username and roles on home.jsp.
Add this to the pom dependencies.

<dependency>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-taglibs</artifactId>
 <version>${org.springframework-version}</version>
 </dependency>

Add the following taglib to the home.jsp page

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

and the following content on the jsp page to display the data.

<sec:authorize access="isAuthenticated()">
 Username: <sec:authentication property="principal.username" />
 Role: <sec:authentication property="principal.authorities"/>
 </sec:authorize>

Setting up a project with Spring Data and MongoDB

July 2, 2012 4 comments

From springsource : “The goal of the Spring Data Document (or DATADOC) framework is to provide an extension to the Spring programming model that supports writing applications that use Document databases”.
This blog will cover on how to use Spring Data with MongoDB. We will start with creating a simple Spring MVC application. See my previous blog to see how to setup a basic Spring MVC app using STS.

We will first add the dependencies on the pom file of the project.

<!-- Spring Data Mongo Driver -->

 <dependency>
 <groupId>org.mongodb</groupId>
 <artifactId>mongo-java-driver</artifactId>
 <version>2.7.2</version>
 </dependency>

 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
 <version>1.1.0.M1</version>
 </dependency>
 <dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>2.2</version>
 </dependency>

We will also need to add the Spring Milestone repo to the pom

<repositories>
 <repository>
 <id>spring-milestone</id>
 <name>Spring Maven MILESTONE Repository</name>
 <url>http://maven.springframework.org/milestone</url>
 </repository>
</repositories>

CONFIGURING MONGO TEMPLATE USING SPRING XML
We will now create a mongo-config.xml in the WEB-INF directory of the project. Add this as the content of the xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mongo="http://www.springframework.org/schema/data/mongo"
 xsi:schemaLocation="http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.1.xsd
 http://www.springframework.org/schema/data/mongo
 http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

 <!-- Default bean name is 'mongo' -->
 <mongo:mongo host="localhost" port="27017" />

 <bean id="mongoTemplate"
 class="org.springframework.data.mongodb.core.MongoTemplate">
 <constructor-arg ref="mongo" />
 <constructor-arg name="databaseName" value="codesilo" />

 </bean>

 <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
 <context:annotation-config />

</beans>

Add this to the web.xml configLocation

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/spring/root-context.xml
 /WEB-INF/mongo-config.xml
 </param-value>
 </context-param>

We will keep things simple. Create a user model and refactor the homeController class to use that model. The HomeController class will create a User object, insert it in the database, query and return the first result to the view.
The following is the model User class.

public class User {

 public String username;
 public String password;
 public String firstName;
 public String lastName;

 public User(){

 }

 public User(String username, String password, String firstName, String lastName){
 this.username = username;
 this.password = password;
 this.firstName = firstName;
 this.lastName = lastName;
 }

 public String getUsername() {
 return username;
 }
 public void setUsername(String username) {
 this.username = username;
 }
 public String getPassword() {
 return password;
 }
 public void setPassword(String password) {
 this.password = password;
 }
 public String getFirstName() {
 return firstName;
 }
 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }
 public String getLastName() {
 return lastName;
 }
 public void setLastName(String lastName) {
 this.lastName = lastName;
 }

 @Override
 public String toString(){
 return "User [username=" + username + ", passowrd= ****" + ", firstName=" + firstName + "lastName" + lastName + "]";
 }
}

Change the HomeController class to look like the following

@Controller
public class HomeController {

 @Autowired
 private MongoTemplate mongoTemplate;

 private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

 /**
 * Simply selects the home view to render by returning its name.
 */
 @RequestMapping(value = "/", method = RequestMethod.GET)
 public String home(Locale locale, Model model) {

 logger.info("Welcome home! the client locale is "+ locale.toString());

 MongoOperations mongoOperation = (MongoOperations)mongoTemplate;
 User user = new User("codesilo", "Password", "Code", "Silo");
 mongoOperation.save(user);
 List<User> users = mongoOperation.find(
 new Query(Criteria.where("username").is("codesilo")),
 User.class);

 model.addAttribute("user", users.get(0).toString());

 return "home";
 }

}

Change the body of home.jsp to the following

<body>
<h1>
 Hello world!
</h1>

<P> Getting user from MongoDB: ${user} </P>
</body>

Now when we go to the application, we will see the following

and when we use the mongo shell to query the database, we get..

> db.user.find();
{ "_id" : ObjectId("4fef96227e27ff2b7a81331f"), "_class" : "com.wordpress.codesilo.model.User", "username" : "codesilo", "password" : "Password", "firstName" :
"Code", "lastName" : "Silo" }

References:
MongoTemplate- SpringSource Documentation