Răsfoiți Sursa

SEC-271: Impemented FilterSecurityInovation parser for 'authorization-http-url' tag

Vishal Puri 18 ani în urmă
părinte
comite
97a568c078

+ 170 - 0
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<FilterInvocationDefinitionSourceMapping> mappings = new ArrayList<FilterInvocationDefinitionSourceMapping>();
+
+		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;
+	}
+
+}

+ 35 - 0
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());
+	}
+}

+ 62 - 0
sandbox/spring-security-config/src/test/resources/org/acegisecurity/config/authorization-http-config.xml

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:security="http://www.springframework.org/schema/security"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
+http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
+
+	<!-- ensure element name is not overlapping with portlet or spring web flow or tapestry URI patterns, 
+		as this filter is incompatible with them -->
+
+	<import resource="remember-me-defaults.xml" />
+
+	<security:authorization-http-url id="authorizationhttp">
+		<security:url-mapping
+			source="xml - the default and no other options"
+			sourceBeanId="referenceToTheirObjectDefinitionSource">
+			<!-- Specify security:uri-patterns in order of processing; each pattern must specify EITHER a 
+				regularExpression OR a path, but not both and ALL patterns in the url-mapping MUST be of the 
+				SAME type (ie cannot mix a regular expression and Ant Path) - give exception if tried -->
+			<security:uri-pattern regularExpression="/**">
+				<security:configuration-attribute attribute="ROLE_A" />
+				<security:configuration-attribute attribute="ROLE_B" />
+			</security:uri-pattern>
+			<security:uri-pattern 
+				regularExpression="whatever">
+				<security:configuration-attribute attribute="ROLE_A" />
+			</security:uri-pattern>
+		</security:url-mapping>
+	</security:authorization-http-url>
+
+
+
+	<!--<bean id="filterInvocationInterceptor"
+		class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
+		<property name="authenticationManager"
+		ref="authenticationManager" />
+		<property name="accessDecisionManager">
+		<bean class="org.acegisecurity.vote.AffirmativeBased">
+		<property name="allowIfAllAbstainDecisions"
+		value="false" />
+		<property name="decisionVoters">
+		<list>
+		<bean class="org.acegisecurity.vote.RoleVoter" />
+		<bean
+		class="org.acegisecurity.vote.AuthenticatedVoter" />
+		</list>
+		</property>
+		</bean>
+		</property>
+		<property name="objectDefinitionSource">
+		<value>
+		CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
+		PATTERN_TYPE_APACHE_ANT
+		/acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
+		/**=IS_AUTHENTICATED_REMEMBERED
+		
+		</value>
+		</property>
+		</bean>
+	-->
+</beans>