Search code examples
springspring-securitybcrypt

Encrypting InMemoryAuthentication passwords with Bcrypt


Before I use Bcrypt on a custom implementation of UserDetailsService, I first want to see if I can use it in an in-memory database.

package com.patrick.Security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private UserDetailsService userDetailsService;


    @Autowired
    public WebSecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.POST, "/users").hasAuthority("ADMIN")
                .antMatchers(HttpMethod.POST, "/shifts").hasAnyAuthority("ADMIN", "SUPERVISOR")
                .anyRequest().authenticated()
                .and()
                .addFilter(new AuthenticationFilter(authenticationManager()))
                .addFilter(new AuthorizationFilter(authenticationManager()));
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(passwordEncoder())
                .withUser("admin").password("password").roles("ADMIN");
    }

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

With creating/exposing the PasswordEncoder bean this warning pops up which ultimately prevents me from accessing the login path:

o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt

Adding the Deprecated NoOpPasswordEncoder will temporarily solve the issue, but obviously wont encode the passwords:

@SuppressWarnings("deprecation")
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}

What's the correct way to add Bcrypt?


Solution

  • With creating/exposing the PasswordEncoder bean this warning pops up which ultimately prevents me from accessing the login path:

    o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt
    

    This is because the password you're providing is not encoded with BCrypt. Instead of passing "password" directly as the password it needs to be encoded first.

    For testing purposes, an easy way of doing this would be to just get a hold of your password encoder and encode it in your configure method like this

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        String password = passwordEncoder().encode("password");
        auth.inMemoryAuthentication().withUser("admin").password(password).roles("ADMIN");
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }