diff --git a/samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/RootContextApplicationInitializer.java b/samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/RootContextApplicationInitializer.java deleted file mode 100644 index d079b3fe21..0000000000 --- a/samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/RootContextApplicationInitializer.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/SecurityWebApplicationInitializer.java b/samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/SecurityWebApplicationInitializer.java index 258104f2a9..6683f9909f 100644 --- a/samples/helloworld-jc/src/main/java/org/springframework/security/samples/config/SecurityWebApplicationInitializer.java +++ b/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); + } } diff --git a/web/src/main/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.java b/web/src/main/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.java index 01173b1a1d..5254f31667 100644 --- a/web/src/main/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.java +++ b/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}. * *
* By default the {@link DelegatingFilterProxy} is registered without support, @@ -53,7 +57,6 @@ import org.springframework.web.filter.DelegatingFilterProxy; *
* Additional configuration before and after the springSecurityFilterChain can * be added by overriding - * {@link #beforeSpringSecurityFilterChain(ServletContext)} and * {@link #afterSpringSecurityFilterChain(ServletContext)}. *
* @@ -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; + } + } } diff --git a/web/src/test/groovy/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.groovy b/web/src/test/groovy/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.groovy index eab3dcb069..4e2cab6b37 100644 --- a/web/src/test/groovy/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.groovy +++ b/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()