From fcb119b94e87050bd1634a28b3730553a5e23cea Mon Sep 17 00:00:00 2001 From: Eleftheria Stein Date: Tue, 2 Jul 2019 14:56:08 -0400 Subject: [PATCH] Allow configuration of remember me through nested builder Issue: gh-5557 --- .../annotation/web/builders/HttpSecurity.java | 37 +++++++++ .../RememberMeConfigurerTests.java | 78 +++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 3bd002b5e8..b8d607d254 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -934,6 +934,43 @@ public final class HttpSecurity extends return getOrApply(new RememberMeConfigurer<>()); } + /** + * Allows configuring of Remember Me authentication. + * + *

Example Configuration

+ * + * The following configuration demonstrates how to allow token based remember me + * authentication. Upon authenticating if the HTTP parameter named "remember-me" + * exists, then the user will be remembered even after their + * {@link javax.servlet.http.HttpSession} expires. + * + *
+	 * @Configuration
+	 * @EnableWebSecurity
+	 * public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {
+	 *
+	 * 	@Override
+	 * 	protected void configure(HttpSecurity http) throws Exception {
+	 * 		http
+	 * 			.authorizeRequests()
+	 * 				.antMatchers("/**").hasRole("USER")
+	 * 				.and()
+	 * 			.formLogin(withDefaults())
+	 * 			.rememberMe(withDefaults());
+	 * 	}
+	 * }
+	 * 
+ * + * @param rememberMeCustomizer the {@link Customizer} to provide more options for + * the {@link RememberMeConfigurer} + * @return the {@link HttpSecurity} for further customizations + * @throws Exception + */ + public HttpSecurity rememberMe(Customizer> rememberMeCustomizer) throws Exception { + rememberMeCustomizer.customize(getOrApply(new RememberMeConfigurer<>())); + return HttpSecurity.this; + } + /** * Allows restricting access based upon the {@link HttpServletRequest} using * diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java index 4c217ee2d9..84c9ec8816 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java @@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +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.httpBasic; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; @@ -299,6 +300,44 @@ public class RememberMeConfigurerTests { } } + + @Test + public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception { + this.spring.register(RememberMeInLambdaConfig.class).autowire(); + + this.mvc.perform(post("/login") + .with(csrf()) + .param("username", "user") + .param("password", "password") + .param("remember-me", "true")) + .andExpect(cookie().exists("remember-me")); + } + + @EnableWebSecurity + static class RememberMeInLambdaConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .formLogin(withDefaults()) + .rememberMe(withDefaults()); + // @formatter:on + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication() + .withUser(PasswordEncodedUser.user()); + // @formatter:on + } + } + @Test public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception { this.spring.register(RememberMeCookieDomainConfig.class).autowire(); @@ -337,6 +376,45 @@ public class RememberMeConfigurerTests { } } + @Test + public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception { + this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire(); + + this.mvc.perform(post("/login") + .with(csrf()) + .param("username", "user") + .param("password", "password") + .param("remember-me", "true")) + .andExpect(cookie().exists("remember-me")) + .andExpect(cookie().domain("remember-me", "spring.io")); + } + + @EnableWebSecurity + static class RememberMeCookieDomainInLambdaConfig extends WebSecurityConfigurerAdapter { + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .formLogin(withDefaults()) + .rememberMe(rememberMe -> + rememberMe + .rememberMeCookieDomain("spring.io") + ); + // @formatter:on + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication() + .withUser(PasswordEncodedUser.user()); + // @formatter:on + } + } + @Test public void configureWhenRememberMeCookieNameAndRememberMeServicesThenException() { assertThatThrownBy(() -> this.spring.register(RememberMeCookieNameAndRememberMeServicesConfig.class).autowire())