Integrating Spring Security with MongoDB

One of the most powerful features of Spring Security (besides support for industry standard, extensibility, easy configuration, expressive authorization schemes and others) is the ability to easily authenticate users with any data store that can manage users credentials and other authentication attributes.

In this short tutorial I will explain how to use MongoDB, the popular scalable and high-performance document database for authentication purposes.

This tutorial assumes a basic knowledge of Spring Security.

First, we'll create the Subscriber (user) entity which is mapped to the subscribers MongoDB collection.


@Entity(value = "subscribers", noClassnameStored = false)
public class Subscriber  {
    private ObjectId id;
    @Indexed(value = IndexDirection.ASC, name="subscriber_index", unique = true)
    @Length(min = 6, max = 12)
    private String identifier;
    @Length(min = 6, max = 12)
    private String credentials;
    private Boolean active;

If some of these annotations seem a little bit JPA-ish familiar (@Entity, @Id) it's not because JPA is used here. Instead, Morphia - a lightweight Object / MongoDB wrapper library above MongoDB Java driver - is being used. Morphia has borrowed some of JPA concepts and behaviors.
Morphia also uses Hibernate Validation to process JSR 303 annotation, and has GWT support extension
Note the unique index annotation above the identifier (username) property. This is used to ensure the index on Morphia bootstrap.

Next, I'll show a minimal Spring Security configuration to be used:



<http auto-config='true'>
        <intercept-url pattern="/rest/**" access="ROLE_USER"/>
    <authentication-provider user-service-ref="userDetailsService"/>
<beans:bean id="userDetailsService" class=""/>


This means that every web request going through the 'rest' URL pattern must be authenticated. The request principal must be granted the "ROLE_USER" role.

The Authentication Provider is injected with a custom User Detail Service (in this case the MongoUserDetailService). Alternatively we could have booted our custom Authentication Provider, put the default one supplied with the Spring Security framework (DaoAuthenticationProvider) with it's method additionalAuthenticationChecks is sufficient for our simple example and needs.

Next we'll have a look at our custom User Details Service:


public class MongoUserDetailService implements UserDetailsService {
    private SubscriberMorphiaDao subscriberMorphiaDao;
    public UserDetails loadUserByUsername(String username) 
           throws UsernameNotFoundException, DataAccessException {
        Subscriber subscriber = subscriberMorphiaDao.find(username);
        if (subscriber == null) {
            return null;
        Collection<GrantedAuthorityImpl> authorities = 
             Sets.newHashSet(new GrantedAuthorityImpl("ROLE_USER"));
        return new User(subscriber.getIdentifier(), subscriber.getCredentials(), 
                subscriber.isActive(),true,true, true, authorities);


Our MongoUserDetailService implements UserDetailService's loadUserByUsername() method.

First a DAO a used to retrieve the Subscriber class discussed above using the username which is mapped to a unique key in Mongo's subscriber collection.
Next a Spring Security User instance, which encapsulate user credentials and authorities, is being constructed. The first three parameters are for the username, password and enabled properties respectively. The true triplet is for ignoring account password expiry and lock which is none of our concern for now. The last parameter is a collection of GrantedAuthority (roles) the user is associated with. The "ROLE_USER" authority matches the URL pattern defined in the configuration file.
The "ROLE_USER" is hard coded here, but the collection of authorities could have been easily constructed from an array in the Subscriber document, for example.