浏览代码

SEC-2156: AbstractSecurityWebApplicationInitializer configures SessionTrackingMode

It also allows customization by overriding a method.
Rob Winch 12 年之前
父节点
当前提交
ac053dbda7

+ 33 - 0
web/src/main/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.java

@@ -17,12 +17,15 @@ package org.springframework.security.web.context;
 
 import java.util.Arrays;
 import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterRegistration.Dynamic;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.SessionTrackingMode;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.Conventions;
@@ -83,6 +86,7 @@ public abstract class AbstractSecurityWebApplicationInitializer implements WebAp
         if(enableHttpSessionEventPublisher()) {
             servletContext.addListener("org.springframework.security.web.session.HttpSessionEventPublisher");
         }
+        servletContext.setSessionTrackingModes(getSessionTrackingModes());
         insertSpringSecurityFilterChain(servletContext);
         afterSpringSecurityFilterChain(servletContext);
     }
@@ -207,6 +211,35 @@ public abstract class AbstractSecurityWebApplicationInitializer implements WebAp
         return SERVLET_CONTEXT_PREFIX + dispatcherServletName;
     }
 
+    /**
+     * Determines how a session should be tracked. By default, the following
+     * modes are used:
+     *
+     * <ul>
+     * <li> {@link SessionTrackingMode#COOKIE}</li>
+     * <li> {@link SessionTrackingMode#SSL}</li>
+     * </ul>
+     *
+     * <p>
+     * Note that {@link SessionTrackingMode#URL} is intentionally omitted to
+     * help protected against <a
+     * href="http://en.wikipedia.org/wiki/Session_fixation">session fixation
+     * attacks</a>.
+     * </p>
+     *
+     * <p>
+     * Subclasses can override this method to make customizations.
+     * </p>
+     *
+     * @return
+     */
+    protected Set<SessionTrackingMode> getSessionTrackingModes() {
+        Set<SessionTrackingMode> modes = new HashSet<SessionTrackingMode>();
+        modes.add(SessionTrackingMode.COOKIE);
+        modes.add(SessionTrackingMode.SSL);
+        return modes;
+    }
+
     /**
      * Return the <servlet-name> to use the DispatcherServlet's
      * {@link WebApplicationContext} to find the {@link DelegatingFilterProxy}

+ 28 - 0
web/src/test/groovy/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.groovy

@@ -21,6 +21,7 @@ import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterRegistration;
 import javax.servlet.ServletContext;
+import javax.servlet.SessionTrackingMode;
 
 import org.springframework.security.web.session.HttpSessionEventPublisher;
 import org.springframework.web.filter.DelegatingFilterProxy;
@@ -239,6 +240,33 @@ class AbstractSecurityWebApplicationInitializerTests extends Specification {
             success.message == "filters cannot be null or empty"
     }
 
+    def "sessionTrackingModes defaults"() {
+        setup:
+            ServletContext context = Mock()
+            FilterRegistration.Dynamic registration = Mock()
+        when:
+            new AbstractSecurityWebApplicationInitializer(){ }.onStartup(context)
+        then:
+            1 * context.addFilter("springSecurityFilterChain", {DelegatingFilterProxy f -> f.targetBeanName == "springSecurityFilterChain" && f.contextAttribute == null}) >> registration
+            1 * context.setSessionTrackingModes({Set<SessionTrackingMode> modes -> modes.size() == 2 && modes.containsAll([SessionTrackingMode.COOKIE, SessionTrackingMode.SSL]) })
+    }
+
+    def "sessionTrackingModes override"() {
+        setup:
+            ServletContext context = Mock()
+            FilterRegistration.Dynamic registration = Mock()
+        when:
+            new AbstractSecurityWebApplicationInitializer(){
+                @Override
+                public Set<SessionTrackingMode> getSessionTrackingModes() {
+                    return [SessionTrackingMode.COOKIE]
+                }
+            }.onStartup(context)
+        then:
+            1 * context.addFilter("springSecurityFilterChain", {DelegatingFilterProxy f -> f.targetBeanName == "springSecurityFilterChain" && f.contextAttribute == null}) >> registration
+            1 * context.setSessionTrackingModes({Set<SessionTrackingMode> modes -> modes.size() == 1 && modes.containsAll([SessionTrackingMode.COOKIE]) })
+    }
+
     def "appendFilters filters with null"() {
         setup:
             Filter filter1 = Mock()