From 1a7aaa85c40a31f13ff4c27339044350f6703dd3 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Fri, 9 Nov 2012 14:34:00 -0600 Subject: [PATCH] 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. --- .../method/ProtectPointcutPostProcessor.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/method/ProtectPointcutPostProcessor.java b/config/src/main/java/org/springframework/security/config/method/ProtectPointcutPostProcessor.java index 8fa3f1b925..0c0dfa8691 100644 --- a/config/src/main/java/org/springframework/security/config/method/ProtectPointcutPostProcessor.java +++ b/config/src/main/java/org/springframework/security/config/method/ProtectPointcutPostProcessor.java @@ -51,6 +51,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor { private final PointcutParser parser; private final Set processedBeans = new HashSet(); + public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) { Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required"); this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource; @@ -80,26 +81,34 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor { return bean; } - // Obtain methods for the present bean - Method[] methods; - try { - methods = bean.getClass().getMethods(); - } catch (Exception e) { - throw new IllegalStateException(e.getMessage()); - } + synchronized(processedBeans) { + // check again synchronized this time + if (processedBeans.contains(beanName)) { + return bean; + } - // 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 + // Obtain methods for the present bean + Method[] methods; + try { + methods = bean.getClass().getMethods(); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } + + // 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; }