Skip to content

Commit

Permalink
Update credential erasure examples
Browse files Browse the repository at this point in the history
Closes gh-15683
  • Loading branch information
sjohnr committed Sep 13, 2024
1 parent a0e6c17 commit 0a4eb0f
Showing 1 changed file with 81 additions and 91 deletions.
172 changes: 81 additions & 91 deletions docs/modules/ROOT/pages/servlet/authentication/passwords/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,74 @@ Normally, Spring Security builds an `AuthenticationManager` internally composed
In certain cases, it may still be desired to customize the instance of `AuthenticationManager` used by Spring Security.
For example, you may need to simply disable xref:servlet/authentication/architecture.adoc#servlet-authentication-providermanager-erasing-credentials[credential erasure] for cached users.

The recommended way to do this is to simply publish your own `AuthenticationManager` bean, and Spring Security will use it.
You can publish an `AuthenticationManager` using the following configuration:
To do this, you can take advantage of the fact that the `AuthenticationManagerBuilder` used to build Spring Security's global `AuthenticationManager` is published as a bean.
You can configure the builder as follows:

.Configure global `AuthenticationManagerBuilder`
[tabs]
=====
Java::
+
[source,java,role="primary"]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// ...
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
// Return a UserDetailsService that caches users
// ...
}
@Autowired
public void configure(AuthenticationManagerBuilder builder) {
builder.eraseCredentials(false);
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
import org.springframework.security.config.annotation.web.invoke
.Publish `AuthenticationManager` bean for Spring Security
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
// ...
return http.build()
}
@Bean
fun userDetailsService(): UserDetailsService {
// Return a UserDetailsService that caches users
// ...
}
@Autowired
fun configure(builder: AuthenticationManagerBuilder) {
builder.eraseCredentials(false)
}
}
----
=====

Alternatively, you may configure a local `AuthenticationManager` to override the global one.

.Configure local `AuthenticationManager` for Spring Security
[tabs]
=====
Java::
Expand All @@ -344,31 +408,27 @@ public class SecurityConfig {
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
.formLogin(Customizer.withDefaults())
.authenticationManager(authenticationManager());
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
private AuthenticationManager authenticationManager() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
ProviderManager providerManager = new ProviderManager(authenticationProvider);
providerManager.setEraseCredentialsAfterAuthentication(false);
return providerManager;
}
@Bean
public UserDetailsService userDetailsService() {
private UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
Expand All @@ -378,8 +438,7 @@ public class SecurityConfig {
return new InMemoryUserDetailsManager(userDetails);
}
@Bean
public PasswordEncoder passwordEncoder() {
private PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
Expand All @@ -390,8 +449,7 @@ XML::
+
[source,xml,role="secondary"]
----
<http>
<intercept-url pattern="/login" access="permitAll"/>
<http authentication-manager-ref="authenticationManager">
<intercept-url pattern="/**" access="authenticated"/>
<form-login />
<http-basic />
Expand Down Expand Up @@ -431,32 +489,29 @@ class SecurityConfig {
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize("/login", permitAll)
authorize(anyRequest, authenticated)
}
formLogin { }
httpBasic { }
authenticationManager = authenticationManager()
}
return http.build()
}
@Bean
fun authenticationManager(
userDetailsService: UserDetailsService,
passwordEncoder: PasswordEncoder): AuthenticationManager {
fun authenticationManager(): AuthenticationManager {
val authenticationProvider = DaoAuthenticationProvider()
authenticationProvider.setUserDetailsService(userDetailsService)
authenticationProvider.setPasswordEncoder(passwordEncoder)
authenticationProvider.setUserDetailsService(userDetailsService())
authenticationProvider.setPasswordEncoder(passwordEncoder())
val providerManager = ProviderManager(authenticationProvider)
providerManager.eraseCredentialsAfterAuthentication = false
return providerManager
}
@Bean
fun userDetailsService(): UserDetailsService {
private fun userDetailsService(): UserDetailsService {
val user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
Expand All @@ -466,76 +521,11 @@ class SecurityConfig {
return InMemoryUserDetailsManager(user)
}
@Bean
fun passwordEncoder(): PasswordEncoder {
private fun passwordEncoder(): PasswordEncoder {
return PasswordEncoderFactories.createDelegatingPasswordEncoder()
}
}
----
=====

Alternatively, you can take advantage of the fact that the `AuthenticationManagerBuilder` used to build Spring Security's global `AuthenticationManager` is published as a bean.
You can configure the builder as follows:

.Configure global `AuthenticationManagerBuilder`
[tabs]
=====
Java::
+
[source,java,role="primary"]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// ...
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
// Return a UserDetailsService that caches users
// ...
}
@Autowired
public void configure(AuthenticationManagerBuilder builder) {
builder.eraseCredentials(false);
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
// ...
return http.build()
}
@Bean
fun userDetailsService(): UserDetailsService {
// Return a UserDetailsService that caches users
// ...
}
@Autowired
fun configure(builder: AuthenticationManagerBuilder) {
builder.eraseCredentials(false)
}
}
----
=====

0 comments on commit 0a4eb0f

Please sign in to comment.