VOOZH about

URL: https://www.javacodegeeks.com/2016/09/spring-boot-spring-security-nosql.html

โ‡ฑ Spring boot with Spring Security and NoSQL - Java Code Geeks


In the previous post we set up a spring security configuration by providing custom queries for user and authority retrieval from an sql database.

Nowadays many modern applications utilize NoSQL databases. Spring security does not come with an out of the box solution for NoSQL databases.

In those case we need to provide a solution by Implementing a Custom UserDetailsService.

We will use a MongoDB Database for this example. I will use a docker image, however it is as easy to set up a mongodb database by downloading it from the official website.

Those are some commands to get started with docker and mongodb (feel free to ignore them if you donโ€™t use docker)

#pull the mongo image
docker pull mongo
#create a mongo container
docker run --name some-mongo -d mongo
#get the docker container id
docker ps
#get the containers ip
docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CID
#connection using the ip retrieved
mongo $mongodb_container_ip

Then we will write a simple initialization script called createuser.js. The script creates an document containing user information such as username password and authorities.

use springsecurity
db.users.insert({"name":"John","surname":"doe","email":"john@doe.com","password":"cleartextpass","authorities":["user","admin"]})

We will use mongo cli to execute it.

mongo 172.17.0.2:27017 < createuser.js

In order to use spring security with mongodb we need to retrieve the user information from the users collection.

First step is to add the mongodb dependencies to our gradle file, including the mongodb driver. Note that we will use a profile called โ€˜customuserdetailsโ€™.

group 'com.gkatzioura'
version '1.0-SNAPSHOT'

buildscript {
 repositories {
 mavenCentral()
 }
 dependencies {
 classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE")
 }
}

apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'spring-boot'

sourceCompatibility = 1.8

repositories {
 mavenCentral()
}

dependencies {
 compile("org.springframework.boot:spring-boot-starter-web")
 compile("org.thymeleaf:thymeleaf-spring4")
 compile("org.springframework.boot:spring-boot-starter-security")
 compile("org.mongodb:mongo-java-driver:1.3")
 compile("org.slf4j:slf4j-api:1.6.6")
 compile("ch.qos.logback:logback-core:1.1.7")
 compile("ch.qos.logback:logback-classic:1.1.7")
 testCompile "junit:junit:4.11"
}

bootRun {
 systemProperty "spring.profiles.active", "customuserdetails"
}

Then we shall create a mongodb connection bean.

package com.gkatzioura.spring.security.config;

import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
 * Created by gkatzioura on 9/27/16.
 */
@Configuration
@Profile("customuserdetails")
public class MongoConfiguration {

 @Bean
 public MongoClient createConnection() {

 //You should put your mongo ip here
 return new MongoClient("172.17.0.2:27017");
 }
}

Then we will create a custom user details object.

package com.gkatzioura.spring.security.model;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;

/**
 * Created by gkatzioura on 9/27/16.
 */
public class MongoUserDetails implements UserDetails{

 private String username;
 private String password;
 private List<GrantedAuthority> grantedAuthorities;
 
 public MongoUserDetails(String username,String password,String[] authorities) {
 this.username = username;
 this.password = password;
 this.grantedAuthorities = AuthorityUtils.createAuthorityList(authorities);
 }
 
 @Override
 public Collection<? extends GrantedAuthority> getAuthorities() {
 return grantedAuthorities;
 }

 @Override
 public String getPassword() {
 return password;
 }

 @Override
 public String getUsername() {
 return username;
 }

 @Override
 public boolean isAccountNonExpired() {
 return true;
 }

 @Override
 public boolean isAccountNonLocked() {
 return true;
 }

 @Override
 public boolean isCredentialsNonExpired() {
 return true;
 }

 @Override
 public boolean isEnabled() {
 return true;
 }
}

Next step we will add a custom UserDetailsService retrieving user details through the mongodb database.

package com.gkatzioura.spring.security.service;

import com.gkatzioura.spring.security.model.MongoUserDetails;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Created by gkatzioura on 9/27/16.
 */
public class CustomerUserDetailsService implements UserDetailsService {

 @Autowired
 private MongoClient mongoClient;

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

 MongoDatabase database = mongoClient.getDatabase("springsecurity");
 MongoCollection<Document> collection = database.getCollection("users");

 Document document = collection.find(Filters.eq("email",email)).first();

 if(document!=null) {

 String name = document.getString("name");
 String surname = document.getString("surname");
 String password = document.getString("password");
 List<String> authorities = (List<String>) document.get("authorities");

 MongoUserDetails mongoUserDetails = new MongoUserDetails(email,password,authorities.toArray(new String[authorities.size()]));

 return mongoUserDetails;
 }

 return null;
 }

}

Final step is to provide a spring security configuration using the custom UserDetailsService we implemented previously.

package com.gkatzioura.spring.security.config;

import com.gkatzioura.spring.security.service.CustomerUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * Created by gkatzioura on 9/27/16.
 */
@EnableWebSecurity
@Profile("customuserdetails")
public class CustomUserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {

 @Bean
 public UserDetailsService mongoUserDetails() {
 return new CustomerUserDetailsService();
 }

 @Override
 protected void configure(AuthenticationManagerBuilder auth) throws Exception {

 UserDetailsService userDetailsService = mongoUserDetails();
 auth.userDetailsService(userDetailsService);
 }

 @Override
 protected void configure(HttpSecurity http) throws Exception {

 http.authorizeRequests()
 .antMatchers("/public").permitAll()
 .anyRequest().authenticated()
 .and()
 .formLogin()
 .permitAll()
 .and()
 .logout()
 .permitAll();
 }

}

To run the application issue

gradle bootRun

You can find the source code on github

Reference: Spring boot with Spring Security and NoSQL from our JCG partner Emmanouil Gkatziouras at the gkatzioura blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

๐Ÿ‘ Photo of Emmanouil Gkatziouras
Emmanouil Gkatziouras
September 29th, 2016Last Updated: September 28th, 2016
1 206 3 minutes read

Emmanouil Gkatziouras

He is a versatile software engineer with experience in a wide variety of applications/services.He is enthusiastic about new projects, embracing new technologies, and getting to know people in the field of software.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Luis Henrique Rocha
9 years ago

Tried to login running this example and got the following exception:

java.lang.IllegalArgumentException: Invalid salt

0
Reply
Back to top button
Close
wpDiscuz