浏览代码

SEC-2249: AbstractSecurityWebApplicationInitializer allows register config

Rob Winch 12 年之前
父节点
当前提交
e8278f3b9b

+ 0 - 37
samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/RootContextApplicationInitializer.java

@@ -1,37 +0,0 @@
-/*
- * Copyright 2002-2013 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.samples.config;
-
-import org.springframework.web.context.AbstractContextLoaderInitializer;
-import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
-
-/**
- * @author Rob Winch
- *
- */
-public class RootContextApplicationInitializer extends AbstractContextLoaderInitializer {
-
-    /* (non-Javadoc)
-     * @see org.springframework.web.context.AbstractContextLoaderInitializer#createRootApplicationContext()
-     */
-    @Override
-    protected WebApplicationContext createRootApplicationContext() {
-        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
-        context.register(SecurityConfig.class);
-        return context;
-    }
-}

+ 4 - 0
samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/SecurityWebApplicationInitializer.java

@@ -23,4 +23,8 @@ import org.springframework.security.web.context.AbstractSecurityWebApplicationIn
  * @author Rob Winch
  */
 public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
+
+    public SecurityWebApplicationInitializer() {
+        super(SecurityConfig.class);
+    }
 }

+ 50 - 4
web/src/main/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.java

@@ -35,14 +35,18 @@ import org.springframework.security.web.session.HttpSessionEventPublisher;
 import org.springframework.util.Assert;
 import org.springframework.web.WebApplicationInitializer;
 import org.springframework.web.context.AbstractContextLoaderInitializer;
+import org.springframework.web.context.ContextLoaderListener;
 import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
 import org.springframework.web.filter.DelegatingFilterProxy;
 
 /**
  * Registers the {@link DelegatingFilterProxy} to use the
- * springSecurityFilterChain before any other registered {@link Filter}. This
- * class is typically used in addition to a subclass of
- * {@link AbstractContextLoaderInitializer}.
+ * springSecurityFilterChain before any other registered {@link Filter}. When
+ * used with {@link #AbstractSecurityWebApplicationInitializer(Class...)}, it
+ * will also register a {@link ContextLoaderListener}. When used with
+ * {@link #AbstractSecurityWebApplicationInitializer()}, this class is typically
+ * used in addition to a subclass of {@link AbstractContextLoaderInitializer}.
  *
  * <p>
  * By default the {@link DelegatingFilterProxy} is registered without support,
@@ -53,7 +57,6 @@ import org.springframework.web.filter.DelegatingFilterProxy;
  * <p>
  * Additional configuration before and after the springSecurityFilterChain can
  * be added by overriding
- * {@link #beforeSpringSecurityFilterChain(ServletContext)} and
  * {@link #afterSpringSecurityFilterChain(ServletContext)}.
  * </p>
  *
@@ -77,11 +80,37 @@ public abstract class AbstractSecurityWebApplicationInitializer implements WebAp
 
     public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";
 
+    private WebApplicationInitializer contextLoaderListenerInitializer;
+
+    /**
+     * Creates a new instance that assumes the Spring Security configuration is
+     * loaded by some other means than this class. For example, a user might
+     * create a {@link ContextLoaderListener} using a subclass of
+     * {@link AbstractContextLoaderInitializer}.
+     *
+     * @see ContextLoaderListener
+     */
+    protected AbstractSecurityWebApplicationInitializer() {
+    }
+
+    /**
+     * Creates a new instance that will instantiate the
+     * {@link ContextLoaderListener} with the specified classes.
+     *
+     * @param configurationClasses
+     */
+    protected AbstractSecurityWebApplicationInitializer(Class<?>... configurationClasses) {
+        contextLoaderListenerInitializer = new RootContextApplicationInitializer(configurationClasses){};
+    }
+
     /* (non-Javadoc)
      * @see org.springframework.web.WebApplicationInitializer#onStartup(javax.servlet.ServletContext)
      */
     public final void onStartup(ServletContext servletContext)
             throws ServletException {
+        if(contextLoaderListenerInitializer != null) {
+            contextLoaderListenerInitializer.onStartup(servletContext);
+        }
         if(enableHttpSessionEventPublisher()) {
             servletContext.addListener("org.springframework.security.web.session.HttpSessionEventPublisher");
         }
@@ -281,4 +310,21 @@ public abstract class AbstractSecurityWebApplicationInitializer implements WebAp
         return true;
     }
 
+    private static abstract class RootContextApplicationInitializer extends AbstractContextLoaderInitializer {
+        private Class<?>[] configurationClasses;
+
+        private RootContextApplicationInitializer(Class<?>... configurationClasses) {
+            this.configurationClasses = configurationClasses;
+        }
+
+        /* (non-Javadoc)
+         * @see org.springframework.web.context.AbstractContextLoaderInitializer#createRootApplicationContext()
+         */
+        @Override
+        protected WebApplicationContext createRootApplicationContext() {
+            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+            context.register(configurationClasses);
+            return context;
+        }
+    }
 }

+ 25 - 9
web/src/test/groovy/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.groovy

@@ -15,16 +15,16 @@
  */
 package org.springframework.security.web.context;
 
-import java.util.EnumSet;
+import javax.servlet.DispatcherType
+import javax.servlet.Filter
+import javax.servlet.FilterRegistration
+import javax.servlet.ServletContext
+import javax.servlet.SessionTrackingMode
 
-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;
+import org.springframework.context.annotation.Configuration
+import org.springframework.security.web.session.HttpSessionEventPublisher
+import org.springframework.web.context.ContextLoaderListener
+import org.springframework.web.filter.DelegatingFilterProxy
 
 import spock.lang.Specification
 
@@ -47,6 +47,22 @@ class AbstractSecurityWebApplicationInitializerTests extends Specification {
             0 * context.addListener(_)
     }
 
+    def "defaults with ContextLoaderListener"() {
+        setup:
+            ServletContext context = Mock()
+            FilterRegistration.Dynamic registration = Mock()
+        when:
+            new AbstractSecurityWebApplicationInitializer(MyRootConfiguration){}.onStartup(context)
+        then:
+            1 * context.addFilter("springSecurityFilterChain", {DelegatingFilterProxy f -> f.targetBeanName == "springSecurityFilterChain" && f.contextAttribute == null}) >> registration
+            1 * registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR), false, "/*");
+            1 * registration.setAsyncSupported(true)
+            1 * context.addListener(_ as ContextLoaderListener)
+    }
+
+    @Configuration
+    static class MyRootConfiguration {}
+
     def "enableHttpSessionEventPublisher() = true"() {
         setup:
             ServletContext context = Mock()