diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java index bf144dc56c..95bea02fcf 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,7 +97,10 @@ public final class DefaultLoginPageConfigurer> if (this.loginPageGeneratingFilter.isEnabled() && authenticationEntryPoint == null) { this.loginPageGeneratingFilter = postProcess(this.loginPageGeneratingFilter); http.addFilter(this.loginPageGeneratingFilter); - http.addFilter(this.logoutPageGeneratingFilter); + LogoutConfigurer logoutConfigurer = http.getConfigurer(LogoutConfigurer.class); + if (logoutConfigurer != null) { + http.addFilter(this.logoutPageGeneratingFilter); + } } } 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 aa492bf276..585a523acd 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 @@ -2229,7 +2229,10 @@ public class ServerHttpSecurity { } if (loginPage != null) { http.addFilterAt(loginPage, SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING); - http.addFilterAt(new LogoutPageGeneratingWebFilter(), SecurityWebFiltersOrder.LOGOUT_PAGE_GENERATING); + if (http.logout != null) { + http.addFilterAt(new LogoutPageGeneratingWebFilter(), + SecurityWebFiltersOrder.LOGOUT_PAGE_GENERATING); + } } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java index 5b18272caa..ab373dcaff 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,11 +46,14 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * Tests for {@link DefaultLoginPageConfigurer} @@ -375,6 +378,18 @@ public class DefaultLoginPageConfigurerTests { .isZero(); } + @Test + public void formLoginWhenLogoutEnabledThenCreatesDefaultLogoutPage() throws Exception { + this.spring.register(DefaultLogoutPageConfig.class).autowire(); + this.mvc.perform(get("/logout").with(user("user"))).andExpect(status().isOk()); + } + + @Test + public void formLoginWhenLogoutDisabledThenDefaultLogoutPageDoesNotExist() throws Exception { + this.spring.register(LogoutDisabledConfig.class).autowire(); + this.mvc.perform(get("/logout").with(user("user"))).andExpect(status().isNotFound()); + } + @EnableWebSecurity static class DefaultLoginPageConfig extends WebSecurityConfigurerAdapter { @@ -533,6 +548,41 @@ public class DefaultLoginPageConfigurerTests { } + @EnableWebSecurity + static class DefaultLogoutPageConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests((authorize) -> authorize + .anyRequest().authenticated() + ) + .formLogin(withDefaults()); + // @formatter:on + } + + } + + @EnableWebSecurity + static class LogoutDisabledConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests((authorize) -> authorize + .anyRequest().authenticated() + ) + .formLogin(withDefaults()) + .logout((logout) -> logout + .disable() + ); + // @formatter:on + } + + } + static class ReflectingObjectPostProcessor implements ObjectPostProcessor { @Override diff --git a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java index 1149e97c34..d00c38a629 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,10 @@ import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.config.Customizer.withDefaults; /** @@ -146,7 +149,7 @@ public class LogoutSpecTests { } @Test - public void logoutWhenDisabledThenPostToLogoutDoesNothing() { + public void logoutWhenDisabledThenDefaultLogoutPageDoesNotExist() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http .authorizeExchange() @@ -156,7 +159,7 @@ public class LogoutSpecTests { .logout().disable() .build(); WebTestClient webTestClient = WebTestClientBuilder - .bindToWebFilters(securityWebFilter) + .bindToControllerAndWebFilters(HomeController.class, securityWebFilter) .build(); WebDriver driver = WebTestClientHtmlUnitDriverBuilder .webTestClientSetup(webTestClient) @@ -171,8 +174,8 @@ public class LogoutSpecTests { .submit(FormLoginTests.HomePage.class); // @formatter:on homePage.assertAt(); - FormLoginTests.DefaultLogoutPage.to(driver).assertAt().logout(); - homePage.assertAt(); + FormLoginTests.DefaultLogoutPage.to(driver); + assertThat(driver.getPageSource()).isEmpty(); } @Test @@ -208,4 +211,14 @@ public class LogoutSpecTests { FormLoginTests.HomePage.to(driver, FormLoginTests.DefaultLoginPage.class).assertAt(); } + @RestController + public static class HomeController { + + @GetMapping("/") + public String ok() { + return "ok"; + } + + } + }