diff --git a/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.groovy b/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.groovy deleted file mode 100644 index 2222480b8b..0000000000 --- a/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.groovy +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright 2002-2013 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.security.config.annotation.web.configurers - -import javax.servlet.http.HttpSession - -import org.springframework.context.annotation.Configuration -import org.springframework.mock.web.MockFilterChain -import org.springframework.mock.web.MockHttpServletRequest -import org.springframework.mock.web.MockHttpServletResponse -import org.springframework.security.config.annotation.AnyObjectPostProcessor -import org.springframework.security.config.annotation.BaseSpringSpec -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.BaseWebConfig; -import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer; -import org.springframework.security.web.FilterChainProxy -import org.springframework.security.web.access.ExceptionTranslationFilter; -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter -import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler -import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter - -/** - * Tests to verify that {@link DefaultLoginPageConfigurer} works - * - * @author Rob Winch - * - */ -public class DefaultLoginPageConfigurerTests extends BaseSpringSpec { - def "http/form-login default login generating page"() { - setup: - loadConfig(DefaultLoginPageConfig) - when: - springSecurityFilterChain.doFilter(request,response,chain) - then: - findFilter(DefaultLoginPageGeneratingFilter) - response.getRedirectedUrl() == "http://localhost/login" - when: "request the login page" - super.setup() - request.requestURI = "/login" - springSecurityFilterChain.doFilter(request,response,chain) - then: - response.getContentAsString() == """ - - - - - - - Please sign in - - - - -
-
- -

- - -

-

- - -

- - -
-
-""" - when: "fail to log in" - super.setup() - request.servletPath = "/login" - request.method = "POST" - springSecurityFilterChain.doFilter(request,response,chain) - then: "sent to login error page" - response.getRedirectedUrl() == "/login?error" - when: "request the error page" - HttpSession session = request.session - super.setup() - request.session = session - request.requestURI = "/login" - request.queryString = "error" - springSecurityFilterChain.doFilter(request,response,chain) - then: - response.getContentAsString() == """ - - - - - - - Please sign in - - - - -
-
- -

- - -

-

- - -

- - -
-
-""" - when: "login success" - super.setup() - request.servletPath = "/login" - request.method = "POST" - request.parameters.username = ["user"] as String[] - request.parameters.password = ["password"] as String[] - springSecurityFilterChain.doFilter(request,response,chain) - then: "sent to default succes page" - response.getRedirectedUrl() == "/" - } - - def "logout success renders"() { - setup: - loadConfig(DefaultLoginPageConfig) - when: "logout success" - request.requestURI = "/login" - request.queryString = "logout" - request.method = "GET" - springSecurityFilterChain.doFilter(request,response,chain) - then: "sent to default success page" - response.getContentAsString() == """ - - - - - - - Please sign in - - - - -
-
- -

- - -

-

- - -

- - -
-
-""" - } - - @Configuration - static class DefaultLoginPageConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - } - } - - def "custom logout success handler prevents rendering"() { - setup: - loadConfig(DefaultLoginPageCustomLogoutSuccessHandlerConfig) - when: "logout success" - request.requestURI = "/login" - request.queryString = "logout" - request.method = "GET" - springSecurityFilterChain.doFilter(request,response,chain) - then: "default success page is NOT rendered (application is in charge of it)" - response.getContentAsString() == "" - } - - @Configuration - static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .logout() - .logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler()) - .and() - .formLogin() - } - } - - def "custom logout success url prevents rendering"() { - setup: - loadConfig(DefaultLoginPageCustomLogoutConfig) - when: "logout success" - request.requestURI = "/login" - request.queryString = "logout" - request.method = "GET" - springSecurityFilterChain.doFilter(request,response,chain) - then: "default success page is NOT rendered (application is in charge of it)" - response.getContentAsString() == "" - } - - @Configuration - static class DefaultLoginPageCustomLogoutConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .logout() - .logoutSuccessUrl("/login?logout") - .and() - .formLogin() - } - } - - def "http/form-login default login with remember me"() { - setup: - loadConfig(DefaultLoginPageWithRememberMeConfig) - when: "request the login page" - super.setup() - request.requestURI = "/login" - springSecurityFilterChain.doFilter(request,response,chain) - then: - response.getContentAsString() == """ - - - - - - - Please sign in - - - - -
-
- -

- - -

-

- - -

-

Remember me on this computer.

- - -
-
-""" - } - - @Configuration - static class DefaultLoginPageWithRememberMeConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe() - } - } - - def "http/form-login default login with openid"() { - setup: - loadConfig(DefaultLoginPageWithOpenIDConfig) - when: "request the login page" - request.requestURI = "/login" - springSecurityFilterChain.doFilter(request,response,chain) - then: - response.getContentAsString() == """ - - - - - - - Please sign in - - - - -
-
- -

- - -

- - -
-
-""" - } - - @Configuration - static class DefaultLoginPageWithOpenIDConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .openidLogin() - } - } - - def "http/form-login default login with openid, form login, and rememberme"() { - setup: - loadConfig(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig) - when: "request the login page" - request.requestURI = "/login" - springSecurityFilterChain.doFilter(request,response,chain) - then: - response.getContentAsString() == """ - - - - - - - Please sign in - - - - -
-
- -

- - -

-

- - -

-

Remember me on this computer.

- - -
-
- -

- - -

-

Remember me on this computer.

- - -
-
-""" - } - - @Configuration - static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .rememberMe() - .and() - .formLogin() - .and() - .openidLogin() - } - } - - def "default login with custom AuthenticationEntryPoint"() { - when: - loadConfig(DefaultLoginWithCustomAuthenticationEntryPointConfig) - then: - !findFilter(DefaultLoginPageGeneratingFilter) - } - - @Configuration - static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends BaseWebConfig { - @Override - protected void configure(HttpSecurity http) { - http - .exceptionHandling() - .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) - .and() - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - } - } - - def "DefaultLoginPage ObjectPostProcessor"() { - setup: - AnyObjectPostProcessor objectPostProcessor = Mock() - when: - HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:]) - DefaultLoginPageConfigurer defaultLoginConfig = new DefaultLoginPageConfigurer([builder:http]) - defaultLoginConfig.addObjectPostProcessor(objectPostProcessor) - http - // must set builder manually due to groovy not selecting correct method - .apply(defaultLoginConfig).and() - .exceptionHandling() - .and() - .formLogin() - .and() - .build() - - then: "DefaultLoginPageGeneratingFilter is registered with LifecycleManager" - 1 * objectPostProcessor.postProcess(_ as DefaultLoginPageGeneratingFilter) >> {DefaultLoginPageGeneratingFilter o -> o} - 1 * objectPostProcessor.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o} - 1 * objectPostProcessor.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o} - 1 * objectPostProcessor.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o} - } -} 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 new file mode 100644 index 0000000000..0bd6e0417f --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java @@ -0,0 +1,561 @@ +/* + * Copyright 2002-2019 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.config.annotation.web.configurers; + +import org.junit.Rule; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.security.config.annotation.ObjectPostProcessor; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.test.SpringTestRule; +import org.springframework.security.core.userdetails.PasswordEncodedUser; +import org.springframework.security.web.FilterChainProxy; +import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; +import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.security.web.csrf.DefaultCsrfToken; +import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +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.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +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; + +/** + * Tests for {@link DefaultLoginPageConfigurer} + * + * @author Rob Winch + * @author Eleftheria Stein + */ +public class DefaultLoginPageConfigurerTests { + + @Rule + public final SpringTestRule spring = new SpringTestRule(); + + @Autowired + MockMvc mvc; + + @Test + public void getWhenFormLoginEnabledThenRedirectsToLoginPage() throws Exception { + this.spring.register(DefaultLoginPageConfig.class).autowire(); + + this.mvc.perform(get("/")) + .andExpect(redirectedUrl("http://localhost/login")); + } + + @Test + public void loginPageThenDefaultLoginPageIsRendered() throws Exception { + this.spring.register(DefaultLoginPageConfig.class).autowire(); + CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); + String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); + + this.mvc.perform(get("/login") + .sessionAttr(csrfAttributeName, csrfToken)) + .andExpect(content().string( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Please sign in\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + "" + )); + } + + @Test + public void loginWhenNoCredentialsThenRedirectedToLoginPageWithError() throws Exception { + this.spring.register(DefaultLoginPageConfig.class).autowire(); + + this.mvc.perform(post("/login") + .with(csrf())) + .andExpect(redirectedUrl("/login?error")); + } + + @Test + public void loginPageWhenErrorThenDefaultLoginPageWithError() throws Exception { + this.spring.register(DefaultLoginPageConfig.class).autowire(); + CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); + String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); + + MvcResult mvcResult = this.mvc.perform(post("/login") + .with(csrf())) + .andReturn(); + + this.mvc.perform(get("/login?error") + .session((MockHttpSession) mvcResult.getRequest().getSession()) + .sessionAttr(csrfAttributeName, csrfToken)) + .andExpect(content().string( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Please sign in\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "
Bad credentials

\n" + + " \n" + + " \n" + + "

\n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + "" + )); + } + + @Test + public void loginWhenValidCredentialsThenRedirectsToDefaultSuccessPage() throws Exception { + this.spring.register(DefaultLoginPageConfig.class).autowire(); + + this.mvc.perform(post("/login") + .with(csrf()) + .param("username", "user") + .param("password", "password")) + .andExpect(redirectedUrl("/")); + } + + @Test + public void loginPageWhenLoggedOutThenDefaultLoginPageWithLogoutMessage() throws Exception { + this.spring.register(DefaultLoginPageConfig.class).autowire(); + CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); + String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); + + this.mvc.perform(get("/login?logout") + .sessionAttr(csrfAttributeName, csrfToken)) + .andExpect(content().string( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Please sign in\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "
You have been signed out

\n" + + " \n" + + " \n" + + "

\n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + "" + )); + } + + @EnableWebSecurity + static class DefaultLoginPageConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .formLogin(); + // @formatter:on + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication() + .withUser(PasswordEncodedUser.user()); + // @formatter:on + } + } + + @Test + public void loginPageWhenLoggedOutAndCustomLogoutSuccessHandlerThenDoesNotRenderLoginPage() throws Exception { + this.spring.register(DefaultLoginPageCustomLogoutSuccessHandlerConfig.class).autowire(); + + this.mvc.perform(get("/login?logout")) + .andExpect(content().string("")); + } + + + @EnableWebSecurity + static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .logout() + .logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler()) + .and() + .formLogin(); + // @formatter:on + } + } + + @Test + public void loginPageWhenLoggedOutAndCustomLogoutSuccessUrlThenDoesNotRenderLoginPage() throws Exception { + this.spring.register(DefaultLoginPageCustomLogoutSuccessUrlConfig.class).autowire(); + + this.mvc.perform(get("/login?logout")) + .andExpect(content().string("")); + } + + @EnableWebSecurity + static class DefaultLoginPageCustomLogoutSuccessUrlConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .logout() + .logoutSuccessUrl("/login?logout") + .and() + .formLogin(); + // @formatter:on + } + } + + @Test + public void loginPageWhenRememberConfigureThenDefaultLoginPageWithRememberMeCheckbox() throws Exception { + this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire(); + CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); + String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); + + this.mvc.perform(get("/login") + .sessionAttr(csrfAttributeName, csrfToken)) + .andExpect(content().string( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Please sign in\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "

Remember me on this computer.

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + "" + )); + } + + @EnableWebSecurity + static class DefaultLoginPageWithRememberMeConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .formLogin() + .and() + .rememberMe(); + // @formatter:on + } + } + + @Test + public void loginPageWhenOpenIdLoginConfiguredThenOpedIdLoginPage() throws Exception { + this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire(); + + CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); + String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); + + this.mvc.perform(get("/login") + .sessionAttr(csrfAttributeName, csrfToken)) + .andExpect(content().string( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Please sign in\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + "" + )); + } + + @EnableWebSecurity + static class DefaultLoginPageWithOpenIDConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .openidLogin(); + // @formatter:on + } + } + + @Test + public void loginPageWhenOpenIdLoginAndFormLoginAndRememberMeConfiguredThenOpedIdLoginPage() throws Exception { + this.spring.register(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig.class).autowire(); + CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); + String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); + + this.mvc.perform(get("/login") + .sessionAttr(csrfAttributeName, csrfToken)) + .andExpect(content().string( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Please sign in\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "

Remember me on this computer.

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "

\n" + + " \n" + + " \n" + + "

\n" + + "

Remember me on this computer.

\n" + + "\n" + + " \n" + + "
\n" + + "
\n" + + "" + )); + } + + @EnableWebSecurity + static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .rememberMe() + .and() + .formLogin() + .and() + .openidLogin(); + // @formatter:on + } + } + + @Test + public void configureWhenAuthenticationEntryPointThenNoDefaultLoginPageGeneratingFilter() { + this.spring.register(DefaultLoginWithCustomAuthenticationEntryPointConfig.class).autowire(); + + FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class); + assertThat(filterChain.getFilterChains().get(0).getFilters().stream() + .filter(filter -> filter.getClass().isAssignableFrom(DefaultLoginPageGeneratingFilter.class)) + .count()) + .isZero(); + } + + @EnableWebSecurity + static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .exceptionHandling() + .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) + .and() + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .formLogin(); + // @formatter:on + } + } + + @Test + public void configureWhenRegisteringObjectPostProcessorThenInvokedOnDefaultLoginPageGeneratingFilter() { + ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class); + this.spring.register(ObjectPostProcessorConfig.class).autowire(); + + verify(ObjectPostProcessorConfig.objectPostProcessor) + .postProcess(any(DefaultLoginPageGeneratingFilter.class)); + } + + @Test + public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() { + ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class); + this.spring.register(ObjectPostProcessorConfig.class).autowire(); + + verify(ObjectPostProcessorConfig.objectPostProcessor) + .postProcess(any(UsernamePasswordAuthenticationFilter.class)); + } + + @Test + public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() { + ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class); + this.spring.register(ObjectPostProcessorConfig.class).autowire(); + + verify(ObjectPostProcessorConfig.objectPostProcessor) + .postProcess(any(LoginUrlAuthenticationEntryPoint.class)); + } + + @Test + public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() { + ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class); + this.spring.register(ObjectPostProcessorConfig.class).autowire(); + + verify(ObjectPostProcessorConfig.objectPostProcessor) + .postProcess(any(ExceptionTranslationFilter.class)); + } + + @EnableWebSecurity + static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter { + static ObjectPostProcessor objectPostProcessor; + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .exceptionHandling() + .and() + .formLogin(); + // @formatter:on + } + + @Bean + static ObjectPostProcessor objectPostProcessor() { + return objectPostProcessor; + } + } + + static class ReflectingObjectPostProcessor implements ObjectPostProcessor { + @Override + public O postProcess(O object) { + return object; + } + } +}