2
0
Эх сурвалжийг харах

SEC-2461: Multi WebSecurityConfiguration does not create null springSecurityFilterChain

Rob Winch 11 жил өмнө
parent
commit
6b42a2eae1

+ 58 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configuration/AutowiredWebSecurityConfigurersIgnoreParents.java

@@ -0,0 +1,58 @@
+/*
+ * 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.config.annotation.web.configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.Filter;
+
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.security.config.annotation.SecurityConfigurer;
+import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.util.Assert;
+
+
+/**
+ * A class used to get all the {@link WebSecurityConfigurer} instances from the
+ * current {@link ApplicationContext} but ignoring the parent.
+ *
+ * @author Rob Winch
+ *
+ */
+final class AutowiredWebSecurityConfigurersIgnoreParents {
+
+    private final ConfigurableListableBeanFactory beanFactory;
+
+    public AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
+        Assert.notNull(beanFactory,"beanFactory cannot be null");
+        this.beanFactory = beanFactory;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
+        List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
+        Map<String, WebSecurityConfigurer> beansOfType = beanFactory.getBeansOfType(WebSecurityConfigurer.class);
+        for(Entry<String,WebSecurityConfigurer> entry : beansOfType.entrySet()) {
+            webSecurityConfigurers.add(entry.getValue());
+        }
+        return webSecurityConfigurers;
+    }
+}

+ 8 - 7
config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java

@@ -23,6 +23,8 @@ import javax.servlet.Filter;
 
 import org.springframework.beans.factory.BeanClassLoaderAware;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.DependsOn;
@@ -34,7 +36,6 @@ import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.core.annotation.Order;
 import org.springframework.core.type.AnnotationMetadata;
 import org.springframework.security.access.expression.SecurityExpressionHandler;
-import org.springframework.security.config.annotation.AlreadyBuiltException;
 import org.springframework.security.config.annotation.ObjectPostProcessor;
 import org.springframework.security.config.annotation.SecurityConfigurer;
 import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
@@ -88,11 +89,7 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
         if(!hasConfigurers) {
             throw new IllegalStateException("At least one non-null instance of "+ WebSecurityConfigurer.class.getSimpleName()+" must be exposed as a @Bean when using @EnableWebSecurity. Hint try extending "+ WebSecurityConfigurerAdapter.class.getSimpleName());
         }
-        try {
-            return webSecurity.build();
-        } catch (AlreadyBuiltException e) {
-            return webSecurity.getObject();
-        }
+        return webSecurity.build();
     }
 
     /**
@@ -115,7 +112,7 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
      */
     @Autowired(required = false)
     public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
-            List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
+            @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
         webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
         if(debugEnabled != null) {
             webSecurity.debug(debugEnabled);
@@ -137,6 +134,10 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
         this.webSecurityConfigurers = webSecurityConfigurers;
     }
 
+    @Bean
+    public AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
+        return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
+    }
 
     /**
      * A custom verision of the Spring provided AnnotationAwareOrderComparator

+ 43 - 14
config/src/test/groovy/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.groovy

@@ -17,31 +17,28 @@ package org.springframework.security.config.annotation.web.configuration;
 
 import static org.junit.Assert.*
 
-import java.util.List;
-
 import org.springframework.beans.factory.BeanCreationException
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.annotation.Bean;
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.core.annotation.Order
-import org.springframework.expression.ExpressionParser;
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.security.access.expression.SecurityExpressionHandler;
+import org.springframework.expression.ExpressionParser
+import org.springframework.mock.web.MockHttpServletRequest
+import org.springframework.security.access.expression.SecurityExpressionHandler
 import org.springframework.security.authentication.AuthenticationManager
-import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
 import org.springframework.security.config.annotation.BaseSpringSpec
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
 import org.springframework.security.config.annotation.web.builders.HttpSecurity
 import org.springframework.security.config.annotation.web.builders.WebSecurity
 import org.springframework.security.web.FilterChainProxy
 import org.springframework.security.web.SecurityFilterChain
-import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
-import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
-import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
-import org.springframework.security.web.access.expression.WebSecurityExpressionHandler;
-import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator
+import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator
+import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
+import org.springframework.security.web.access.expression.WebSecurityExpressionHandler
 import org.springframework.security.web.util.matcher.AnyRequestMatcher
-import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.test.util.ReflectionTestUtils
 
 /**
  * @author Rob Winch
@@ -313,4 +310,36 @@ class WebSecurityConfigurationTests extends BaseSpringSpec {
             }
         }
     }
+
+    def "SEC-2461: Multiple WebSecurityConfiguration instances cause null springSecurityFilterChain"() {
+        setup:
+            def parent = loadConfig(ParentConfig)
+            def child = new AnnotationConfigApplicationContext()
+            child.register(ChildConfig)
+            child.parent = parent
+        when:
+            child.refresh()
+        then: "springSecurityFilterChain can be found in parent and child"
+            parent.getBean("springSecurityFilterChain")
+            child.getBean("springSecurityFilterChain")
+        and: "springSecurityFilterChain is defined in both parent and child (don't search parent)"
+            parent.containsBeanDefinition("springSecurityFilterChain")
+            child.containsBeanDefinition("springSecurityFilterChain")
+        cleanup:
+            child?.close()
+            // parent.close() is in superclass
+    }
+
+    @EnableWebSecurity
+    @Configuration
+    static class ParentConfig extends WebSecurityConfigurerAdapter {
+        @Autowired
+        public void configureGlobal(AuthenticationManagerBuilder auth) {
+            auth.inMemoryAuthentication()
+        }
+    }
+
+    @EnableWebSecurity
+    @Configuration
+    static class ChildConfig extends WebSecurityConfigurerAdapter { }
 }

+ 3 - 2
config/src/test/groovy/org/springframework/security/config/annotation/web/configuration/sec2377/b/Sec2377BConfig.java

@@ -17,9 +17,10 @@ package org.springframework.security.config.annotation.web.configuration.sec2377
 
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
 @EnableWebSecurity
 @Configuration
-public class Sec2377BConfig {
+public class Sec2377BConfig extends WebSecurityConfigurerAdapter {
 
-}
+}