1
0
mirror of synced 2026-08-04 01:07:02 +00:00

Configuration of session management strategies

This commit adds an ExpiredSessionStrategy for the ConcurrentSessionFilter
analogous to the InvalidSessionStrategy for the SessionManagementFilter. It also
adds a configuration option for both the InvalidSessionStrategy and
ExpiredSessionStrategy to the XML namespace and Java configuration.

Fixes gh-3794
Fixes gh-3795
This commit is contained in:
Marten Deinum
2016-04-12 07:59:14 +02:00
committed by Rob Winch
parent a82cab7afd
commit b88418b94a
11 changed files with 272 additions and 107 deletions
@@ -17,7 +17,6 @@
package org.springframework.security.web.session;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
@@ -35,7 +34,6 @@ import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.logout.CompositeLogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;
@@ -51,8 +49,8 @@ import org.springframework.web.filter.GenericFilterBean;
* as expired. If it has been marked as expired, the configured logout handlers will be
* called (as happens with
* {@link org.springframework.security.web.authentication.logout.LogoutFilter}), typically
* to invalidate the session. A redirect to the expiredURL specified will be performed,
* and the session invalidation will cause an
* to invalidate the session. To handle the expired session a call to the {@link ExpiredSessionStrategy} is made.
* The session invalidation will cause an
* {@link org.springframework.security.web.session.HttpSessionDestroyedEvent} to be
* published via the
* {@link org.springframework.security.web.session.HttpSessionEventPublisher} registered
@@ -61,15 +59,15 @@ import org.springframework.web.filter.GenericFilterBean;
*
* @author Ben Alex
* @author Eddú Meléndez
* @author Marten Deinum
*/
public class ConcurrentSessionFilter extends GenericFilterBean {
// ~ Instance fields
// ================================================================================================
private SessionRegistry sessionRegistry;
private String expiredUrl;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private final SessionRegistry sessionRegistry;
private LogoutHandler handlers = new CompositeLogoutHandler(new SecurityContextLogoutHandler());
private ExpiredSessionStrategy expiredSessionStrategy;
// ~ Methods
// ========================================================================================================
@@ -81,17 +79,13 @@ public class ConcurrentSessionFilter extends GenericFilterBean {
public ConcurrentSessionFilter(SessionRegistry sessionRegistry, String expiredUrl) {
Assert.notNull(sessionRegistry, "SessionRegistry required");
Assert.isTrue(expiredUrl == null || UrlUtils.isValidRedirectUrl(expiredUrl),
expiredUrl + " isn't a valid redirect URL");
this.sessionRegistry = sessionRegistry;
this.expiredUrl = expiredUrl;
this.expiredSessionStrategy = new SimpleRedirectExpiredSessionStrategy(expiredUrl);
}
@Override
public void afterPropertiesSet() {
Assert.notNull(sessionRegistry, "SessionRegistry required");
Assert.isTrue(expiredUrl == null || UrlUtils.isValidRedirectUrl(expiredUrl),
expiredUrl + " isn't a valid redirect URL");
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
@@ -108,12 +102,14 @@ public class ConcurrentSessionFilter extends GenericFilterBean {
if (info != null) {
if (info.isExpired()) {
// Expired - abort processing
if (logger.isDebugEnabled()) {
logger.debug("Requested session ID "
+ request.getRequestedSessionId() + " has expired.");
}
doLogout(request, response);
String targetUrl = determineExpiredUrl(request, info);
if (targetUrl != null) {
redirectStrategy.sendRedirect(request, response, targetUrl);
if (this.expiredSessionStrategy != null) {
this.expiredSessionStrategy.onExpiredSessionDetected(request, response);
return;
}
@@ -136,10 +132,6 @@ public class ConcurrentSessionFilter extends GenericFilterBean {
chain.doFilter(request, response);
}
protected String determineExpiredUrl(HttpServletRequest request,
SessionInformation info) {
return expiredUrl;
}
private void doLogout(HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
@@ -151,7 +143,7 @@ public class ConcurrentSessionFilter extends GenericFilterBean {
this.handlers = new CompositeLogoutHandler(handlers);
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
public void setExpiredSessionStrategy(ExpiredSessionStrategy expiredSessionStrategy) {
this.expiredSessionStrategy=expiredSessionStrategy;
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2015-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 org.springframework.security.web.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Determines the behaviour of the {@code ConcurrentSessionFilter} when an expired session
* is detected in the {@code ConcurrentSessionFilter}.
*
* @author Marten Deinum
* @since 4.1.0
*/
public interface ExpiredSessionStrategy {
void onExpiredSessionDetected(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;
}
@@ -0,0 +1,58 @@
/*
* Copyright 2002-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 org.springframework.security.web.session;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
/**
* Performs a redirect to a fixed URL when an expired session is detected by the
* {@code ConcurrentSessionFilter}.
*
* @author Marten Deinum
* @since 4.1.0
*/
public final class SimpleRedirectExpiredSessionStrategy implements ExpiredSessionStrategy {
private final Log logger = LogFactory.getLog(getClass());
private final String destinationUrl;
private final RedirectStrategy redirectStrategy;
public SimpleRedirectExpiredSessionStrategy(String invalidSessionUrl) {
this(invalidSessionUrl, new DefaultRedirectStrategy());
}
public SimpleRedirectExpiredSessionStrategy(String invalidSessionUrl, RedirectStrategy redirectStrategy) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl),
"url must start with '/' or with 'http(s)'");
this.destinationUrl=invalidSessionUrl;
this.redirectStrategy=redirectStrategy;
}
public void onExpiredSessionDetected(HttpServletRequest request,
HttpServletResponse response) throws IOException {
logger.debug("Redirecting to '" + destinationUrl + "'");
redirectStrategy.sendRedirect(request, response, destinationUrl);
}
}
@@ -16,11 +16,7 @@
package org.springframework.security.web.concurrent;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Date;
import javax.servlet.FilterChain;
import org.junit.Test;
@@ -29,10 +25,13 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SimpleRedirectExpiredSessionStrategy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
/**
* Tests {@link ConcurrentSessionFilter}.
@@ -56,9 +55,10 @@ public class ConcurrentSessionFilterTests {
registry.getSessionInformation(session.getId()).expireNow();
// Setup our test fixture and registry to want this session to be expired
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry,
"/expired.jsp");
filter.setRedirectStrategy(new DefaultRedirectStrategy());
SimpleRedirectExpiredSessionStrategy expiredSessionStrategy = new SimpleRedirectExpiredSessionStrategy("/expired.jsp");
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry);
filter.setExpiredSessionStrategy(expiredSessionStrategy);
filter.setLogoutHandlers(new LogoutHandler[] { new SecurityContextLogoutHandler() });
filter.afterPropertiesSet();
@@ -97,11 +97,6 @@ public class ConcurrentSessionFilterTests {
new ConcurrentSessionFilter(null);
}
@Test(expected = IllegalArgumentException.class)
public void detectsInvalidUrl() throws Exception {
new ConcurrentSessionFilter(new SessionRegistryImpl(), "ImNotValid");
}
@Test
public void lastRequestTimeUpdatesCorrectly() throws Exception {
// Setup our HTTP request
@@ -115,11 +110,11 @@ public class ConcurrentSessionFilterTests {
// Setup our test fixture
SessionRegistry registry = new SessionRegistryImpl();
registry.registerNewSession(session.getId(), "principal");
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry,
"/expired.jsp");
SimpleRedirectExpiredSessionStrategy expiredSessionStrategy = new SimpleRedirectExpiredSessionStrategy("/expired.jsp");
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry);
filter.setExpiredSessionStrategy(expiredSessionStrategy);
Date lastRequest = registry.getSessionInformation(session.getId())
.getLastRequest();
Date lastRequest = registry.getSessionInformation(session.getId()).getLastRequest();
Thread.sleep(1000);