Polish SpringSessionRememberMeServices
* Move to ~.security.web.authentication package * Add documentation * Use getBeanNamesForType to avoid eager bean initialization * Remove rememberMeCookieMaxAge because it must be Integer.MAX_VALUE since cookie is only written at the creation of the session * Change from parameter to rememberMeParameterName Issue gh-189
This commit is contained in:
@@ -32,6 +32,7 @@ dependencies {
|
||||
"org.springframework.data:spring-data-gemfire:$springDataGemFireVersion",
|
||||
"org.springframework.data:spring-data-redis:$springDataRedisVersion",
|
||||
"org.springframework.data:spring-data-gemfire:$springDataGemFireVersion",
|
||||
"org.springframework:spring-webmvc:${springVersion}",
|
||||
"org.springframework:spring-websocket:${springVersion}",
|
||||
"org.springframework:spring-messaging:${springVersion}",
|
||||
"org.springframework:spring-jdbc:${springVersion}",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
= Spring Session
|
||||
Rob Winch, Vedran Pavić, Jakub Kubrynski
|
||||
:doctype: book
|
||||
@@ -518,17 +519,49 @@ Before using WebSocket integration, you should be sure that you have <<httpsessi
|
||||
|
||||
include::guides/websocket.adoc[tags=config,leveloffset=+2]
|
||||
|
||||
[[spring-security-concurrent-sessions]]
|
||||
[[spring-security]]
|
||||
== Spring Security Integration
|
||||
|
||||
Spring Session provides integration with Spring Security.
|
||||
|
||||
[[spring-security-rememberme]]
|
||||
=== Spring Security Remember-Me Support
|
||||
|
||||
Spring Session provides integration with http://docs.spring.io/spring-security/site/docs/4.2.x/reference/htmlsingle/#remember-me[Spring Security's Remember-Me Authentication].
|
||||
The support will:
|
||||
|
||||
* Change the session expiration length
|
||||
* Ensure the session cookie expires at `Integer.MAX_VALUE`.
|
||||
The cookie expiration is set to the largest possible value because the cookie is only set when the session is created.
|
||||
If it were set to the same value as the session expiration, then the session would get renewed when the user used it but the cookie expiration would not be updated causing the expiration to be fixed.
|
||||
|
||||
To configure Spring Session with Spring Security in Java Configuration use the following as a guide:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{docs-test-dir}docs/security/RememberMeSecurityConfiguration.java[tags=http-rememberme]
|
||||
}
|
||||
|
||||
include::{docs-test-dir}docs/security/RememberMeSecurityConfiguration.java[tags=rememberme-bean]
|
||||
----
|
||||
|
||||
An XML based configuration would look something like this:
|
||||
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{docs-test-resources-dir}docs/security/RememberMeSecurityConfigurationXmlTests-context.xml[tags=config]
|
||||
----
|
||||
|
||||
|
||||
[[spring-security-concurrent-sessions]]
|
||||
=== Spring Security Concurrent Session Control
|
||||
|
||||
|
||||
Spring Session provides integration with Spring Security to support its concurrent session control.
|
||||
This allows limiting the number of active sessions that a single user can have concurrently, but unlike the default
|
||||
Spring Security support this will also work in a clustered environment. This is done by providing a custom
|
||||
implementation of Spring Security's `SessionRegistry` interface.
|
||||
|
||||
[[spring-security-concurrent-sessions-how]]
|
||||
=== Configuring Spring Security's concurrent session management
|
||||
|
||||
When using Spring Security's Java config DSL, you can configure the custom `SessionRegistry` through the
|
||||
`SessionManagementConfigurer` like this:
|
||||
[source,java,indent=0]
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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 docs.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
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.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
|
||||
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
@EnableSpringHttpSession
|
||||
public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
// @formatter:off
|
||||
// tag::http-rememberme[]
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ... additional configuration ...
|
||||
.rememberMe()
|
||||
.rememberMeServices(rememberMeServices());
|
||||
// end::http-rememberme[]
|
||||
|
||||
http
|
||||
.formLogin().and()
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
// tag::rememberme-bean[]
|
||||
@Bean
|
||||
RememberMeServices rememberMeServices() {
|
||||
SpringSessionRememberMeServices rememberMeServices =
|
||||
new SpringSessionRememberMeServices();
|
||||
// optionally customize
|
||||
rememberMeServices.setAlwaysRemember(true);
|
||||
return rememberMeServices;
|
||||
}
|
||||
// end::rememberme-bean[]
|
||||
// @formatter:on
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager userDetailsService() {
|
||||
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager();
|
||||
uds.createUser(
|
||||
User.withUsername("user").password("password").roles("USER").build());
|
||||
return uds;
|
||||
}
|
||||
|
||||
@Bean
|
||||
MapSessionRepository sessionRepository() {
|
||||
return new MapSessionRepository();
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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 docs.security;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = RememberMeSecurityConfiguration.class)
|
||||
@WebAppConfiguration
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class RememberMeSecurityConfigurationTests<T extends ExpiringSession> {
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
SessionRepositoryFilter springSessionRepositoryFilter;
|
||||
@Autowired
|
||||
SessionRepository<T> sessions;
|
||||
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
this.mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup(this.context)
|
||||
.addFilters(this.springSessionRepositoryFilter)
|
||||
.apply(springSecurity())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSpringSessionRememberMeEnabledThenCookieMaxAgeAndSessionExpirationSet()
|
||||
throws Exception {
|
||||
// @formatter:off
|
||||
MvcResult result = this.mockMvc
|
||||
.perform(formLogin())
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
|
||||
Cookie cookie = result.getResponse().getCookie("SESSION");
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions.getSession(cookie.getValue());
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds())
|
||||
.isEqualTo((int) TimeUnit.DAYS.toSeconds(30));
|
||||
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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 docs.security;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
|
||||
/**
|
||||
* @author rwinch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@WebAppConfiguration
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class RememberMeSecurityConfigurationXmlTests<T extends ExpiringSession> {
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
SessionRepositoryFilter springSessionRepositoryFilter;
|
||||
@Autowired
|
||||
SessionRepository<T> sessions;
|
||||
|
||||
MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// @formatter:off
|
||||
this.mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup(this.context)
|
||||
.addFilters(this.springSessionRepositoryFilter)
|
||||
.apply(springSecurity())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSpringSessionRememberMeEnabledThenCookieMaxAgeAndSessionExpirationSet()
|
||||
throws Exception {
|
||||
// @formatter:off
|
||||
MvcResult result = this.mockMvc
|
||||
.perform(formLogin())
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
|
||||
Cookie cookie = result.getResponse().getCookie("SESSION");
|
||||
assertThat(cookie.getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
T session = this.sessions.getSession(cookie.getValue());
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds())
|
||||
.isEqualTo((int) TimeUnit.DAYS.toSeconds(30));
|
||||
|
||||
}
|
||||
}
|
||||
// end::class[]
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<!-- tag::config[] -->
|
||||
<security:http>
|
||||
<!-- ... -->
|
||||
<security:form-login />
|
||||
<security:remember-me services-ref="rememberMeServices"/>
|
||||
</security:http>
|
||||
|
||||
<bean id="rememberMeServices"
|
||||
class="org.springframework.session.security.web.authentication.SpringSessionRememberMeServices"
|
||||
p:alwaysRemember="true"/>
|
||||
<!-- end::config[] -->
|
||||
|
||||
|
||||
<security:user-service>
|
||||
<security:user name="user" password="password" authorities="ROLE_USER"/>
|
||||
</security:user-service>
|
||||
|
||||
<bean class="org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration"/>
|
||||
<bean id="springSessionRepository" class="org.springframework.session.MapSessionRepository"/>
|
||||
</beans>
|
||||
@@ -33,7 +33,7 @@ import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDestroyedEvent;
|
||||
import org.springframework.session.security.SpringSessionRememberMeServices;
|
||||
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
|
||||
import org.springframework.session.web.http.CookieHttpSessionStrategy;
|
||||
import org.springframework.session.web.http.CookieSerializer;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
@@ -42,6 +42,7 @@ import org.springframework.session.web.http.MultiHttpSessionStrategy;
|
||||
import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Configures the basics for setting up Spring Session in a web environment. In order to
|
||||
@@ -138,10 +139,12 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
if (ClassUtils.isPresent("org.springframework.security.web.authentication." +
|
||||
"RememberMeServices", null)) {
|
||||
this.usesSpringSessionRememberMeServices = !applicationContext
|
||||
.getBeansOfType(SpringSessionRememberMeServices.class).isEmpty();
|
||||
if (ClassUtils.isPresent(
|
||||
"org.springframework.security.web.authentication.RememberMeServices",
|
||||
null)) {
|
||||
this.usesSpringSessionRememberMeServices = !ObjectUtils
|
||||
.isEmpty(applicationContext
|
||||
.getBeanNamesForType(SpringSessionRememberMeServices.class));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.security;
|
||||
package org.springframework.session.security.web.authentication;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,8 @@ import org.springframework.util.Assert;
|
||||
* @author Vedran Pavic
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringSessionRememberMeServices implements RememberMeServices {
|
||||
public class SpringSessionRememberMeServices
|
||||
implements RememberMeServices, LogoutHandler {
|
||||
|
||||
/**
|
||||
* Remember-me login request attribute name.
|
||||
@@ -42,13 +44,14 @@ public class SpringSessionRememberMeServices implements RememberMeServices {
|
||||
public static final String REMEMBER_ME_LOGIN_ATTR = SpringSessionRememberMeServices.class
|
||||
.getName() + "REMEMBER_ME_LOGIN_ATTR";
|
||||
|
||||
private static final String DEFAULT_PARAMETER = "remember-me";
|
||||
private static final String DEFAULT_REMEMBERME_PARAMETER = "remember-me";
|
||||
|
||||
private static final int THIRTY_DAYS_SECONDS = 2592000;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SpringSessionRememberMeServices.class);
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(SpringSessionRememberMeServices.class);
|
||||
|
||||
private String parameter = DEFAULT_PARAMETER;
|
||||
private String rememberMeParameterName = DEFAULT_REMEMBERME_PARAMETER;
|
||||
|
||||
private boolean alwaysRemember;
|
||||
|
||||
@@ -59,17 +62,15 @@ public class SpringSessionRememberMeServices implements RememberMeServices {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void loginFail(HttpServletRequest request, HttpServletResponse response) {
|
||||
logger.debug("Interactive login attempt was unsuccessful.");
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
session.invalidate();
|
||||
}
|
||||
public final void loginFail(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
logout(request);
|
||||
}
|
||||
|
||||
public final void loginSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication successfulAuthentication) {
|
||||
if (!this.alwaysRemember && !rememberMeRequested(request, this.parameter)) {
|
||||
public final void loginSuccess(HttpServletRequest request,
|
||||
HttpServletResponse response, Authentication successfulAuthentication) {
|
||||
if (!this.alwaysRemember
|
||||
&& !rememberMeRequested(request, this.rememberMeParameterName)) {
|
||||
logger.debug("Remember-me login not requested.");
|
||||
return;
|
||||
}
|
||||
@@ -96,8 +97,8 @@ public class SpringSessionRememberMeServices implements RememberMeServices {
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Did not send remember-me cookie (principal did not set " +
|
||||
"parameter '" + parameter + "')");
|
||||
logger.debug("Did not send remember-me cookie (principal did not set "
|
||||
+ "parameter '" + parameter + "')");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -106,11 +107,12 @@ public class SpringSessionRememberMeServices implements RememberMeServices {
|
||||
* Set the name of the parameter which should be checked for to see if a remember-me
|
||||
* has been requested during a login request. This should be the same name you assign
|
||||
* to the checkbox in your login form.
|
||||
* @param parameter the request parameter
|
||||
* @param rememberMeParameterName the request parameter
|
||||
*/
|
||||
public void setParameter(String parameter) {
|
||||
Assert.hasText(parameter, "Parameter name cannot be empty or null");
|
||||
this.parameter = parameter;
|
||||
public void setRememberMeParameterName(String rememberMeParameterName) {
|
||||
Assert.hasText(rememberMeParameterName,
|
||||
"rememberMeParameterName cannot be empty or null");
|
||||
this.rememberMeParameterName = rememberMeParameterName;
|
||||
}
|
||||
|
||||
public void setAlwaysRemember(boolean alwaysRemember) {
|
||||
@@ -121,4 +123,16 @@ public class SpringSessionRememberMeServices implements RememberMeServices {
|
||||
this.validitySeconds = validitySeconds;
|
||||
}
|
||||
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) {
|
||||
logout(request);
|
||||
}
|
||||
|
||||
private void logout(HttpServletRequest request) {
|
||||
logger.debug("Interactive login attempt was unsuccessful.");
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
session.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,8 +55,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private String rememberMeRequestAttribute;
|
||||
|
||||
private int rememberMeCookieMaxAge = Integer.MAX_VALUE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -115,9 +113,11 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
if ("".equals(requestedCookieValue)) {
|
||||
sessionCookie.setMaxAge(0);
|
||||
}
|
||||
else if (this.rememberMeRequestAttribute != null &&
|
||||
request.getAttribute(this.rememberMeRequestAttribute) != null) {
|
||||
sessionCookie.setMaxAge(this.rememberMeCookieMaxAge);
|
||||
else if (this.rememberMeRequestAttribute != null
|
||||
&& request.getAttribute(this.rememberMeRequestAttribute) != null) {
|
||||
// the cookie is only written at time of session creation, so we rely on
|
||||
// session expiration rather than cookie expiration if remember me is enabled
|
||||
sessionCookie.setMaxAge(Integer.MAX_VALUE);
|
||||
}
|
||||
else {
|
||||
sessionCookie.setMaxAge(this.cookieMaxAge);
|
||||
@@ -209,10 +209,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
* @param cookieMaxAge the maxAge property of the Cookie
|
||||
*/
|
||||
public void setCookieMaxAge(int cookieMaxAge) {
|
||||
if (cookieMaxAge > this.rememberMeCookieMaxAge) {
|
||||
throw new IllegalArgumentException("cookieMaxAge cannot be greater than " +
|
||||
"rememberMeCookieMaxAge");
|
||||
}
|
||||
this.cookieMaxAge = cookieMaxAge;
|
||||
}
|
||||
|
||||
@@ -304,12 +300,10 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request attribute name that indicates remember-me login. Used to write
|
||||
* {@link Cookie} with {@code maxAge} property indicated by
|
||||
* {@link #rememberMeCookieMaxAge}.
|
||||
* Set the request attribute name that indicates remember-me login. If specified, the
|
||||
* cookie will be written as Integer.MAX_VALUE.
|
||||
* @param rememberMeRequestAttribute the remember-me request attribute name
|
||||
* @since 1.3.0
|
||||
* @see #setRememberMeCookieMaxAge(int)
|
||||
*/
|
||||
public void setRememberMeRequestAttribute(String rememberMeRequestAttribute) {
|
||||
if (rememberMeRequestAttribute == null) {
|
||||
@@ -319,20 +313,6 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
this.rememberMeRequestAttribute = rememberMeRequestAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code maxAge} property of the {@link Cookie} to be used when remember-me
|
||||
* is requested. The default is {@link Integer#MAX_VALUE}.
|
||||
* @param rememberMeCookieMaxAge the {@code maxAge} property of the {@code Cookie}
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public void setRememberMeCookieMaxAge(int rememberMeCookieMaxAge) {
|
||||
if (rememberMeCookieMaxAge < 1 || rememberMeCookieMaxAge < this.cookieMaxAge) {
|
||||
throw new IllegalArgumentException("rememberMeCookieMaxAge must be greater " +
|
||||
"than zero and greater than cookieMaxAge");
|
||||
}
|
||||
this.rememberMeCookieMaxAge = rememberMeCookieMaxAge;
|
||||
}
|
||||
|
||||
private String getDomainName(HttpServletRequest request) {
|
||||
if (this.domainName != null) {
|
||||
return this.domainName;
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.security.SpringSessionRememberMeServices;
|
||||
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
|
||||
import org.springframework.session.web.http.CookieHttpSessionStrategy;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.security;
|
||||
package org.springframework.session.security.web.authentication;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -50,44 +50,48 @@ public class SpringSessionRememberMeServicesTests {
|
||||
@Test
|
||||
public void create() {
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices, "parameter"))
|
||||
.isEqualTo("remember-me");
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices, "alwaysRemember"))
|
||||
.isEqualTo(false);
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices, "validitySeconds"))
|
||||
.isEqualTo(2592000);
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices,
|
||||
"rememberMeParameterName")).isEqualTo("remember-me");
|
||||
assertThat(
|
||||
ReflectionTestUtils.getField(this.rememberMeServices, "alwaysRemember"))
|
||||
.isEqualTo(false);
|
||||
assertThat(
|
||||
ReflectionTestUtils.getField(this.rememberMeServices, "validitySeconds"))
|
||||
.isEqualTo(2592000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithCustomParameter() {
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
this.rememberMeServices.setParameter("test-param");
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices, "parameter"))
|
||||
.isEqualTo("test-param");
|
||||
this.rememberMeServices.setRememberMeParameterName("test-param");
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices,
|
||||
"rememberMeParameterName")).isEqualTo("test-param");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithNullParameter() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Parameter name cannot be empty or null");
|
||||
this.thrown.expectMessage("rememberMeParameterName cannot be empty or null");
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
this.rememberMeServices.setParameter(null);
|
||||
this.rememberMeServices.setRememberMeParameterName(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithAlwaysRemember() {
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
this.rememberMeServices.setAlwaysRemember(true);
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices, "alwaysRemember"))
|
||||
.isEqualTo(true);
|
||||
assertThat(
|
||||
ReflectionTestUtils.getField(this.rememberMeServices, "alwaysRemember"))
|
||||
.isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithCustomValidity() {
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
this.rememberMeServices.setValiditySeconds(100000);
|
||||
assertThat(ReflectionTestUtils.getField(this.rememberMeServices, "validitySeconds"))
|
||||
.isEqualTo(100000);
|
||||
assertThat(
|
||||
ReflectionTestUtils.getField(this.rememberMeServices, "validitySeconds"))
|
||||
.isEqualTo(100000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,7 +143,7 @@ public class SpringSessionRememberMeServicesTests {
|
||||
given(request.getParameter(eq("test-param"))).willReturn("true");
|
||||
given(request.getSession()).willReturn(session);
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
this.rememberMeServices.setParameter("test-param");
|
||||
this.rememberMeServices.setRememberMeParameterName("test-param");
|
||||
this.rememberMeServices.loginSuccess(request, response, authentication);
|
||||
verify(request, times(1)).getParameter(eq("test-param"));
|
||||
verify(request, times(1)).getSession();
|
||||
@@ -172,8 +176,7 @@ public class SpringSessionRememberMeServicesTests {
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
HttpSession session = mock(HttpSession.class);
|
||||
given(request.getParameter(eq("remember-me")))
|
||||
.willReturn("true");
|
||||
given(request.getParameter(eq("remember-me"))).willReturn("true");
|
||||
given(request.getSession()).willReturn(session);
|
||||
this.rememberMeServices = new SpringSessionRememberMeServices();
|
||||
this.rememberMeServices.setValiditySeconds(100000);
|
||||
@@ -431,23 +431,6 @@ public class DefaultCookieSerializerTests {
|
||||
|
||||
// --- rememberMe ---
|
||||
|
||||
@Test
|
||||
public void setRememberMeCookieMaxAgeNotGreaterThanZero() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("rememberMeCookieMaxAge must be greater than zero and " +
|
||||
"greater than cookieMaxAge");
|
||||
this.serializer.setRememberMeCookieMaxAge(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRememberMeCookieMaxAgeNotGreaterMaxCookieAge() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("rememberMeCookieMaxAge must be greater than zero and " +
|
||||
"greater than cookieMaxAge");
|
||||
this.serializer.setCookieMaxAge(20);
|
||||
this.serializer.setRememberMeCookieMaxAge(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieRememberMeCookieMaxAgeDefault() {
|
||||
this.request.setAttribute("rememberMe", true);
|
||||
@@ -457,17 +440,6 @@ public class DefaultCookieSerializerTests {
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCookieRememberMeCookieMaxAgeExplicit() {
|
||||
this.request.setAttribute("rememberMe", true);
|
||||
this.serializer.setRememberMeRequestAttribute("rememberMe");
|
||||
this.serializer.setRememberMeCookieMaxAge(100);
|
||||
|
||||
this.serializer.writeCookieValue(cookieValue(this.sessionId));
|
||||
|
||||
assertThat(getCookie().getMaxAge()).isEqualTo(100);
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
this.cookieName = cookieName;
|
||||
this.serializer.setCookieName(cookieName);
|
||||
|
||||
Reference in New Issue
Block a user