Skip to content

Commit

Permalink
Merge branch '6.3.x'
Browse files Browse the repository at this point in the history
Closes gh-15306
  • Loading branch information
marcusdacoregio committed Jun 26, 2024
2 parents 902aff4 + e16ce57 commit dd74722
Showing 1 changed file with 44 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,11 @@ To facilitate that, Spring Security provides integration with the https://haveib

You can either use the `CompromisedPasswordChecker` API by yourself or, if you are using xref:servlet/authentication/passwords/dao-authentication-provider.adoc[the `DaoAuthenticationProvider]` via xref:servlet/authentication/passwords/index.adoc[Spring Security authentication mechanisms], you can provide a `CompromisedPasswordChecker` bean, and it will be automatically picked up by Spring Security configuration.

.Using CompromisedPasswordChecker as a bean
By doing that, when you try to authenticate via Form Login using a weak password, let's say `123456`, you will receive a 401 or be redirected to the `/login?error` page (depending on your user-agent).
However, just a 401 or the redirect is not so useful in that case, it will cause some confusion because the user provided the right password and still was not allowed to log in.
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::
Expand All @@ -615,15 +619,35 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.httpBasic(withDefaults());
.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::
Expand All @@ -636,8 +660,9 @@ open fun filterChain(http:HttpSecurity): SecurityFilterChain {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
formLogin {}
httpBasic {}
formLogin {
failureHandler = CompromisedPasswordAuthenticationFailureHandler()
}
}
return http.build()
}
Expand All @@ -646,44 +671,22 @@ open fun filterChain(http:HttpSecurity): SecurityFilterChain {
open fun compromisedPasswordChecker(): CompromisedPasswordChecker {
return HaveIBeenPwnedRestApiPasswordChecker()
}
----
======

By doing that, when you try to authenticate via HTTP Basic or Form Login using a weak password, let's say `123456`, you will receive a 401 response status code.
However, just a 401 is not so useful in that case, it will cause some confusion because the user provided the right password and still was not allowed to log in.
In such cases, you can handle the `CompromisedPasswordException` to perform your desired logic, like redirecting the user-agent to `/reset-password`, for example:

[tabs]
======
Java::
+
[source,java,role="primary"]
----
@ControllerAdvice
public class MyControllerAdvice {
@ExceptionHandler(CompromisedPasswordException.class)
public String handleCompromisedPasswordException(CompromisedPasswordException ex, RedirectAttributes attributes) {
attributes.addFlashAttribute("error", ex.message);
return "redirect:/reset-password";
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@ControllerAdvice
class MyControllerAdvice {
@ExceptionHandler(CompromisedPasswordException::class)
fun handleCompromisedPasswordException(ex: CompromisedPasswordException, attributes: RedirectAttributes): RedirectView {
attributes.addFlashAttribute("error", ex.message)
return RedirectView("/reset-password")
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)
}
}
----
======

0 comments on commit dd74722

Please sign in to comment.