diff --git a/sandbox/spring-security-config/src/main/java/org/acegisecurity/config/FilterSecurityInterceptorBeanDefinitionParser.java b/sandbox/spring-security-config/src/main/java/org/acegisecurity/config/FilterSecurityInterceptorBeanDefinitionParser.java new file mode 100644 index 0000000000..577ac2eafb --- /dev/null +++ b/sandbox/spring-security-config/src/main/java/org/acegisecurity/config/FilterSecurityInterceptorBeanDefinitionParser.java @@ -0,0 +1,170 @@ +package org.acegisecurity.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.acegisecurity.intercept.web.FilterInvocationDefinitionDecorator; +import org.acegisecurity.intercept.web.FilterInvocationDefinitionSourceMapping; +import org.acegisecurity.intercept.web.FilterSecurityInterceptor; +import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap; +import org.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap; +import org.acegisecurity.util.BeanDefinitionParserUtils; +import org.acegisecurity.vote.AffirmativeBased; +import org.acegisecurity.vote.AuthenticatedVoter; +import org.acegisecurity.vote.RoleVoter; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.Assert; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * @author Vishal Puri + * + */ +public class FilterSecurityInterceptorBeanDefinitionParser extends AbstractBeanDefinitionParser { + + private static final String OBJECT_DEFINITION_SOURCE_PROPERTY = "objectDefinitionSource"; + + private static final String OBJECT_DEFINITION_SOURCE_REF_ATTRIBUTE = "sourceBeanId"; + + private static final String PATH_ATTRIBUTE = "path"; + + private static final String REG_EX_ATTRIBUTE = "regularExpression"; + + private static final String CONFIGURATION_ATTRIB_ATTRIBUTE = "attribute"; + + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + return createBeanDefinitionForFilterSecurityInterceptor(element, parserContext); + } + + protected static RootBeanDefinition createBeanDefinitionForFilterSecurityInterceptor(Element element, + ParserContext parserContext) { + RootBeanDefinition filterInvocationInterceptor = new RootBeanDefinition(FilterSecurityInterceptor.class); + + RootBeanDefinition accessDecisionManager = createAccessDecisionManagerAffirmativeBased(); + filterInvocationInterceptor.getPropertyValues() + .addPropertyValue("accessDecisionManager", accessDecisionManager); + + FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator(); + FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping(); + List mappings = new ArrayList(); + + Element firstChild = DomUtils.getChildElementByTagName(element, "url-mapping"); + // if 'url-mapping' element is defined + if (firstChild != null) { + BeanDefinitionParserUtils.setPropertyIfAvailable(firstChild, OBJECT_DEFINITION_SOURCE_REF_ATTRIBUTE, + OBJECT_DEFINITION_SOURCE_PROPERTY, true/* RuntimeBeanReference */, filterInvocationInterceptor); + // get 'uri-pattern' or 'path' attribute. not both can be specified + // together + List uriPatternElements = DomUtils.getChildElementsByTagName(firstChild, "uri-pattern"); + boolean patternToMatchCreated = false; + + Node patternAttribute = null; + + String url = ""; + + boolean isPathFound = false; + for (Iterator it = uriPatternElements.iterator(); it.hasNext();) { + Element uriPattern = (Element) it.next(); + + /* path or pattern - only one attribute is allowed */ + NamedNodeMap map = uriPattern.getAttributes(); + + Assert.isTrue(map.getLength() == 1, + "only 'path' or 'regularExperssion' attribute allowed with 'uri-pattern' tag"); + + // check if typecreated variable is false then create a type and + // store it somewhere and set typecreated variable to true + if (!patternToMatchCreated) { + // should only be one attribute "path" or + // "regularExpression" + patternAttribute = map.item(0); + // set this variable to true + patternToMatchCreated = true; + // get the attributes and set the decoratd type + // appropriately + if (uriPattern.hasAttribute(PATH_ATTRIBUTE)) { + isPathFound = true; + url = uriPattern.getAttribute(PATH_ATTRIBUTE); + source.setDecorated(new PathBasedFilterInvocationDefinitionMap()); + } + else if (uriPattern.hasAttribute(REG_EX_ATTRIBUTE)) { + url = uriPattern.getAttribute(REG_EX_ATTRIBUTE); + source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap()); + } + } + else { + // type created already so check if it matches with the + // current element + // if it matches get the one attribute "path" or + // "regularExpression" and apply as property + uriPattern.getAttribute(patternAttribute.getLocalName()); + Assert + .hasLength(uriPattern.getAttribute(patternAttribute.getLocalName()), + " ALL uri-pattern tags in the url-mapping must be of the same type (ie cannot mix a regular expression and Ant Path)"); + + if (isPathFound) { + url = uriPattern.getAttribute(PATH_ATTRIBUTE); + } + else { + url = uriPattern.getAttribute(REG_EX_ATTRIBUTE); + } + + } + mapping.setUrl(url); + // get child elements 'configuration-attribute' + List configAttributes = DomUtils.getChildElementsByTagName(uriPattern, "configuration-attribute"); + + for (Iterator iter = configAttributes.iterator(); iter.hasNext();) { + Element configAttribute = (Element) iter.next(); + String configAttributeValue = configAttribute.getAttribute(CONFIGURATION_ATTRIB_ATTRIBUTE); + mapping.addConfigAttribute(configAttributeValue); + } + + } + + } + // default properties + else { + String url1 = "/acegilogin.jsp"; + String value1 = "IS_AUTHENTICATED_ANONYMOUSLY"; + + String url2 = "/**"; + String value2 = "IS_AUTHENTICATED_REMEMBERED"; + + mapping.setUrl(url1); + mapping.addConfigAttribute(value1); + + mapping.setUrl(url2); + mapping.addConfigAttribute(value2); + } + + mappings.add(mapping); + source.setMappings(mappings); + filterInvocationInterceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", + source.getDecorated()); + return filterInvocationInterceptor; + } + + protected static RootBeanDefinition createAccessDecisionManagerAffirmativeBased() { + ManagedList decisionVoters = new ManagedList(); + RootBeanDefinition accessDecisionManager = new RootBeanDefinition(AffirmativeBased.class); + accessDecisionManager.getPropertyValues().addPropertyValue("allowIfAllAbstainDecisions", Boolean.FALSE); + RootBeanDefinition authenticatedVoter = new RootBeanDefinition(AuthenticatedVoter.class); + RootBeanDefinition roleVoter = new RootBeanDefinition(RoleVoter.class); + decisionVoters.add(authenticatedVoter); + decisionVoters.add(roleVoter); + accessDecisionManager.getPropertyValues().addPropertyValue("decisionVoters", decisionVoters); + return accessDecisionManager; + } + +} diff --git a/sandbox/spring-security-config/src/test/java/org/acegisecurity/config/FilterSecurityInterceptorBeanDefinitionParserTests.java b/sandbox/spring-security-config/src/test/java/org/acegisecurity/config/FilterSecurityInterceptorBeanDefinitionParserTests.java new file mode 100644 index 0000000000..a9a0febeff --- /dev/null +++ b/sandbox/spring-security-config/src/test/java/org/acegisecurity/config/FilterSecurityInterceptorBeanDefinitionParserTests.java @@ -0,0 +1,35 @@ +package org.acegisecurity.config; + +import junit.framework.TestCase; + +import org.acegisecurity.AccessDecisionManager; +import org.acegisecurity.intercept.web.FilterSecurityInterceptor; +import org.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap; +import org.acegisecurity.vote.AffirmativeBased; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Vishal Puri + */ +public class FilterSecurityInterceptorBeanDefinitionParserTests extends TestCase { + + public void testParsingBeanDefinition() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "org/acegisecurity/config/authorization-http-config.xml"); + ConfigurableListableBeanFactory bf = (ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory(); + String[] beanNames = bf.getBeanNamesForType(FilterSecurityInterceptor.class); + assertEquals(1, beanNames.length); + BeanDefinition def = bf.getBeanDefinition(beanNames[0]); + assertEquals(2, def.getPropertyValues().size()); + PropertyValue objectDefinitionSource = def.getPropertyValues().getPropertyValue("objectDefinitionSource"); + assertTrue(objectDefinitionSource.getValue() instanceof RegExpBasedFilterInvocationDefinitionMap); + PropertyValue accessDecisionManager = def.getPropertyValues().getPropertyValue("accessDecisionManager"); + BeanDefinition definition = (RootBeanDefinition) accessDecisionManager.getValue() ; + assertEquals("org.acegisecurity.vote.AffirmativeBased" , definition.getBeanClassName()); + } +} diff --git a/sandbox/spring-security-config/src/test/resources/org/acegisecurity/config/authorization-http-config.xml b/sandbox/spring-security-config/src/test/resources/org/acegisecurity/config/authorization-http-config.xml new file mode 100644 index 0000000000..07ac8a9c58 --- /dev/null +++ b/sandbox/spring-security-config/src/test/resources/org/acegisecurity/config/authorization-http-config.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file