diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc index 7377955b6c..dda2a172a5 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc @@ -537,7 +537,7 @@ remember-me.attlist &= attribute services-alias {xsd:token}? remember-me.attlist &= - ## Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS. Defaults to false. + ## Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS (recommended). By default, secure cookies will be used if the request is made on a secure connection. attribute use-secure-cookie {xsd:boolean}? remember-me.attlist &= diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd index 1ba7bb1f43..f1354fa1c1 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd @@ -1172,7 +1172,7 @@ - Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS. Defaults to false. + Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS (recommended). By default, secure cookies will be used if the request is made on a secure connection. diff --git a/docs/manual/src/docbook/appendix-namespace.xml b/docs/manual/src/docbook/appendix-namespace.xml index b3d8040038..2bdfc09194 100644 --- a/docs/manual/src/docbook/appendix-namespace.xml +++ b/docs/manual/src/docbook/appendix-namespace.xml @@ -72,9 +72,9 @@
<literal>jaas-api-provision</literal> - If available, runs the request as the Subject acquired from - the JaasAuthenticationToken which is implemented by - adding a JaasApiIntegrationFilter bean to the stack. + If available, runs the request as the Subject acquired from + the JaasAuthenticationToken which is implemented by + adding a JaasApiIntegrationFilter bean to the stack. Defaults to "false".
@@ -334,7 +334,7 @@ Allows complete control of the RememberMeServices implementation that will be used by the filter. The value should be the id of a bean in the application - context which implements this interface. Should also implement + context which implements this interface. Should also implement LogoutHandler if a logout filter is in use.
@@ -369,6 +369,17 @@ and used automatically by the namespace configuration. If there are multiple instances, you can specify a bean id explicitly using this attribute.
+
+ <literal>use-secure-cookie</literal> + It is recommended that remember-me cookies are only submitted over HTTPS and thus should + be flagged as secure. By default, a secure cookie will be used if the + connection over which the login request is made is secure (as it should be). + If you set this property to false, secure cookies will not be used. + Setting it to true will always set the secure flag on the cookie. + This attribute maps to the useSecureCookie property of + AbstractRememberMeServices. + +
<literal>authentication-success-handler-ref</literal> Sets the authenticationSuccessHandler property on the diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java index ca4c6d0ae0..cbf842874a 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java @@ -56,7 +56,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices, private boolean alwaysRemember; private String key; private int tokenValiditySeconds = TWO_WEEKS_S; - private boolean useSecureCookie = false; + private Boolean useSecureCookie = null; private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); public void afterPropertiesSet() throws Exception { @@ -296,9 +296,6 @@ public abstract class AbstractRememberMeServices implements RememberMeServices, /** * Sets a "cancel cookie" (with maxAge = 0) on the response to disable persistent logins. - * - * @param request - * @param response */ protected void cancelCookie(HttpServletRequest request, HttpServletResponse response) { logger.debug("Cancelling cookie"); @@ -310,7 +307,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices, } /** - * Sets the cookie on the response + * Sets the cookie on the response. + * + * By default a secure cookie will be used if the connection is secure. You can set the {@code useSecureCookie} + * property to {@code false} to override this. If you set it to {@code true}, the cookie will always be flagged + * as secure. * * @param tokens the tokens which will be encoded to make the cookie value. * @param maxAge the value passed to {@link Cookie#setMaxAge(int)} @@ -322,7 +323,13 @@ public abstract class AbstractRememberMeServices implements RememberMeServices, Cookie cookie = new Cookie(cookieName, cookieValue); cookie.setMaxAge(maxAge); cookie.setPath(getCookiePath(request)); - cookie.setSecure(useSecureCookie); + + if (useSecureCookie == null) { + cookie.setSecure(request.isSecure()); + } else { + cookie.setSecure(useSecureCookie); + } + response.addCookie(cookie); } @@ -332,7 +339,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices, } /** - * Implementation of LogoutHandler. Default behaviour is to call cancelCookie(). + * Implementation of {@code LogoutHandler}. Default behaviour is to call {@code cancelCookie()}. */ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { if (logger.isDebugEnabled()) { @@ -395,6 +402,15 @@ public abstract class AbstractRememberMeServices implements RememberMeServices, return tokenValiditySeconds; } + /** + * Whether the cookie should be flagged as secure or not. Secure cookies can only be sent over an HTTPS connection + * and this cannot be accidentally submitted over HTTP where they could be intercepted. + *

+ * By default the cookie will be secure if the request is secure. If you only want to use remember-me over + * HTTPS (recommended) you should set this property to {@code true}. + * + * @param useSecureCookie set to {@code true} to always user secure cookies, {@code false} to disable their use. + */ public void setUseSecureCookie(boolean useSecureCookie) { this.useSecureCookie = useSecureCookie; } diff --git a/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java b/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java index 0d5cf45876..402fcf2cf6 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java @@ -106,7 +106,7 @@ public class AbstractRememberMeServicesTests { request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); // set non-login cookie - request.setCookies(new Cookie[] {new Cookie("mycookie", "cookie")}); + request.setCookies(new Cookie("mycookie", "cookie")); assertNull(services.autoLogin(request, response)); assertNull(response.getCookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY)); } @@ -134,8 +134,7 @@ public class AbstractRememberMeServicesTests { MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletResponse response = new MockHttpServletResponse(); - request.setCookies(new Cookie[] { - new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, "ZZZ")}); + request.setCookies(new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, "ZZZ")); Authentication result = services.autoLogin(request, response); assertNull(result); assertCookieCancelled(response); @@ -147,8 +146,7 @@ public class AbstractRememberMeServicesTests { MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletResponse response = new MockHttpServletResponse(); - request.setCookies(new Cookie[] { - new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, "")}); + request.setCookies(new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, "")); Authentication result = services.autoLogin(request, response); assertNull(result); assertCookieCancelled(response);