How to configure Spring Security using Hibernate with Spring MVC

April 1, 2014

Java is almost always giving me a bit of a hard time. I run into problems every now and then, so I start looking for answers on Google. Coming from PHP I am used to finding the answers within one query on your favorite search engine. However, with Java this is almost never the case.

I always have to view at least the first ten results to forge the answer to the problem I am having. This was also the case with configuring Spring MVC, Spring Security and Hibernate. And when you’ve figured it out, it’s quite simple actually.

First of, if you haven’t yet, add Spring Web Security to your Maven file:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>3.2.2.RELEASE</version>
</dependency>


<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>3.2.2.RELEASE</version>
</dependency>

3.2.2 is the latest version at the moment of writing.

Alright, when this is installed it is time to configure your web application. I assume you know how to create an Entity within Hibernate, so I am not going to cover that.

First off, the configuration:

Add this to web.xml:

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

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/mvc-dispatcher-servlet.xml
    </param-value>
</context-param>

<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>

Keep in mind, my web.xml was rather plain because I started out with a pretty clean project, this could be different for you. Also mind the name mvc-dispatcher-servlet.xml could be named differently in your project.

If you haven’t added the XML security namespaces to your project yet, it’s time to do so now:

xmlns:security="http://www.springframework.org/schema/security"

And add this to your schemaLocation:

http://www.springframework.org/schema/security

http://www.springframework.org/schema/security/spring-security-3.2.xsd

So this will make your XML header look something like this:

<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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context.xsd


http://www.springframework.org/schema/mvc


http://www.springframework.org/schema/mvc/spring-mvc.xsd


http://www.springframework.org/schema/security


http://www.springframework.org/schema/security/spring-security.xsd

        ">

Then, add this to mvc-dispatcher-servlet.xml:

<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

<security:http auto-config="true">
    <security:intercept-url pattern="/members/*" access="ROLE_USER" />
    <security:form-login login-page="/login" default-target-url="/"
                         authentication-failure-url="/login/failed" />
    <security:logout logout-success-url="/" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="userDetailsService">

        <security:password-encoder ref="passwordEncoder" />

    </security:authentication-provider>
</security:authentication-manager>

As you can see here I declare a passwordEncoder, using the BCryptPasswordEncoder provided by the Spring Framework. This is by more secure than SHA-1 or MD5 (just do a google search on this subject).

Another perhaps interesting fact is that I refer to the service userDetailsService here. We will declare this now, it is used to build our user objects.

UserDetailsService.java:

@Service("userDetailsService")
public class UserDetailService implements UserDetailsService {

    @Autowired
    @Qualifier("userDao")
    private IUserDao userDao;

    @Autowired
    private Assembler assembler;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userDao.findByEmail(username);

        if (user == null)
            throw new UsernameNotFoundException("User not found");

        return assembler.buildUserFromEntity(user);

    }
}

And as you can imagine, we will need to declare the Assembler as well. I assume you know how the UserDAO works, or how it’s supposed to work. At the very least it should have a method that queries a user by email address or username.

Assembler.java:

@Service("assembler")
public class Assembler {

    @Transactional
    public User buildUserFromEntity(com.mtech.easyexchange.model.User user) {
        String username = user.getEmail();
        String password = user.getPassword();
        boolean enabled = true;

        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        return new User(username, password, enabled, enabled, enabled, enabled, authorities);
    }
}

As you can see I simply add a SimpleGrantedAuthority hardcoded to the user: ROLE_USER. What you could do is create an entity holding UserRoles and load them from the database.

This pretty much concludes the very basic configuration of Spring Security using Hibernate 4.3 with Spring MVC 4.