February 16th, 2023
Spring In-Memory Authentication – Dynamic users
This illustrates the use of Spring in-memory authentication. We also look into how to customize the Spring Security AuthenticationManager to use Spring Security in-memory authentication and add multiple users with different attributes, authorities, and roles.
Let’s use Spring boot to quickly create and bootstrap spring applications. We configure Spring Security to use In-Memory Authentication in this spring boot application.

Tools and Technologies Used

  • Spring Boot – 2.7.8
  • Spring Framework – 5.7.6
  • Spring Security – 5.7.6
  • Maven – 3.8.7
  • Spring Tool Suite IDE – 4.14.0.RELEASE
  • OS – Linux 5.15.93-1-MANJARO

Development Steps

Let’s use below development steps to create this example:
  1. Creating a Spring Boot Application
  2. Project Structure
  3. Maven Dependencies – Pom.xml
  4. Spring Security In-Memory Authentication
  5. Running the Application
  6. Demo
  7. Conclusion

1. Creating a Spring Boot Application

There are many ways to create a Spring Boot application. You can refer below articles to create a Spring Boot application.
>> Create Spring Boot Project With Spring Initializer
>> Create Spring Boot Project in Spring Tool Suite [STS]

2. Project Structure

Following is the package or project structure for your reference 
 
 
 

3. Maven Dependencies – Pom.xml

Make sure the following dependencies reside on the class-path.
				
					<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.8</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>in-memory</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>in-memory</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

				
			

4. Spring Security In-Memory Authentication

In the following configuration class, we are using the AuthenticationManagerBuilder with the In-memory UserDetailsManagerConfigurer to configure the Spring Security In-Memory Authentication.
				
					package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.antMatchers("/").permitAll()
				.anyRequest().authenticated()
				.and()
			.httpBasic()
				.and()
			.logout()
				.permitAll();
	}
	@Override
	public void configure(WebSecurity web) throws Exception {
		web
			.ignoring()
			.antMatchers(HttpMethod.POST, "/register");
	}
	
	@Bean
	public InMemoryUserDetailsManager getInMemoryUserDetailsManager() {
		return new InMemoryUserDetailsManager();
	}
}

				
			
Notice that we are using a builder pattern to create multiple users with different attributes, authorities, and roles. This automatically configures a UserDetailsService which we can use.
Note that we have added a password storage format, for plain text, add {noop}. Prior to Spring Security 5.0, the default PasswordEncoder was NoOpPasswordEncoder which required plain text passwords. In Spring Security 5, the default is DelegatingPasswordEncoder, which required Password Storage Format like {noop}.
 

5. Simple Rest Web Service

Let’s create a simple rest service that is protected. We can obtain the current in-memory user by injecting the Authentication as an argument of the method
				
					package com.example.demo.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WelcomeController {

	private final InMemoryUserDetailsManager inMemoryUserDetailsManager;
	
	public WelcomeController(InMemoryUserDetailsManager inMemoryUserDetailsManager) {
		this.inMemoryUserDetailsManager = inMemoryUserDetailsManager; 
	}
	
	@GetMapping("/")
	public String greeting() {
		return "Welcome: home";
	}
	@GetMapping("/login")
	public String greeting(Authentication auth) {
		UserDetails user = inMemoryUserDetailsManager.loadUserByUsername(auth.getName());
		System.out.println(user);
		return "Welcome: "+auth.toString();
	}
	
	@PostMapping("/register")
	public String register(@RequestParam("username") String username, @RequestParam("password") String password) {
		inMemoryUserDetailsManager.createUser(User
				.withUsername(username)
				.password("{noop}"+password)
				.roles("USER")
				.build()
				);
		return username +" Created!";
	}
	
	@Bean
	public void addUsersOnStartup() {
		UserDetails user = User.builder()
			.username("user")
			.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
			.roles("USER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
			.roles("USER", "ADMIN")
			.build();
		inMemoryUserDetailsManager.createUser(user);
		inMemoryUserDetailsManager.createUser(admin);
	}
}

				
			

6. Running the Application

Let’s run the spring boot application with following entry point:
				
					package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class InMemoryApplication {

	public static void main(String[] args) {
		SpringApplication.run(InMemoryApplication.class, args);
	}
}

				
			

7. Demo

Hit this link in browser – http://localhost:8080/. Below is the default login page provided by spring security. 
 
Register new users via the Post API
Login with the newly created users
 

Related Tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *