Add Include-Code to the Password Storage page

References gh-16226

Signed-off-by: Himanshu Pareek <himanshupareekiit01@gmail.com>
This commit is contained in:
Himanshu Pareek 2025-10-15 21:44:45 +05:30 committed by Josh Cummings
parent 56a23d9ddc
commit dcb4e47cd5
15 changed files with 401 additions and 293 deletions

View File

@ -67,68 +67,12 @@ Instead Spring Security introduces `DelegatingPasswordEncoder`, which solves all
You can easily construct an instance of `DelegatingPasswordEncoder` by using `PasswordEncoderFactories`:
.Create Default DelegatingPasswordEncoder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
PasswordEncoder passwordEncoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val passwordEncoder: PasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder()
----
======
include-code::./DelegatingPasswordEncoderUsage[tag=createDefaultPasswordEncoder,indent=0]
Alternatively, you can create your own custom instance:
.Create Custom DelegatingPasswordEncoder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("sha256", new StandardPasswordEncoder());
PasswordEncoder passwordEncoder =
new DelegatingPasswordEncoder(idForEncode, encoders);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val idForEncode = "bcrypt"
val encoders: MutableMap<String, PasswordEncoder> = mutableMapOf()
encoders[idForEncode] = BCryptPasswordEncoder()
encoders["noop"] = NoOpPasswordEncoder.getInstance()
encoders["pbkdf2"] = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5()
encoders["pbkdf2@SpringSecurity_v5_8"] = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()
encoders["scrypt"] = SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1()
encoders["scrypt@SpringSecurity_v5_8"] = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8()
encoders["argon2"] = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2()
encoders["argon2@SpringSecurity_v5_8"] = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()
encoders["sha256"] = StandardPasswordEncoder()
val passwordEncoder: PasswordEncoder = DelegatingPasswordEncoder(idForEncode, encoders)
----
======
include-code::./DelegatingPasswordEncoderUsage[tag=createCustomPasswordEncoder,indent=0]
[[authentication-password-storage-dpe-format]]
=== Password Storage Format
@ -209,74 +153,12 @@ If you are putting together a demo or a sample, it is a bit cumbersome to take t
There are convenience mechanisms to make this easier, but this is still not intended for production.
.withDefaultPasswordEncoder Example
[tabs]
======
Java::
+
[source,java,role="primary",attrs="-attributes"]
----
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("user")
.build();
System.out.println(user.getPassword());
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
----
Kotlin::
+
[source,kotlin,role="secondary",attrs="-attributes"]
----
val user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("user")
.build()
println(user.password)
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
----
======
include-code::./WithDefaultPasswordEncoderUsage[tag=createSingleUser,indent=0]
If you are creating multiple users, you can also reuse the builder:
.withDefaultPasswordEncoder Reusing the Builder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
UserBuilder users = User.withDefaultPasswordEncoder();
UserDetails user = users
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = users
.username("admin")
.password("password")
.roles("USER","ADMIN")
.build();
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val users = User.withDefaultPasswordEncoder()
val user = users
.username("user")
.password("password")
.roles("USER")
.build()
val admin = users
.username("admin")
.password("password")
.roles("USER", "ADMIN")
.build()
----
======
include-code::./WithDefaultPasswordEncoderUsage[tag=createMultipleUsers,indent=0]
This does hash the password that is stored, but the passwords are still exposed in memory and in the compiled source code.
Therefore, it is still not considered secure for a production environment.
@ -337,28 +219,7 @@ The default implementation of `BCryptPasswordEncoder` uses strength 10 as mentio
tune and test the strength parameter on your own system so that it takes roughly 1 second to verify a password.
.BCryptPasswordEncoder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
// Create an encoder with strength 16
val encoder = BCryptPasswordEncoder(16)
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
======
include-code::./BCryptPasswordEncoderUsage[tag=bcryptPasswordEncoder,indent=0]
[[authentication-password-storage-argon2]]
== Argon2PasswordEncoder
@ -370,28 +231,7 @@ Like other adaptive one-way functions, it should be tuned to take about 1 second
The current implementation of the `Argon2PasswordEncoder` requires BouncyCastle.
.Argon2PasswordEncoder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
// Create an encoder with all the defaults
Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
// Create an encoder with all the defaults
val encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
======
include-code::./Argon2PasswordEncoderUsage[tag=argon2PasswordEncoder,indent=0]
[[authentication-password-storage-pbkdf2]]
== Pbkdf2PasswordEncoder
@ -402,28 +242,7 @@ Like other adaptive one-way functions, it should be tuned to take about 1 second
This algorithm is a good choice when FIPS certification is required.
.Pbkdf2PasswordEncoder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
// Create an encoder with all the defaults
val encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
======
include-code::./Pbkdf2PasswordEncoderUsage[tag=pbkdf2PasswordEncoder,indent=0]
[[authentication-password-storage-scrypt]]
== SCryptPasswordEncoder
@ -433,28 +252,7 @@ To defeat password cracking on custom hardware, scrypt is a deliberately slow al
Like other adaptive one-way functions, it should be tuned to take about 1 second to verify a password on your system.
.SCryptPasswordEncoder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
// Create an encoder with all the defaults
SCryptPasswordEncoder encoder = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
// Create an encoder with all the defaults
val encoder = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
======
include-code::./SCryptPasswordEncoderUsage[tag=sCryptPasswordEncoder,indent=0]
[[authentication-password-storage-other]]
== Other ``PasswordEncoder``s
@ -606,86 +404,4 @@ However, just a 401 or the redirect is not so useful in that case, it will cause
In such cases, you can handle the `CompromisedPasswordException` via the `AuthenticationFailureHandler` to perform your desired logic, like redirecting the user-agent to `/reset-password`, for example:
.Using CompromisedPasswordChecker
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin((login) -> login
.failureHandler(new CompromisedPasswordAuthenticationFailureHandler())
);
return http.build();
}
@Bean
public CompromisedPasswordChecker compromisedPasswordChecker() {
return new HaveIBeenPwnedRestApiPasswordChecker();
}
static class CompromisedPasswordAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final SimpleUrlAuthenticationFailureHandler defaultFailureHandler = new SimpleUrlAuthenticationFailureHandler(
"/login?error");
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception instanceof CompromisedPasswordException) {
this.redirectStrategy.sendRedirect(request, response, "/reset-password");
return;
}
this.defaultFailureHandler.onAuthenticationFailure(request, response, exception);
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
open fun filterChain(http:HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
formLogin {
failureHandler = CompromisedPasswordAuthenticationFailureHandler()
}
}
return http.build()
}
@Bean
open fun compromisedPasswordChecker(): CompromisedPasswordChecker {
return HaveIBeenPwnedRestApiPasswordChecker()
}
class CompromisedPasswordAuthenticationFailureHandler : AuthenticationFailureHandler {
private val defaultFailureHandler = SimpleUrlAuthenticationFailureHandler("/login?error")
private val redirectStrategy = DefaultRedirectStrategy()
override fun onAuthenticationFailure(
request: HttpServletRequest,
response: HttpServletResponse,
exception: AuthenticationException
) {
if (exception is CompromisedPasswordException) {
redirectStrategy.sendRedirect(request, response, "/reset-password")
return
}
defaultFailureHandler.onAuthenticationFailure(request, response, exception)
}
}
----
======
include-code::./CompromisedPasswordCheckerUsage[tag=configuration,indent=0]

View File

@ -0,0 +1,57 @@
package org.springframework.security.docs.features.authentication.authenticationcompromisedpasswordcheck;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.password.CompromisedPasswordChecker;
import org.springframework.security.authentication.password.CompromisedPasswordException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.password.HaveIBeenPwnedRestApiPasswordChecker;
public class CompromisedPasswordCheckerUsage {
// tag::configuration[]
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin((login) -> login
.failureHandler(new CompromisedPasswordAuthenticationFailureHandler())
);
return http.build();
}
@Bean
public CompromisedPasswordChecker compromisedPasswordChecker() {
return new HaveIBeenPwnedRestApiPasswordChecker();
}
static class CompromisedPasswordAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final SimpleUrlAuthenticationFailureHandler defaultFailureHandler = new SimpleUrlAuthenticationFailureHandler(
"/login?error");
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception instanceof CompromisedPasswordException) {
this.redirectStrategy.sendRedirect(request, response, "/reset-password");
return;
}
this.defaultFailureHandler.onAuthenticationFailure(request, response, exception);
}
}
// end::configuration[]
}

View File

@ -0,0 +1,16 @@
package org.springframework.security.docs.features.authentication.authenticationpasswordstorageargon2;
import static org.junit.Assert.assertTrue;
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
public class Argon2PasswordEncoderUsage {
public void testArgon2PasswordEncoder() {
// tag::argon2PasswordEncoder[]
// Create an encoder with all the defaults
Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
// end::argon2PasswordEncoder[]
}
}

View File

@ -0,0 +1,16 @@
package org.springframework.security.docs.features.authentication.authenticationpasswordstoragebcrypt;
import static org.junit.Assert.assertTrue;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class BCryptPasswordEncoderUsage {
public void testBCryptPasswordEncoder() {
// tag::bcryptPasswordEncoder[]
// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
// end::bcryptPasswordEncoder[]
}
}

View File

@ -0,0 +1,38 @@
package org.springframework.security.docs.features.authentication.authenticationpasswordstoragedepgettingstarted;
import java.util.List;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import static org.springframework.security.core.userdetails.User.UserBuilder;
public class WithDefaultPasswordEncoderUsage {
public UserDetails createSingleUser() {
// tag::createSingleUser[]
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("user")
.build();
System.out.println(user.getPassword());
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
// end::createSingleUser[]
return user;
}
public List<UserDetails> createMultipleUsers() {
// tag::createMultipleUsers[]
UserBuilder users = User.withDefaultPasswordEncoder();
UserDetails user = users
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = users
.username("admin")
.password("password")
.roles("USER","ADMIN")
.build();
// end::createMultipleUsers[]
return List.of(user, admin);
}
}

View File

@ -0,0 +1,43 @@
package org.springframework.security.docs.features.authentication.authenticationpasswordstoragedpe;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
public class DelegatingPasswordEncoderUsage {
PasswordEncoder defaultDelegatingPasswordEncoder() {
// tag::createDefaultPasswordEncoder[]
PasswordEncoder passwordEncoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
// end::createDefaultPasswordEncoder[]
return passwordEncoder;
}
PasswordEncoder customDelegatingPasswordEncoder() {
// tag::createCustomPasswordEncoder[]
String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("sha256", new StandardPasswordEncoder());
PasswordEncoder passwordEncoder =
new DelegatingPasswordEncoder(idForEncode, encoders);
// end::createCustomPasswordEncoder[]
return passwordEncoder;
}
}

View File

@ -0,0 +1,16 @@
package org.springframework.security.docs.features.authentication.authenticationpasswordstoragepbkdf2;
import static org.junit.Assert.assertTrue;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
public class Pbkdf2PasswordEncoderUsage {
void testPbkdf2PasswordEncoder() {
// tag::pbkdf2PasswordEncoder[]
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
// end::pbkdf2PasswordEncoder[]
}
}

View File

@ -0,0 +1,16 @@
package org.springframework.security.docs.features.authentication.authenticationpasswordstoragescrypt;
import static org.junit.Assert.assertTrue;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
public class SCryptPasswordEncoderUsage {
void testSCryptPasswordEncoder() {
// tag::sCryptPasswordEncoder[]
// Create an encoder with all the defaults
SCryptPasswordEncoder encoder = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
// end::sCryptPasswordEncoder[]
}
}

View File

@ -0,0 +1,55 @@
package org.springframework.security.kt.docs.features.authentication.authenticationcompromisedpasswordcheck
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Bean
import org.springframework.security.authentication.password.CompromisedPasswordChecker
import org.springframework.security.authentication.password.CompromisedPasswordException
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.invoke
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.DefaultRedirectStrategy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import org.springframework.security.web.authentication.password.HaveIBeenPwnedRestApiPasswordChecker
class CompromisedPasswordCheckerUsage {
// tag::configuration[]
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
formLogin {
authenticationFailureHandler = CompromisedPasswordAuthenticationFailureHandler()
}
}
return http.build()
}
@Bean
open fun compromisedPasswordChecker(): CompromisedPasswordChecker {
return HaveIBeenPwnedRestApiPasswordChecker()
}
class CompromisedPasswordAuthenticationFailureHandler : AuthenticationFailureHandler {
private val defaultFailureHandler = SimpleUrlAuthenticationFailureHandler("/login?error")
private val redirectStrategy = DefaultRedirectStrategy()
override fun onAuthenticationFailure(
request: HttpServletRequest,
response: HttpServletResponse,
exception: AuthenticationException
) {
if (exception is CompromisedPasswordException) {
redirectStrategy.sendRedirect(request, response, "/reset-password")
return
}
defaultFailureHandler.onAuthenticationFailure(request, response, exception)
}
}
// end::configuration[]
}

View File

@ -0,0 +1,15 @@
package org.springframework.security.kt.docs.features.authentication.authenticationpasswordstorageargon2
import org.junit.Assert.assertTrue
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder
class Argon2PasswordEncoderUsage {
fun testArgon2PasswordEncoder() {
// tag::argon2PasswordEncoder[]
// Create an encoder with all the defaults
val encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
// end::argon2PasswordEncoder[]
}
}

View File

@ -0,0 +1,15 @@
package org.springframework.security.kt.docs.features.authentication.authenticationpasswordstoragebcrypt
import org.junit.Assert.assertTrue
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
class BCryptPasswordEncoderUsage {
fun testBCryptPasswordEncoder() {
// tag::bcryptPasswordEncoder[]
// Create an encoder with strength 16
val encoder = BCryptPasswordEncoder(16)
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
// end::bcryptPasswordEncoder[]
}
}

View File

@ -0,0 +1,36 @@
package org.springframework.security.kt.docs.features.authentication.authenticationpasswordstoragedepgettingstarted
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
class WithDefaultPasswordEncoderUsage {
fun createSingleUser(): UserDetails {
// tag::createSingleUser[]
val user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("user")
.build()
println(user.password)
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
// end::createSingleUser[]
return user
}
fun createMultipleUsers(): List<UserDetails> {
// tag::createMultipleUsers[]
val users = User.withDefaultPasswordEncoder()
val user = users
.username("user")
.password("password")
.roles("USER")
.build()
val admin = users
.username("admin")
.password("password")
.roles("USER", "ADMIN")
.build()
// end::createMultipleUsers[]
return listOf(user, admin)
}
}

View File

@ -0,0 +1,39 @@
package org.springframework.security.kt.docs.features.authentication.authenticationpasswordstoragedpe
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.factory.PasswordEncoderFactories
import org.springframework.security.crypto.password.DelegatingPasswordEncoder
import org.springframework.security.crypto.password.NoOpPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder
import org.springframework.security.crypto.password.StandardPasswordEncoder
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder
class DelegatingPasswordEncoderUsage {
fun defaultDelegatingPasswordEncoder(): PasswordEncoder {
// tag::createDefaultPasswordEncoder[]
val passwordEncoder: PasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder()
// end::createDefaultPasswordEncoder[]
return passwordEncoder
}
fun customDelegatingPasswordEncoder(): PasswordEncoder {
// tag::createCustomPasswordEncoder[]
val idForEncode = "bcrypt"
val encoders: MutableMap<String, PasswordEncoder> = mutableMapOf()
encoders[idForEncode] = BCryptPasswordEncoder()
encoders["noop"] = NoOpPasswordEncoder.getInstance()
encoders["pbkdf2"] = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5()
encoders["pbkdf2@SpringSecurity_v5_8"] = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()
encoders["scrypt"] = SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1()
encoders["scrypt@SpringSecurity_v5_8"] = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8()
encoders["argon2"] = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2()
encoders["argon2@SpringSecurity_v5_8"] = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()
encoders["sha256"] = StandardPasswordEncoder()
val passwordEncoder: PasswordEncoder = DelegatingPasswordEncoder(idForEncode, encoders)
// end::createCustomPasswordEncoder[]
return passwordEncoder
}
}

View File

@ -0,0 +1,15 @@
package org.springframework.security.kt.docs.features.authentication.authenticationpasswordstoragepbkdf2
import org.junit.Assert.assertTrue
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder
class Pbkdf2PasswordEncoderUsage {
fun testPbkdf2PasswordEncoder() {
// tag::pbkdf2PasswordEncoder[]
// Create an encoder with all the defaults
val encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
// end::pbkdf2PasswordEncoder[]
}
}

View File

@ -0,0 +1,15 @@
package org.springframework.security.kt.docs.features.authentication.authenticationpasswordstoragescrypt
import org.junit.Assert.assertTrue
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder
class SCryptPasswordEncoderUsage {
fun testSCryptPasswordEncoder() {
// tag::sCryptPasswordEncoder[]
// Create an encoder with all the defaults
val encoder = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
// end::sCryptPasswordEncoder[]
}
}