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 251c586f3e..2e9212c470 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. @@ -100,7 +100,10 @@ public final class DefaultLoginPageConfigurer> if (loginPageGeneratingFilter.isEnabled() && authenticationEntryPoint == null) { loginPageGeneratingFilter = postProcess(loginPageGeneratingFilter); http.addFilter(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 4f165d91ae..fa24612eb1 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 @@ -3264,7 +3264,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 0bd6e0417f..a37a2e7a83 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. @@ -44,11 +44,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} @@ -217,6 +220,18 @@ public class DefaultLoginPageConfigurerTests { )); } + @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 { @Override @@ -552,6 +567,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 public O postProcess(O object) { 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 723251e4cf..5313064942 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. @@ -25,7 +25,10 @@ import org.springframework.security.web.server.context.WebSessionServerSecurityC import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; +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; /** @@ -167,7 +170,8 @@ public class LogoutSpecTests { } @Test - public void logoutWhenDisabledThenPostToLogoutDoesNothing() { + public void logoutWhenDisabledThenDefaultLogoutPageDoesNotExist() { + // @formatter:off SecurityWebFilterChain securityWebFilter = this.http .authorizeExchange() .anyExchange().authenticated() @@ -177,7 +181,7 @@ public class LogoutSpecTests { .build(); WebTestClient webTestClient = WebTestClientBuilder - .bindToWebFilters(securityWebFilter) + .bindToControllerAndWebFilters(HomeController.class, securityWebFilter) .build(); WebDriver driver = WebTestClientHtmlUnitDriverBuilder @@ -191,15 +195,10 @@ public class LogoutSpecTests { .username("user") .password("password") .submit(FormLoginTests.HomePage.class); - + // @formatter:on homePage.assertAt(); - - FormLoginTests.DefaultLogoutPage.to(driver) - .assertAt() - .logout(); - - homePage - .assertAt(); + FormLoginTests.DefaultLogoutPage.to(driver); + assertThat(driver.getPageSource()).isEmpty(); } @@ -243,4 +242,15 @@ public class LogoutSpecTests { FormLoginTests.HomePage.to(driver, FormLoginTests.DefaultLoginPage.class) .assertAt(); } + + @RestController + public static class HomeController { + + @GetMapping("/") + public String ok() { + return "ok"; + } + + } + }