# Authentication : JdbcUserDetailsManager

In 
Published 2023-06-24

This tutorial explains how we can authenticate into Spring Boot using Spring Security and credentials stored into a MySql database.

This tutorial consider you have already created the application from My first Spring Boot Service using Spring Security , disabled the CSRF and Store Users & Passwords into a MySql database.

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 MySql database for each user.

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

This is done automatically by the following code snippet:

@Bean
    // We are using JdbcUserDetailsManager interface for finding the credentials
    public UserDetailsService userDetailsService(DataSource dataSource) {
        return new JdbcUserDetailsManager(dataSource);
    }

Here we have the whole configuration class which implements the Spring Boot Authentication:

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.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@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
    // We are using JdbcUserDetailsManager interface for finding the credentials
    public UserDetailsService userDetailsService(DataSource dataSource) {
        return new JdbcUserDetailsManager(dataSource);
    }

    @Bean
    // We are not hashing the password : the password is in clear text in the MySql database
    // This mustn't happen in PROD environment, but it is good for testing purpose
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

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
    // Return true if this AuthenticationProvider supports the provided authentication class
    public boolean supports(Class<?> authenticationType) {
        return authenticationType.equals(UsernamePasswordAuthenticationToken.class);
    }
}

I have also modified the Controller to look like this:

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 !