Spring Security 5 Default Password Encoder
January 03, 2020
Spring Security DelegatingPasswordEncoder
delegates to another PasswordEncoder
based upon a prefixed identifier. The DelegatingPasswordEncoder
is introduced in Spring Security 5.0 and is the default password encoder. Now the password format will be used as {id}EncodedPassword
. Suppose password is {bcrypt}EncodedPassword
then DelegatingPasswordEncoder
will delegate it to BCryptPasswordEncoder
. Before Spring Security 5.0, the default PasswordEncoder
was NoOpPasswordEncoder
which requires plain text password. Now in Spring Security 5.0, if we want to use plain text password, then the password format will be {noop}password
and DelegatingPasswordEncoder
will delegate it to NoOpPasswordEncoder
automatically.
Here we will discuss using Spring Security 5 default password encoder in detail with examples.
Contents
Technologies Used
Find the technologies being used in our example.1. Java 11
2. Spring 5.2.1.RELEASE
3. Spring Boot 2.2.1.RELEASE
4. Maven 3.5.2
Using DelegatingPasswordEncoder
TheDelegatingPasswordEncoder
is the default password encoder in Spring Security 5.0. To store a password using DelegatingPasswordEncoder
, we need to use following format.
{id}EncodedPassword
1. noop for
NoOpPasswordEncoder
2. bcrypt for
BCryptPasswordEncoder
3. pbkdf2 for
Pbkdf2PasswordEncoder
4. scrypt for
SCryptPasswordEncoder
5. sha256 for
StandardPasswordEncoder
We store password in file, database, LDAP, in-memory etc. Using prefixed id with password, the
DelegatingPasswordEncoder
delegates the password to respective encoder to handle it. Find the sample password storage format examples.
1.
{noop}ram123
DelegatingPasswordEncoder
will delegate this password to NoOpPasswordEncoder
.
2.
{bcrypt}$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6
DelegatingPasswordEncoder
will delegate this password to BCryptPasswordEncoder
.
3.
{pbkdf2}77a366e9ba2d6830b64d1b86eb7462996f3102d2b76562de3e56e5f13543a02486e1ee553cef18de
DelegatingPasswordEncoder
will delegate this password to Pbkdf2PasswordEncoder
.
4.
{scrypt}$e0801$VoXA+5ot9fXbuLaOj5izqgd3JrOtBjvsqpbwssgHIA3omPpNB8t+FYtnsVpxx5DJjAvFtrA/klDstepB320TSw==$CLsjnAxzzNof2jkDrSBeoCTvuxO8qi67FRDY0vrCZwY=
DelegatingPasswordEncoder
will delegate this password to SCryptPasswordEncoder
.
5.
{sha256}25ff1da3db4fc9bfab27acfc47625ac607a076450762fed1d53003ebeb73239e70529567767eee51
DelegatingPasswordEncoder
will delegate this password to StandardPasswordEncoder
.
Find the example for
DelegatingPasswordEncoder
password format. Here we are using in-memory authentication.
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("ram") .password("{noop}ram123") //ram123 .roles("USER") .and() .withUser("lakhan") .password("{bcrypt}$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6") //lakhan123 .roles("USER") .and() .withUser("bharat") .password("{pbkdf2}77a366e9ba2d6830b64d1b86eb7462996f3102d2b76562de3e56e5f13543a02486e1ee553cef18de") //bharat123 .roles("USER") .and() .withUser("shatru") .password("{scrypt}$e0801$VoXA+5ot9fXbuLaOj5izqgd3JrOtBjvsqpbwssgHIA3omPpNB8t+FYtnsVpxx5DJjAvFtrA/klDstepB320TSw==$CLsjnAxzzNof2jkDrSBeoCTvuxO8qi67FRDY0vrCZwY=") //shatru123 .roles("USER") .and() .withUser("bali") .password("{sha256}25ff1da3db4fc9bfab27acfc47625ac607a076450762fed1d53003ebeb73239e70529567767eee51") //bali123 .roles("USER"); }
DelegatingPasswordEncoder
should delegate to our any specific password encoder such as BCryptPasswordEncoder
, we just have to create its bean in our Java configuration.
@Bean public static BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6
DelegatingPasswordEncoder
will delegate above password to BCryptPasswordEncoder
automatically.
Find the XML configuration to create
BCryptPasswordEncoder
bean.
<bean name="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
We can instantiate
DelegatingPasswordEncoder
as following in our application.
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
Custom DelegatingPasswordEncoder
We can prepare a customDelegatingPasswordEncoder
instance to be configured with Spring Security application. Prepare a Map
with password encoder id and PasswordEncoder
instance.
Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put("myBcrypt", new BCryptPasswordEncoder()); encoders.put("myPbkdf2", new Pbkdf2PasswordEncoder()); encoders.put("myScrypt", new SCryptPasswordEncoder());
DelegatingPasswordEncoder
constructor.
public DelegatingPasswordEncoder(String idForEncode, Map<String, PasswordEncoder> idToPasswordEncoder)
PasswordEncoder
used to encode raw password using encode(CharSequence rawPassword)
method.
idToPasswordEncoder is the
Map
of password encoder id and PasswordEncoder
instance.
So we create instance of
DelegatingPasswordEncoder
as following.
PasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("myBcrypt", encoders);
DelegatingPasswordEncoder
instance with in-memory authentication.
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put("myBcrypt", new BCryptPasswordEncoder()); encoders.put("myPbkdf2", new Pbkdf2PasswordEncoder()); encoders.put("myScrypt", new SCryptPasswordEncoder()); PasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("myBcrypt", encoders); auth.inMemoryAuthentication().passwordEncoder(passwordEncoder) .withUser("lakhan") .password("{myBcrypt}$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6") //lakhan123 .roles("USER") .and() .withUser("bharat") .password("{myPbkdf2}77a366e9ba2d6830b64d1b86eb7462996f3102d2b76562de3e56e5f13543a02486e1ee553cef18de") //bharat123 .roles("USER") .and() .withUser("shatru") .password("{myScrypt}$e0801$VoXA+5ot9fXbuLaOj5izqgd3JrOtBjvsqpbwssgHIA3omPpNB8t+FYtnsVpxx5DJjAvFtrA/klDstepB320TSw==$CLsjnAxzzNof2jkDrSBeoCTvuxO8qi67FRDY0vrCZwY=") //shatru123 .roles("USER"); }
Troubleshooting
Suppose password encoder id is missing in password format.$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:250) org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$LazyPasswordEncoder.matches(AuthenticationConfiguration.java:312)
{myBcrypt}$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6
Complete Example
We will create a Spring Security 5 login application to demo the default password encoder.pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath /> </parent> <properties> <context.path>spring-app</context.path> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>
package com.concretepage; import org.springframework.context.annotation.Configuration; 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; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/**").access("hasRole('USER')") .and().formLogin(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("ram") .password("{noop}ram123") //ram123 .roles("USER") .and() .withUser("lakhan") .password("{bcrypt}$2a$10$q5pHs1fyVDbQSnBu3Il/meAONlMYFT1RhGlT2OC6IXX5.bp2JBZU6") //lakhan123 .roles("USER") .and() .withUser("bharat") .password("{pbkdf2}77a366e9ba2d6830b64d1b86eb7462996f3102d2b76562de3e56e5f13543a02486e1ee553cef18de") //bharat123 .roles("USER") .and() .withUser("shatru") .password("{scrypt}$e0801$VoXA+5ot9fXbuLaOj5izqgd3JrOtBjvsqpbwssgHIA3omPpNB8t+FYtnsVpxx5DJjAvFtrA/klDstepB320TSw==$CLsjnAxzzNof2jkDrSBeoCTvuxO8qi67FRDY0vrCZwY=") //shatru123 .roles("USER") .and() .withUser("bali") .password("{sha256}25ff1da3db4fc9bfab27acfc47625ac607a076450762fed1d53003ebeb73239e70529567767eee51") //bali123 .roles("USER"); } }
package com.concretepage; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class AppController { @GetMapping("/app") public @ResponseBody String helloUser(Authentication authentication) { return "Welcome! " + authentication.getName(); } }
package com.concretepage; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } }
Output
Download the project and run the following command from root folder of the project using command prompt.mvn spring-boot:run
http://localhost:8080/app
References
Spring Security ReferenceSpring doc: DelegatingPasswordEncoder