浏览代码

SEC-1657: Added support for 'name' attribute in <http> element to expose filter chain as a list bean.

Luke Taylor 14 年之前
父节点
当前提交
2eefbf3a23

+ 3 - 1
config/src/main/java/org/springframework/security/config/http/HttpFirewallBeanDefinitionParser.java

@@ -2,6 +2,7 @@ package org.springframework.security.config.http;
 
 import org.springframework.beans.BeanMetadataElement;
 import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanReference;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.support.ManagedMap;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
@@ -26,8 +27,9 @@ public class HttpFirewallBeanDefinitionParser implements BeanDefinitionParser {
             pc.getReaderContext().error("ref attribute is required", pc.extractSource(element));
         }
 
+        // Ensure the FCP is registered.
         HttpSecurityBeanDefinitionParser.registerFilterChainProxy(pc,
-                new ManagedMap<BeanDefinition, List<BeanMetadataElement>>(),
+                new ManagedMap<BeanDefinition, BeanReference>(),
                 pc.extractSource(element));
         BeanDefinition filterChainProxy = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY);
         filterChainProxy.getPropertyValues().addPropertyValue("firewall", new RuntimeBeanReference(ref));

+ 21 - 5
config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java

@@ -10,6 +10,7 @@ import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.BeanMetadataElement;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanReference;
+import org.springframework.beans.factory.config.ListFactoryBean;
 import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
@@ -72,7 +73,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         pc.pushContainingComponent(compositeDef);
 
         MatcherType matcherType = MatcherType.fromElement(element);
-        ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
+        ManagedMap<BeanDefinition, BeanReference> filterChainMap = new ManagedMap<BeanDefinition, BeanReference>();
 
         String filterChainPattern = element.getAttribute(ATT_PATH_PATTERN);
 
@@ -92,7 +93,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
         return null;
     }
 
-    List<BeanMetadataElement> createFilterChain(Element element, ParserContext pc, MatcherType matcherType) {
+    BeanReference createFilterChain(Element element, ParserContext pc, MatcherType matcherType) {
         boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));
 
         if (!secured) {
@@ -108,7 +109,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
                 }
             }
 
-            return Collections.emptyList();
+            return createFilterListBean(element, pc, Collections.emptyList());
         }
 
         final String portMapperName = createPortMapper(element, pc);
@@ -140,9 +141,24 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
             filterChain.add(od.bean);
         }
 
-        return filterChain;
+        return createFilterListBean(element, pc, filterChain);
     }
 
+    private BeanReference createFilterListBean(Element element, ParserContext pc, List<?> filterChain) {
+        BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
+
+        String id = element.getAttribute("name");
+        if (!StringUtils.hasText(id)) {
+            id = element.getAttribute("id");
+            if (!StringUtils.hasText(id)) {
+                id = pc.getReaderContext().generateBeanName(listFactoryBean);
+            }
+        }
+        listFactoryBean.getPropertyValues().add("sourceList", filterChain);
+        pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean, id));
+
+        return new RuntimeBeanReference(id);
+    }
 
     private String createPortMapper(Element elt, ParserContext pc) {
         // Register the portMapper. A default will always be created, even if no element exists.
@@ -247,7 +263,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
     }
 
     @SuppressWarnings("unchecked")
-    static void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, Object source) {
+    static void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, BeanReference> filterChainMap, Object source) {
         if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
             // Already registered. Obtain the filter chain map and add the new entries to it
 

+ 7 - 0
config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc

@@ -25,6 +25,9 @@ url =
 id =
     ## A bean identifier, used for referring to the bean elsewhere in the context.
     attribute id {xsd:ID}
+name =
+    ## A bean identifier, used for referring to the bean elsewhere in the context.
+    attribute name {xsd:ID}
 ref =
     ## Defines a reference to a Spring bean Id.
     attribute ref {xsd:token}
@@ -311,6 +314,10 @@ http.attlist &=
 http.attlist &=
     ## Prevents the jsessionid parameter from being added to rendered URLs.
     attribute disable-url-rewriting {xsd:boolean}?
+http.attlist &=
+    ## Exposes the list of filters defined by this configuration under this bean name in the application context. May be used by
+    name?
+
 
 access-denied-handler =
     ## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.

+ 12 - 0
config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd

@@ -70,6 +70,13 @@
       </xs:annotation>
     </xs:attribute>
   </xs:attributeGroup>
+  <xs:attributeGroup name="name">
+    <xs:attribute name="name" use="required" type="xs:ID">
+      <xs:annotation>
+        <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:attributeGroup>
   <xs:attributeGroup name="ref">
     <xs:attribute name="ref" use="required" type="xs:token">
       <xs:annotation>
@@ -781,6 +788,11 @@
         <xs:documentation>Prevents the jsessionid parameter from being added to rendered URLs.</xs:documentation>
       </xs:annotation>
     </xs:attribute>
+    <xs:attribute name="name" type="xs:ID">
+      <xs:annotation>
+        <xs:documentation>A bean identifier, used for referring to the bean elsewhere in the context.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
   </xs:attributeGroup>
   
   <xs:attributeGroup name="access-denied-handler.attlist">

+ 18 - 0
config/src/test/groovy/org/springframework/security/config/http/MultiHttpBlockConfigTests.groovy

@@ -3,6 +3,7 @@ package org.springframework.security.config.http
 import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
 import org.springframework.security.config.BeanIds
 import org.springframework.security.web.FilterChainProxy
+import org.junit.Assert
 
 /**
  * Tests scenarios with multiple &lt;http&gt; elements.
@@ -40,4 +41,21 @@ class MultiHttpBlockConfigTests extends AbstractHttpConfigTests {
         then:
         thrown(BeanDefinitionParsingException)
     }
+
+    def namedFilterChainIsExposedAsABean () {
+        xml.http(name: 'basic', pattern: '/basic/**', 'create-session': 'stateless') {
+            'http-basic'()
+        }
+        xml.http(pattern: '/form/**') {
+            'form-login'()
+        }
+        createAppContext()
+        def fcp = appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
+        List filterChains = fcp.getFilterChainMap().values() as List;
+        List basicChain = filterChains[0];
+
+        expect:
+        Assert.assertSame (basicChain, appContext.getBean('basic'))
+    }
+
 }