Add RememberMeConfigurer set domain

Fixes gh-3408
This commit is contained in:
Eddú Meléndez 2016-02-12 01:38:26 -05:00 committed by Rob Winch
parent ce20cfcb98
commit 41c6a797c3
4 changed files with 80 additions and 3 deletions

View File

@ -74,6 +74,7 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
* </ul> * </ul>
* *
* @author Rob Winch * @author Rob Winch
* @author Eddú Meléndez
* @since 3.2 * @since 3.2
*/ */
public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extends public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extends
@ -84,6 +85,7 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
private LogoutHandler logoutHandler; private LogoutHandler logoutHandler;
private String rememberMeParameter = "remember-me"; private String rememberMeParameter = "remember-me";
private String rememberMeCookieName = "remember-me"; private String rememberMeCookieName = "remember-me";
private String rememberMeCookieDomain;
private PersistentTokenRepository tokenRepository; private PersistentTokenRepository tokenRepository;
private UserDetailsService userDetailsService; private UserDetailsService userDetailsService;
private Integer tokenValiditySeconds; private Integer tokenValiditySeconds;
@ -192,6 +194,18 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
return this; return this;
} }
/**
* The domain name within which the remember me cookie is visible.
*
* @param rememberMeCookieDomain the domain name within which the remember me cookie is visible.
* @return the {@link RememberMeConfigurer} for further customization
* @since 4.1.0
*/
public RememberMeConfigurer<H> rememberMeCookieDomain(String rememberMeCookieDomain) {
this.rememberMeCookieDomain = rememberMeCookieDomain;
return this;
}
/** /**
* Allows control over the destination a remembered user is sent to when they are * Allows control over the destination a remembered user is sent to when they are
* successfully authenticated. By default, the filter will just allow the current * successfully authenticated. By default, the filter will just allow the current
@ -294,6 +308,9 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
http, key); http, key);
tokenRememberMeServices.setParameter(rememberMeParameter); tokenRememberMeServices.setParameter(rememberMeParameter);
tokenRememberMeServices.setCookieName(rememberMeCookieName); tokenRememberMeServices.setCookieName(rememberMeCookieName);
if (rememberMeCookieDomain != null) {
tokenRememberMeServices.setCookieDomain(rememberMeCookieDomain);
}
if (tokenValiditySeconds != null) { if (tokenValiditySeconds != null) {
tokenRememberMeServices.setTokenValiditySeconds(tokenValiditySeconds); tokenRememberMeServices.setTokenValiditySeconds(tokenValiditySeconds);
} }

View File

@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers
import javax.servlet.http.Cookie import javax.servlet.http.Cookie
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse import org.springframework.mock.web.MockHttpServletResponse
@ -28,7 +27,6 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.AnyObjectPostProcessor import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity 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.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
@ -157,6 +155,23 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
response.getRedirectedUrl() == "http://localhost/login" response.getRedirectedUrl() == "http://localhost/login"
} }
def "http/remember-me with cookied domain"() {
setup:
loadConfig(RememberMeCookieDomainConfig)
when:
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
request.parameters.'remember-me' = ["true"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
Cookie rememberMeCookie = getRememberMeCookie()
then: "response contains remember me cookie"
rememberMeCookie != null
rememberMeCookie.domain == "spring.io"
}
@EnableWebSecurity @EnableWebSecurity
static class RememberMeConfig extends WebSecurityConfigurerAdapter { static class RememberMeConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
@ -177,6 +192,27 @@ public class RememberMeConfigurerTests extends BaseSpringSpec {
} }
} }
@EnableWebSecurity
static class RememberMeCookieDomainConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
.rememberMeCookieDomain("spring.io")
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
Cookie createRememberMeCookie() { Cookie createRememberMeCookie() {
MockHttpServletRequest request = new MockHttpServletRequest() MockHttpServletRequest request = new MockHttpServletRequest()
MockHttpServletResponse response = new MockHttpServletResponse() MockHttpServletResponse response = new MockHttpServletResponse()

View File

@ -50,6 +50,7 @@ import org.springframework.util.StringUtils;
* *
* @author Luke Taylor * @author Luke Taylor
* @author Rob Winch * @author Rob Winch
* @author Eddú Meléndez
* @since 2.0 * @since 2.0
*/ */
public abstract class AbstractRememberMeServices implements RememberMeServices, public abstract class AbstractRememberMeServices implements RememberMeServices,
@ -75,6 +76,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource(); private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
private String cookieName = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY; private String cookieName = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
private String cookieDomain;
private String parameter = DEFAULT_PARAMETER; private String parameter = DEFAULT_PARAMETER;
private boolean alwaysRemember; private boolean alwaysRemember;
private String key; private String key;
@ -385,7 +387,9 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
Cookie cookie = new Cookie(cookieName, cookieValue); Cookie cookie = new Cookie(cookieName, cookieValue);
cookie.setMaxAge(maxAge); cookie.setMaxAge(maxAge);
cookie.setPath(getCookiePath(request)); cookie.setPath(getCookiePath(request));
if (cookieDomain != null) {
cookie.setDomain(cookieDomain);
}
if (maxAge < 1) { if (maxAge < 1) {
cookie.setVersion(1); cookie.setVersion(1);
} }
@ -430,6 +434,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
this.cookieName = cookieName; this.cookieName = cookieName;
} }
public void setCookieDomain(String cookieDomain) {
Assert.hasLength(cookieDomain, "Cookie domain cannot be empty or null");
this.cookieDomain = cookieDomain;
}
protected String getCookieName() { protected String getCookieName() {
return cookieName; return cookieName;
} }

View File

@ -420,6 +420,21 @@ public class AbstractRememberMeServicesTests {
assertThat(cookie.getVersion()).isEqualTo(0); assertThat(cookie.getVersion()).isEqualTo(0);
} }
@Test
public void setCookieDomainValue() {
MockRememberMeServices services = new MockRememberMeServices();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
services.setCookieName("mycookiename");
services.setCookieDomain("spring.io");
services.setCookie(new String[] { "mycookie" }, 1000, request, response);
Cookie cookie = response.getCookie("mycookiename");
assertThat(cookie).isNotNull();
assertThat(cookie.getDomain()).isEqualTo("spring.io");
}
private Cookie[] createLoginCookie(String cookieToken) { private Cookie[] createLoginCookie(String cookieToken) {
MockRememberMeServices services = new MockRememberMeServices(uds); MockRememberMeServices services = new MockRememberMeServices(uds);
Cookie cookie = new Cookie( Cookie cookie = new Cookie(