# Authentication : InMemoryUserDetailsManager

In 
Published 2023-07-01

This tutorial explains how we can authenticate into Spring Boot using Spring Security and credentials and roles stored in memory.

This tutorial consider you have already created the application from My first Spring Boot Service using Spring Security and disabled the CSRF.

In addition, of what we have got from the articles above, we need to add the authentication mechanism. In our example the username and the password are stored in memory.

The first question is "How we can get these credentials from memory" ?

For this, we need to define them "manually" in the code. This is done by the following code snippet:

    @Bean
    public UserDetailsService users() {
        List<UserDetails> userDetailsList = new ArrayList<>();

        User.UserBuilder builder = User.builder();

        UserDetails userDan = builder
                .username("dan")
                .password(passwordEncoder().encode("dd"))
                .roles("read")
                .build();

        UserDetails userAnna = builder
                .username("anna")
                .password(passwordEncoder().encode("aa"))
                .roles("write")
                .build();

        UserDetails admin = builder
                .username("admin")
                .password(passwordEncoder().encode("adm"))
                .roles("admin")
                .build();

        userDetailsList.add(userDan);
        userDetailsList.add(userAnna);
        userDetailsList.add(admin);

        return new InMemoryUserDetailsManager(userDetailsList);
    }

Here we have the whole configuration class:

ProjectSpringSecurityConfig.java
package com.demo.springsecurity.config;

import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebSecurity
public class ProjectSpringSecurityConfig {

    @Bean
    public SecurityFilterChain myFilterChain1(HttpSecurity http) throws Exception {
        // We have a Basic authentication (username & password)
        http.httpBasic(Customizer.withDefaults())
            // CSRF is disabled
            .csrf(csrf -> csrf.disable())
            // Only authenticated requests are allowed for URL pattern "/employee/*"
            .authorizeHttpRequests((authorize) -> authorize
                 .requestMatchers("/employee/*").authenticated()
            );

        return http.build();
    }

    @Bean
    public UserDetailsService users() {
        List<UserDetails> userDetailsList = new ArrayList<>();

        User.UserBuilder builder = User.builder();

        UserDetails userDan = builder
                .username("dan")
                .password(passwordEncoder().encode("dd"))
                .roles("read")
                .build();

        UserDetails userAnna = builder
                .username("anna")
                .password(passwordEncoder().encode("aa"))
                .roles("write")
                .build();

        UserDetails admin = builder
                .username("admin")
                .password(passwordEncoder().encode("adm"))
                .roles("admin")
                .build();

        userDetailsList.add(userDan);
        userDetailsList.add(userAnna);
        userDetailsList.add(admin);

        return new InMemoryUserDetailsManager(userDetailsList);
    }

    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
}

The Security Filter Chain let only the authenticated user to pass through it. Unauthenticated users will receive "401 Unauthorized" message.

The authentication itself, is done by the implementation of AuthenticationProvider :

ProjectSpringSecurityConfig.java
package com.demo.springsecurity.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        if (passwordEncoder.matches(password, userDetails.getPassword())) {
            return new UsernamePasswordAuthenticationToken(
                    username,
                    password,
                    userDetails.getAuthorities()
            );
        } else {
            throw new BadCredentialsException("Something went wrong with the Authentication");
        }
    }

    @Override
    public boolean supports(Class<?> authenticationType) {
        return authenticationType.equals(UsernamePasswordAuthenticationToken.class);
    }
}

The Controller of my application looks like:

EmployeeController.java
package com.demo.springsecurity.controller;

import com.demo.springsecurity.model.Employee;
import com.demo.springsecurity.service.EmployeeService;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;

@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Autowired
    EmployeeService employeeService;

    @Autowired
    private ApplicationContext context;

    @GetMapping(value="/all")
    String getAllEmployees() {
        ArrayList<Employee> allEmployees = employeeService.getEmployees();
        String json = new Gson().toJson(allEmployees);

        return json;
    }

    @GetMapping(value="/info")
    String info() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication a = securityContext.getAuthentication();
        var returnVar = "Authenticated with : "+a.getName();

        return returnVar;
    }

    @PutMapping (value="/add", consumes = "application/json")
    int addEmployee(@RequestBody Employee newEmployee) {

        employeeService.addEmployee(newEmployee);
        int newCount = employeeService.countEmployees();

        return newCount;
    }

    @DeleteMapping(value="/delete", consumes = "application/json")
    int deleteEmployee(@RequestBody String empId) {

        employeeService.removeEmployee(empId);
        int newCount = employeeService.countEmployees();
        return newCount;
    }

}

You can see how we can get authentication information from the Authentication object (after the authentication of the user). All this information is available in the Security Context Holder:

SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication a = securityContext.getAuthentication();
var returnVar = "Authenticated with : "+a.getName();

Enjoy Spring Security Authentication !