001: package org.acegisecurity.config;
002:
003: import java.util.ArrayList;
004: import java.util.Iterator;
005: import java.util.List;
006:
007: import org.acegisecurity.annotation.SecurityAnnotationAttributes;
008: import org.acegisecurity.intercept.method.MethodDefinitionAttributes;
009: import org.acegisecurity.intercept.method.MethodDefinitionMap;
010: import org.acegisecurity.intercept.method.MethodDefinitionSource;
011: import org.acegisecurity.intercept.method.MethodDefinitionSourceMapping;
012: import org.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
013: import org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor;
014: import org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor;
015: import org.acegisecurity.runas.RunAsManagerImpl;
016: import org.acegisecurity.util.BeanDefinitionParserUtils;
017: import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
018: import org.springframework.beans.factory.BeanDefinitionStoreException;
019: import org.springframework.beans.factory.config.RuntimeBeanReference;
020: import org.springframework.beans.factory.support.AbstractBeanDefinition;
021: import org.springframework.beans.factory.support.RootBeanDefinition;
022: import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
023: import org.springframework.beans.factory.xml.BeanDefinitionParser;
024: import org.springframework.beans.factory.xml.ParserContext;
025: import org.springframework.metadata.commons.CommonsAttributes;
026: import org.springframework.util.Assert;
027: import org.springframework.util.StringUtils;
028: import org.springframework.util.xml.DomUtils;
029: import org.w3c.dom.Element;
030:
031: /**
032: *
033: * @author Vishal Puri
034: *
035: */
036:
037: public class AuthorizationMethodBeanDefinitionParser extends
038: AbstractBeanDefinitionParser implements BeanDefinitionParser {
039: // ~ static initializers
040: // ================================================================================================
041:
042: public static final String ASPECTJ_ATTRIBUTE = "aspectj";
043:
044: public static final String SPRING_AOP_ATTRIBUTE = "springAop";
045:
046: public static final String SOURCE_ATTRIBUTE = "source";
047:
048: public static final String SOURCE_BEAN_REF = "sourceBeanId";
049:
050: public static final String ATTRIBUTE = "attribute";
051:
052: private static final String CONFIGURATION_ATTRIBUTE = "configuration-attribute";
053:
054: private static final String TYPE_ATTRIBUTE = "type";
055:
056: // ~ Method
057: // ================================================================================================
058:
059: protected AbstractBeanDefinition parseInternal(Element element,
060: ParserContext parserContext) {
061: // <security:authorization-joinpoint aspectj="false|true"
062: // springAop="true|false">
063: // one attribute allowed, aspectj or springAop
064: Assert.isTrue(
065: !(element.hasAttribute(SPRING_AOP_ATTRIBUTE) && element
066: .hasAttribute(ASPECTJ_ATTRIBUTE)),
067: "only one attribute (springAop or aspectj) is allowed");
068:
069: Element urlMappingEle = DomUtils.getChildElementByTagName(
070: element, "url-mapping");
071:
072: String sourceBeanId = urlMappingEle
073: .getAttribute(SOURCE_BEAN_REF);
074: boolean isSourceBeanIdDefined = StringUtils
075: .hasLength(sourceBeanId);
076:
077: if (!isValidConfiguration(urlMappingEle, isSourceBeanIdDefined)) {
078: throw new IllegalArgumentException(
079: " 'custom' value provided by 'source' attribute need to be selected when referring to a bean by 'sourceBeanId' attribute ");
080: }
081:
082: if ((element.hasAttribute(ASPECTJ_ATTRIBUTE))
083: && element.getAttribute(ASPECTJ_ATTRIBUTE).equals(
084: "true")) {
085: // create AspectJSecurityInterceptor
086: if (isSourceBeanIdDefined)
087: return createMethodSecurityInterceptor(
088: AspectJSecurityInterceptor.class,
089: new RuntimeBeanReference(sourceBeanId));
090:
091: return createMethodSecurityInterceptor(
092: AspectJSecurityInterceptor.class,
093: createObjectDefinitionSource(parserContext,
094: urlMappingEle));
095: } else if ((element.hasAttribute(SPRING_AOP_ATTRIBUTE))
096: && element.getAttribute(SPRING_AOP_ATTRIBUTE).equals(
097: "true")) {
098: // create MethodSecurityInterceptor and
099: // MethodDefinitionSourceAdvisor
100: if (isSourceBeanIdDefined)
101: return createMethodSecurityInterceptor(
102: MethodSecurityInterceptor.class,
103: new RuntimeBeanReference(sourceBeanId));
104:
105: return createMethodSecurityInterceptor(
106: MethodSecurityInterceptor.class,
107: createObjectDefinitionSource(parserContext,
108: urlMappingEle));
109: }
110: return null;
111: }
112:
113: /**
114: * @param parserContext
115: * @param firstChild
116: * @param sourceValue
117: * @throws BeanDefinitionStoreException
118: */
119: private MethodDefinitionSource createObjectDefinitionSource(
120: ParserContext parserContext, Element element)
121: throws BeanDefinitionStoreException {
122: String sourceValue = element.getAttribute(SOURCE_ATTRIBUTE);
123: if (sourceValue.equals("xml")) {
124: // create MethodDefinitionSourceEditor
125: Element methodPattern = DomUtils.getChildElementByTagName(
126: element, "method-pattern");
127: String methodToProtect = methodPattern
128: .getAttribute(TYPE_ATTRIBUTE);
129:
130: MethodDefinitionSourceMapping mapping = new MethodDefinitionSourceMapping();
131: MethodDefinitionMap source = new MethodDefinitionMap();
132: List<MethodDefinitionSourceMapping> mappings = new ArrayList<MethodDefinitionSourceMapping>();
133:
134: mapping.setMethodName(methodToProtect);
135:
136: List configAttributes = DomUtils.getChildElementsByTagName(
137: methodPattern, CONFIGURATION_ATTRIBUTE);
138:
139: for (Iterator iter = configAttributes.iterator(); iter
140: .hasNext();) {
141: Element configAttribute = (Element) iter.next();
142: String configAttributeValue = configAttribute
143: .getAttribute(ATTRIBUTE);
144: mapping.addConfigAttribute(configAttributeValue);
145: }
146: mappings.add(mapping);
147: source.setMappings(mappings);
148: return source;
149: } else if (sourceValue.equals("annotations")) {
150: BeanDefinitionParserUtils.registerBeanDefinition(
151: parserContext, new RootBeanDefinition(
152: DefaultAdvisorAutoProxyCreator.class));
153:
154: MethodDefinitionAttributes source = new MethodDefinitionAttributes();
155: SecurityAnnotationAttributes attributes = new SecurityAnnotationAttributes();
156: source.setAttributes(attributes);
157: return source;
158: } else if (sourceValue.equals("attributes")) {
159: // create CommonsAttributes
160: CommonsAttributes attributes = new CommonsAttributes();
161: // objectDefinitionSource and inject attributes
162: MethodDefinitionAttributes source = new MethodDefinitionAttributes();
163: source.setAttributes(attributes);
164:
165: // register DefaultAdvisorAutoProxyCreator with parseContext
166: BeanDefinitionParserUtils.registerBeanDefinition(
167: parserContext, new RootBeanDefinition(
168: DefaultAdvisorAutoProxyCreator.class));
169:
170: // register MethodDefinitionSourceAdvisor autowire="constructor"
171: registerMethodDefinitionSourceAdvisor(parserContext);
172: return source;
173: }
174: return null;
175: }
176:
177: /**
178: * @param parserContext
179: * @throws BeanDefinitionStoreException
180: */
181: private void registerMethodDefinitionSourceAdvisor(
182: ParserContext parserContext)
183: throws BeanDefinitionStoreException {
184: RootBeanDefinition methodSecurityAdvisor = new RootBeanDefinition(
185: MethodDefinitionSourceAdvisor.class);
186: methodSecurityAdvisor
187: .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
188: BeanDefinitionParserUtils.registerBeanDefinition(parserContext,
189: methodSecurityAdvisor);
190: }
191:
192: /**
193: * Creates BeanDefinition for MethodSecurityInterceptor
194: * MethodSecurityInterceptor autodetects 'authenticationManager' and
195: * 'accessDecisionManager'
196: * @param name
197: *
198: * @return
199: */
200: private RootBeanDefinition createMethodSecurityInterceptor(
201: Class interceptorType, Object object) {
202: Assert.notNull(object, "objectDefinitionSource required");
203: RootBeanDefinition securityInterceptor = new RootBeanDefinition(
204: interceptorType);
205: if (RuntimeBeanReference.class.isAssignableFrom(object
206: .getClass())) {
207: RuntimeBeanReference source = (RuntimeBeanReference) object;
208: securityInterceptor.getPropertyValues().addPropertyValue(
209: "objectDefinitionSource", source);
210: } else if (MethodDefinitionSource.class.isAssignableFrom(object
211: .getClass())) {
212: MethodDefinitionSource source = (MethodDefinitionSource) object;
213: securityInterceptor.getPropertyValues().addPropertyValue(
214: "objectDefinitionSource", source);
215: }
216: securityInterceptor.getPropertyValues().addPropertyValue(
217: "validateConfigAttributes", Boolean.FALSE);
218: RootBeanDefinition runAsManager = createRunAsManager();
219: securityInterceptor.getPropertyValues().addPropertyValue(
220: "runAsManager", runAsManager);
221: return securityInterceptor;
222: }
223:
224: private RootBeanDefinition createRunAsManager() {
225: RootBeanDefinition runAsManager = new RootBeanDefinition(
226: RunAsManagerImpl.class);
227: runAsManager.getPropertyValues().addPropertyValue("key",
228: "my_run_as_password");
229: return runAsManager;
230: }
231:
232: /**
233: * Checks if 'custom' option is picked for 'source' attribute when
234: * 'sourceBeanId' attribute is provided.
235: * <p>
236: * The valid configuration example:<br/> <security:url-mapping
237: * source="custom" sourceBeanId="referenceToObjectDefinitionSource"/>
238: * </p>
239: * @param urlMappingElement
240: * @return boolean Returns 'true' if configuration is accepted otherwise
241: * returns 'false'
242: */
243: private boolean isValidConfiguration(Element urlMappingElement,
244: boolean isRefDefined) {
245: Assert.notNull(urlMappingElement,
246: "invalid tag - expected 'url-mapping' ");
247: Assert
248: .isTrue(urlMappingElement.getLocalName().equals(
249: "url-mapping"),
250: "invalid tag - expected 'url-mapping' ");
251: if (isRefDefined
252: && (urlMappingElement.getAttribute(SOURCE_ATTRIBUTE)
253: .compareTo("custom") != 0)) {
254: return false;
255: }
256: return true;
257: }
258: }
|