Преглед на файлове

SEC-585: Made expiredUrl optional.

Also implemented Ordered interface for use in namespace configuration.
Luke Taylor преди 18 години
родител
ревизия
3d9ea49d19

+ 29 - 41
core/src/main/java/org/springframework/security/concurrent/ConcurrentSessionFilter.java

@@ -16,36 +16,34 @@
 package org.springframework.security.concurrent;
 
 import org.springframework.beans.factory.InitializingBean;
-
+import org.springframework.security.ui.FilterChainOrderUtils;
+import org.springframework.security.ui.SpringSecurityFilter;
 import org.springframework.util.Assert;
 
-import java.io.IOException;
-
-import javax.servlet.Filter;
 import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
+import java.io.IOException;
 
 
 /**
- * Filter required by concurrent session handling package.<p>This filter performs two functions. First, it calls
- * {@link org.springframework.security.concurrent.SessionRegistry#refreshLastRequest(String)} for each request. That way,
- * registered sessions always have a correct "last update" date/time. Second, it retrieves {@link
- * org.springframework.security.concurrent.SessionInformation} from the <code>SessionRegistry</code> for each request and checks
- * if the session has been marked as expired. If it has been marked as expired, the session is invalidated. The
- * invalidation of the session will also cause the request to redirect to the URL specified, and a {@link
- * org.springframework.security.ui.session.HttpSessionDestroyedEvent} to be published via the {@link
- * org.springframework.security.ui.session.HttpSessionEventPublisher} registered in <code>web.xml</code>.</p>
+ * Filter required by concurrent session handling package.
+ * <p>This filter performs two functions. First, it calls
+ * {@link org.springframework.security.concurrent.SessionRegistry#refreshLastRequest(String)} for each request.
+ * That way, registered sessions always have a correct "last update" date/time. Second, it retrieves
+ * {@link org.springframework.security.concurrent.SessionInformation} from the <code>SessionRegistry</code>
+ * for each request and checks if the session has been marked as expired.
+ * If it has been marked as expired, the session is invalidated. The invalidation of the session will also cause the
+ * request to redirect to the URL specified, and a
+ * {@link org.springframework.security.ui.session.HttpSessionDestroyedEvent} to be published via the
+ * {@link org.springframework.security.ui.session.HttpSessionEventPublisher} registered in <code>web.xml</code>.</p>
  *
  * @author Ben Alex
  * @version $Id$
  */
-public class ConcurrentSessionFilter implements Filter, InitializingBean {
+public class ConcurrentSessionFilter extends SpringSecurityFilter implements InitializingBean {
     //~ Instance fields ================================================================================================
 
     private SessionRegistry sessionRegistry;
@@ -55,23 +53,12 @@ public class ConcurrentSessionFilter implements Filter, InitializingBean {
 
     public void afterPropertiesSet() throws Exception {
         Assert.notNull(sessionRegistry, "SessionRegistry required");
-        Assert.hasText(expiredUrl, "ExpiredUrl required");
     }
 
-    /**
-     * Does nothing. We use IoC container lifecycle services instead.
-     */
-    public void destroy() {}
-
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-        throws IOException, ServletException {
-        Assert.isInstanceOf(HttpServletRequest.class, request, "Can only process HttpServletRequest");
-        Assert.isInstanceOf(HttpServletResponse.class, response, "Can only process HttpServletResponse");
+    public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
 
-        HttpServletRequest httpRequest = (HttpServletRequest) request;
-        HttpServletResponse httpResponse = (HttpServletResponse) response;
-
-        HttpSession session = httpRequest.getSession(false);
+        HttpSession session = request.getSession(false);
 
         if (session != null) {
             SessionInformation info = sessionRegistry.getSessionInformation(session.getId());
@@ -81,8 +68,14 @@ public class ConcurrentSessionFilter implements Filter, InitializingBean {
                     // Expired - abort processing
                     session.invalidate();
 
-                    String targetUrl = httpRequest.getContextPath() + expiredUrl;
-                    httpResponse.sendRedirect(httpResponse.encodeRedirectURL(targetUrl));
+                    if (expiredUrl != null) {
+                        String targetUrl = request.getContextPath() + expiredUrl;
+                        response.sendRedirect(response.encodeRedirectURL(targetUrl));
+                    } else {
+                        response.getWriter().print("This session has been expired (possibly due to multiple concurrent " +
+                                "logins being attempted as the same user).");
+                        response.flushBuffer();
+                    }
 
                     return;
                 } else {
@@ -95,15 +88,6 @@ public class ConcurrentSessionFilter implements Filter, InitializingBean {
         chain.doFilter(request, response);
     }
 
-    /**
-     * Does nothing. We use IoC container lifecycle services instead.
-     *
-     * @param arg0 ignored
-     *
-     * @throws ServletException ignored
-     */
-    public void init(FilterConfig arg0) throws ServletException {}
-
     public void setExpiredUrl(String expiredUrl) {
         this.expiredUrl = expiredUrl;
     }
@@ -111,4 +95,8 @@ public class ConcurrentSessionFilter implements Filter, InitializingBean {
     public void setSessionRegistry(SessionRegistry sessionRegistry) {
         this.sessionRegistry = sessionRegistry;
     }
+
+    public int getOrder() {
+        return FilterChainOrderUtils.CONCURRENT_SESSION_FILTER_ORDER;
+    }
 }

+ 19 - 16
core/src/test/java/org/springframework/security/concurrent/ConcurrentSessionFilterTests.java

@@ -40,10 +40,6 @@ import java.util.Date;
 public class ConcurrentSessionFilterTests extends TestCase {
     //~ Constructors ===================================================================================================
 
-    public ConcurrentSessionFilterTests() {
-        super();
-    }
-
     public ConcurrentSessionFilterTests(String arg0) {
         super(arg0);
     }
@@ -58,10 +54,6 @@ public class ConcurrentSessionFilterTests extends TestCase {
         filter.destroy();
     }
 
-    public static void main(String[] args) {
-        junit.textui.TestRunner.run(ConcurrentSessionFilterTests.class);
-    }
-
     public void testDetectsExpiredSessions() throws Exception {
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest();
@@ -88,16 +80,27 @@ public class ConcurrentSessionFilterTests extends TestCase {
         assertEquals("/expired.jsp", response.getRedirectedUrl());
     }
 
-    public void testDetectsMissingExpiredUrl() throws Exception {
+    // As above, but with no expiredUrl set.
+    public void testReturnsExpectedMessageWhenNoExpiredUrlSet() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpSession session = new MockHttpSession();
+        request.setSession(session);
+
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockFilterConfig config = new MockFilterConfig(null, null);
+
+        MockFilterChain chain = new MockFilterChain(false);
+
         ConcurrentSessionFilter filter = new ConcurrentSessionFilter();
-        filter.setSessionRegistry(new SessionRegistryImpl());
+        SessionRegistry registry = new SessionRegistryImpl();
+        registry.registerNewSession(session.getId(), "principal");
+        registry.getSessionInformation(session.getId()).expireNow();
+        filter.setSessionRegistry(registry);
 
-        try {
-            filter.afterPropertiesSet();
-            fail("Should have thrown IAE");
-        } catch (IllegalArgumentException expected) {
-            assertTrue(true);
-        }
+        executeFilterInContainerSimulator(config, filter, request, response, chain);
+
+        assertEquals("This session has been expired (possibly due to multiple concurrent logins being " +
+                "attempted as the same user).", response.getContentAsString());
     }
 
     public void testDetectsMissingSessionRegistry() throws Exception {