1 package org.springframework.security.config;
2
3 import java.util.Iterator;
4 import java.util.LinkedHashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.springframework.aop.config.AopNamespaceUtils;
9 import org.springframework.beans.factory.config.BeanDefinition;
10 import org.springframework.beans.factory.config.RuntimeBeanReference;
11 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
12 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
13 import org.springframework.beans.factory.support.ManagedList;
14 import org.springframework.beans.factory.support.RootBeanDefinition;
15 import org.springframework.beans.factory.xml.BeanDefinitionParser;
16 import org.springframework.beans.factory.xml.ParserContext;
17 import org.springframework.security.ConfigAttributeDefinition;
18 import org.springframework.security.intercept.method.DelegatingMethodDefinitionSource;
19 import org.springframework.security.intercept.method.MapBasedMethodDefinitionSource;
20 import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
21 import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
22 import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
23 import org.springframework.util.ClassUtils;
24 import org.springframework.util.StringUtils;
25 import org.springframework.util.xml.DomUtils;
26 import org.w3c.dom.Element;
27
28
29
30
31
32
33
34 class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
35 public static final String SECURED_DEPENDENCY_CLASS = "org.springframework.security.annotation.Secured";
36 public static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodDefinitionSource";
37 public static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.Jsr250MethodDefinitionSource";
38 public static final String JSR_250_VOTER_CLASS = "org.springframework.security.annotation.Jsr250Voter";
39 private static final String ATT_ACCESS = "access";
40 private static final String ATT_EXPRESSION = "expression";
41 private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
42 private static final String ATT_USE_JSR250 = "jsr250-annotations";
43 private static final String ATT_USE_SECURED = "secured-annotations";
44
45 private void validatePresent(String className, Element element, ParserContext parserContext) {
46 if (!ClassUtils.isPresent(className, parserContext.getReaderContext().getBeanClassLoader())) {
47 parserContext.getReaderContext().error("Cannot locate '" + className + "'", element);
48 }
49 }
50
51 public BeanDefinition parse(Element element, ParserContext parserContext) {
52 Object source = parserContext.extractSource(element);
53
54 ManagedList delegates = new ManagedList();
55
56 boolean jsr250Enabled = registerAnnotationBasedMethodDefinitionSources(element, parserContext, delegates);
57
58 MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
59 delegates.add(mapBasedMethodDefinitionSource);
60
61
62 Map pointcutMap = parseProtectPointcuts(parserContext,
63 DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
64
65 if (pointcutMap.size() > 0) {
66 registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodDefinitionSource, source);
67 }
68
69 registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
70
71
72 String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
73
74 if (!StringUtils.hasText(accessManagerId)) {
75 ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
76
77 if (jsr250Enabled) {
78 ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
79 }
80
81 accessManagerId = BeanIds.ACCESS_MANAGER;
82 }
83
84 registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
85
86 registerAdvisor(parserContext, source);
87
88 AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
89
90 return null;
91 }
92
93
94
95
96
97 private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
98 boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
99 boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
100
101
102 if (useSecured) {
103 validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
104 validatePresent(SECURED_DEPENDENCY_CLASS, element, pc);
105 delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
106 }
107
108 if (useJsr250) {
109 validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
110 validatePresent(JSR_250_VOTER_CLASS, element, pc);
111 delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
112 }
113
114 return useJsr250;
115 }
116
117 private void registerDelegatingMethodDefinitionSource(ParserContext parserContext, ManagedList delegates, Object source) {
118 if (parserContext.getRegistry().containsBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE)) {
119 parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
120 }
121 RootBeanDefinition delegatingMethodDefinitionSource = new RootBeanDefinition(DelegatingMethodDefinitionSource.class);
122 delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
123 delegatingMethodDefinitionSource.setSource(source);
124 delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
125 parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
126 }
127
128 private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map pointcutMap,
129 MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource, Object source) {
130 RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
131 ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
132 ppbp.setSource(source);
133 ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodDefinitionSource);
134 ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
135 parserContext.getRegistry().registerBeanDefinition(BeanIds.PROTECT_POINTCUT_POST_PROCESSOR, ppbp);
136 }
137
138 private Map parseProtectPointcuts(ParserContext parserContext, List protectPointcutElts) {
139 Map pointcutMap = new LinkedHashMap();
140
141 for (Iterator i = protectPointcutElts.iterator(); i.hasNext();) {
142 Element childElt = (Element) i.next();
143 String accessConfig = childElt.getAttribute(ATT_ACCESS);
144 String expression = childElt.getAttribute(ATT_EXPRESSION);
145
146 if (!StringUtils.hasText(accessConfig)) {
147 parserContext.getReaderContext().error("Access configuration required", parserContext.extractSource(childElt));
148 }
149
150 if (!StringUtils.hasText(expression)) {
151 parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt));
152 }
153
154 ConfigAttributeDefinition def = new ConfigAttributeDefinition(StringUtils.commaDelimitedListToStringArray(accessConfig));
155 pointcutMap.put(expression, def);
156 }
157
158 return pointcutMap;
159 }
160
161 private void registerMethodSecurityInterceptor(ParserContext parserContext, String accessManagerId, Object source) {
162 RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
163 interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
164 interceptor.setSource(source);
165
166 interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
167 interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
168 interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
169 parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
170 parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
171
172 parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
173 new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
174 }
175
176 private void registerAdvisor(ParserContext parserContext, Object source) {
177 RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
178 advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
179 advisor.setSource(source);
180 advisor.getConstructorArgumentValues().addGenericArgumentValue(BeanIds.METHOD_SECURITY_INTERCEPTOR);
181 advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
182
183 parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
184 }
185 }