java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id “null”
This post will discuss how to resolve java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" exception in a Spring Boot application.
Until Spring Security 4, it was possible to store passwords in plain text using in-memory authentication. For instance, the following code runs fine with Spring Security 4:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("password").roles("USER"); } } |
Spring Security 5 recommends using the PasswordEncoder interface for encoding passwords. So, if we upgrade our application to Spring Security 5, we’ll end up with the following error for the above code:
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:244) ~[spring-security-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$LazyPasswordEncoder.matches(AuthenticationConfiguration.java:289) ~[spring-security-config-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:90) ~[spring-security-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166) ~[spring-security-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
The default PasswordEncoder is built as a DelegatingPasswordEncoder in Spring Security 5, but no password encoder was configured for our in-memory authentication. This results in the above error when the passwords are stored in plain text inside the memory. To resolve the above error, we should configure in-memory authentication to use a PasswordEncoder.
1. We can force DelegatingPasswordEncoder to use plain text simply by prefix {noop} to our passwords. This will activate the NoOpPasswordEncoder instead of the default DelegatingPasswordEncoder.
|
1 2 3 4 5 6 7 8 9 10 |
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("{noop}password").roles("USER"); } } |
Alternatively, we can pass instance of NoOpPasswordEncoder to passwordEncoder() method of InMemoryUserDetailsManagerConfigurer class, as shown below:
|
1 2 3 4 5 6 7 8 9 10 11 |
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .passwordEncoder(NoOpPasswordEncoder.getInstance()) .withUser("user").password("password").roles("USER"); } } |
2. We can also use included encoders in PasswordEncoderFactories or define our own set of password encoders. The following example creates a DelegatingPasswordEncoder with default mappings.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); auth.inMemoryAuthentication() .withUser("user") .password(encoder.encode("password")) .roles("USER"); } } |
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)