Archive

Archive for July, 2012

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

Basic MVC project using Spring Security

July 2, 2012 2 comments

Spring Security is a framework that provides authentication and access control on a project. We will set up a project with some basic authentication using Spring Security. In one of my later blogs we will see how to use a user service and get the credential information from a database.

CREATING A BASIC SPRING MVC PROJECT
Get SpringSource tool suite from here. (For reference: I have used STS Version 2.9.2.RELEASE and Maven 3.0.3 for this project).
We will now create a basic Spring MVC project.
Select File>New>Spring Template Project and choose Spring MVC Project from the list. Click yes on the download prompt.
We will name the project as SpringSecurity and the package as com.wordpress.codesilo.

RUNNING THE TEMPLATE ON THE SERVER
Right Click on the created project, Select Run As>Run On Server. Click on “Manually Define a new Server” radio button and search for Tomcat (I have Tomcat already installed on my machine). Select the version of Tomcat server (7.0 in my case)you want to use and click next.
Select the Tomcat Installation Directory and the installed JRE/JDK. Once you click “Finish” the server should start and you should get a Hello World page with the current time on the workspace.

BASIC SPRING SECURITY
We will create a blank security-app-context.xml file under WEB-INF/spring/ and add the following configuration on the file

<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.1.xsd">

<http use-expressions="true">
 <intercept-url pattern="/**" access="isAuthenticated()" />
 <http-basic/>
 </http>

<authentication-manager>
 <authentication-provider>
 <user-service>
 <user name="rod" password="koala" authorities="supervisor, teller, user" />
 <user name="dianne" password="emu" authorities="teller, user" />
 <user name="scott" password="wombat" authorities="user" />
 <user name="peter" password="opal" authorities="user" />
 </user-service>
 </authentication-provider>
 </authentication-manager>
</beans:beans>

Add the following to web.xml

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Add the security-app-context.xml to the configLocation in web.xml

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

Add the following on the dependencies on pom.xml

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

Now when we bring up the server, the following prompt will be presented. If we use one of the username, password combinations in the security context file, we should be able to get to the Hello World page

FORM-BASED LOGIN
We will now change the authentication to use a default form provided by Spring. Change the following section in security-app-context.xml

<http use-expressions="true">
 <intercept-url pattern="/**" access="isAuthenticated()" />
 <http-basic/>
</http>

to

<http use-expressions="true">
 <intercept-url pattern="/**" access="isAuthenticated()" />
 <form-login/>
 <logout/>
</http>

If we go to the application url now (http://localhost:8080/SpringSecurity/) we will be redirected to a login page as follows..

We can get to the Hello World page by providing the credentials.
To logout we use the following url http://localhost:8080/SpringSecurity/j_spring_security_logout

CUSTOMIZING LOGIN FORM
Change the <form-login/> in security-app-context.xml to

<form-login
 login-page="/login.jsp"
 always-use-default-target="true"/>

We will now add login.jsp to the webapp folder in the project. The following is the content of login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>Login</title>
</head>
<body>
 <form action="j_spring_security_check" method="POST">
 <label for="username">User Name:</label>
 <input id="username" name="j_username" type="text" />
 <label for="password">Password:</label>
 <input id="password" name="j_password" type="password" />
 <input type="submit" value="Log In" />
 </form>
</body>
</html>

We will also change the security-app-context.xml to allow access to the login.jsp page

<intercept-url pattern="/login.jsp" access="permitAll" />

If this is not done, we will get too many redirects error

Also, add the logout url on the home.jsp page at the end of the page

<a href="<c:url value="/j_spring_security_logout"/>">Logout</a>

Now, once we go to our application, we will see the custom login page that we created. Also, we will be able to logout by using the logout url provided on the home page.

ADDING SECURITY EXCEPTION HANDLING
Add the following just above the form on login.jsp

<c:if test="${not empty param.login_error}">
 <font color="#ff0000">
 Login unsuccessful.<br/>
 <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.
 </font>
</c:if>

and change the form-login element to the following..

<form-login
 login-page="/login.jsp"
 authentication-failure-url="/login.jsp?login_error=1"
 always-use-default-target="true"
 />

If we bring up the server and provide incorrect credentials, we will see the following error

References:
SpringSource Documentation

Technorati Tags: , , , , ,

Categories: Java, Spring