From 2eefbf3a23ed6f68ccc23696e10f998b4bbfc968 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Fri, 14 Jan 2011 17:21:22 +0000 Subject: [PATCH] SEC-1657: Added support for 'name' attribute in element to expose filter chain as a list bean. --- .../HttpFirewallBeanDefinitionParser.java | 4 ++- .../HttpSecurityBeanDefinitionParser.java | 26 +++++++++++++++---- .../security/config/spring-security-3.1.rnc | 7 +++++ .../security/config/spring-security-3.1.xsd | 12 +++++++++ .../http/MultiHttpBlockConfigTests.groovy | 18 +++++++++++++ 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/http/HttpFirewallBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/HttpFirewallBeanDefinitionParser.java index 444ed6e77f..40c2559fc8 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpFirewallBeanDefinitionParser.java +++ b/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>(), + new ManagedMap(), pc.extractSource(element)); BeanDefinition filterChainProxy = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY); filterChainProxy.getPropertyValues().addPropertyValue("firewall", new RuntimeBeanReference(ref)); diff --git a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java index 02169337ae..12d818a878 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java +++ b/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> filterChainMap = new ManagedMap>(); + ManagedMap filterChainMap = new ManagedMap(); String filterChainPattern = element.getAttribute(ATT_PATH_PATTERN); @@ -92,7 +93,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } - List 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> filterChainMap, Object source) { + static void registerFilterChainProxy(ParserContext pc, Map 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 diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc index b59a7d3f2f..54a83adb1b 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc +++ b/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. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd index 1bac12711c..61f79e126c 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.1.xsd @@ -70,6 +70,13 @@ + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + @@ -781,6 +788,11 @@ Prevents the jsessionid parameter from being added to rendered URLs. + + + A bean identifier, used for referring to the bean elsewhere in the context. + + diff --git a/config/src/test/groovy/org/springframework/security/config/http/MultiHttpBlockConfigTests.groovy b/config/src/test/groovy/org/springframework/security/config/http/MultiHttpBlockConfigTests.groovy index e93d346fff..ce3abe71dc 100644 --- a/config/src/test/groovy/org/springframework/security/config/http/MultiHttpBlockConfigTests.groovy +++ b/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 <http> 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')) + } + }