SEC-2066: ProtectPointcutPostProcessor is now ThreadSafe

Previously a ConcurrentModificationException could occur when
PointcutExpression.matchesMethodExecution was performed in multiple threads. Another
issue was that beans may get processed multiple times.

Now a lock is performed to ensure that only a single thread has access to
PointcutExpression.matchesMethodExecution and that each bean only gets processed once.
This commit is contained in:
Rob Winch 2012-11-09 14:34:00 -06:00
parent 51fd83060e
commit 1a7aaa85c4

View File

@ -51,6 +51,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
private final PointcutParser parser; private final PointcutParser parser;
private final Set<String> processedBeans = new HashSet<String>(); private final Set<String> processedBeans = new HashSet<String>();
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) { public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required"); Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource; this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource;
@ -80,26 +81,34 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
return bean; return bean;
} }
// Obtain methods for the present bean synchronized(processedBeans) {
Method[] methods; // check again synchronized this time
try { if (processedBeans.contains(beanName)) {
methods = bean.getClass().getMethods(); return bean;
} catch (Exception e) { }
throw new IllegalStateException(e.getMessage());
}
// Check to see if any of those methods are compatible with our pointcut expressions // Obtain methods for the present bean
for (Method method : methods) { Method[] methods;
for (PointcutExpression expression : pointCutExpressions) { try {
// Try for the bean class directly methods = bean.getClass().getMethods();
if (attemptMatch(bean.getClass(), method, expression, beanName)) { } catch (Exception e) {
// We've found the first expression that matches this method, so move onto the next method now throw new IllegalStateException(e.getMessage());
break; // the "while" loop, not the "for" loop }
// Check to see if any of those methods are compatible with our pointcut expressions
for (Method method : methods) {
for (PointcutExpression expression : pointCutExpressions) {
// Try for the bean class directly
if (attemptMatch(bean.getClass(), method, expression, beanName)) {
// We've found the first expression that matches this method, so move onto the next method now
break; // the "while" loop, not the "for" loop
}
} }
} }
processedBeans.add(beanName);
} }
processedBeans.add(beanName);
return bean; return bean;
} }