diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index e395752cdd..195555b0d2 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -3050,7 +3050,9 @@ public class ServerHttpSecurity { this.defaultEntryPoint = new RedirectServerAuthenticationEntryPoint(loginPage); this.authenticationEntryPoint = this.defaultEntryPoint; this.requiresAuthenticationMatcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, loginPage); - this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler(loginPage + "?error"); + if (this.authenticationFailureHandler == null) { + this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler(loginPage + "?error"); + } return this; } diff --git a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java index 31c4ac5694..5fcae75750 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java @@ -33,6 +33,7 @@ import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverB import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.WebFilterChainProxy; +import org.springframework.security.web.server.authentication.RedirectServerAuthenticationFailureHandler; import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler; import org.springframework.security.web.server.context.ServerSecurityContextRepository; import org.springframework.security.web.server.csrf.CsrfToken; @@ -213,6 +214,37 @@ public class FormLoginTests { homePage.assertAt(); } + @Test + public void formLoginWhenCustomAuthenticationFailureHandlerThenUsed() { + SecurityWebFilterChain securityWebFilter = this.http + .authorizeExchange() + .pathMatchers("/login", "/failure").permitAll() + .anyExchange().authenticated() + .and() + .formLogin() + .authenticationFailureHandler(new RedirectServerAuthenticationFailureHandler("/failure")) + .and() + .build(); + + WebTestClient webTestClient = WebTestClientBuilder + .bindToWebFilters(securityWebFilter) + .build(); + + WebDriver driver = WebTestClientHtmlUnitDriverBuilder + .webTestClientSetup(webTestClient) + .build(); + + DefaultLoginPage loginPage = HomePage.to(driver, DefaultLoginPage.class) + .assertAt(); + + loginPage.loginForm() + .username("invalid") + .password("invalid") + .submit(HomePage.class); + + assertThat(driver.getCurrentUrl()).endsWith("/failure"); + } + @Test public void authenticationSuccess() { SecurityWebFilterChain securityWebFilter = this.http