Hi guys, thanks for the answers, but I finnally got it working in a totally programatic way.It wasn´t an easy solution, but I´d like to share It.
First of all, I could split the problem into 2 parts:
1) Create the proxy for my own beans.
2) Add the security-roles to every bean. Unfortunately, i couldn´t add a xml-based pointcut, as the beans were all of the same class (a generic service). I wanted a way to secure each bean in a different way, despite they were all the same class.
I decided to use the same declaration used by aopalliance ((execution . etc...)
For whom it may interest, this is how I done:
1) Used spring´s BeanNameAutoProxyCreator class, for creating the proxies around the classes i have manually added:
private void addProxies(ConfigurableListableBeanFactory beanFactory, List<String> exportedServices) {
List<String> interceptorNames = findInterceptorNames(beanFactory);
BeanNameAutoProxyCreator beanPostProcessor = new BeanNameAutoProxyCreator();
beanPostProcessor.setBeanNames(exportedServices.toArray(new String[exportedServices.size()]));
beanPostProcessor.setInterceptorNames(interceptorNames.toArray(new String[interceptorNames.size()]));
beanPostProcessor.setBeanFactory(beanFactory);
beanPostProcessor.setOrder(Ordered.LOWEST_PRECEDENCE);
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
@SuppressWarnings("unchecked")
private List<String> findInterceptorNames(ConfigurableListableBeanFactory beanFactory) {
List<String> interceptorNames = new ArrayList<String>();
List<? extends Advisor> list = new BeanFactoryAdvisorRetrievalHelper(beanFactory).findAdvisorBeans();
for (Advisor ad : list) {
Advice advice = ad.getAdvice();
if (advice instanceof MethodInterceptor) {
Map<String, ?> beansOfType = beanFactory.getBeansOfType(advice.getClass());
for (String name : beansOfType.keySet()) {
interceptorNames.add(name);
}
}
}
return interceptorNames;
}
- where exportedServices stands for the beans i wished to proxy
- The beanFactory instance could be fetched using my own implementation of BeanFactoryPostProcessor
2) For the parameterizable secured-like part:
Created a implementation of spring´s MethodDefinitionSource. implementors of this interface are used by MethodSecurityProxy to fetch securedObjects at runtime.
@SuppressWarnings("unchecked")
@Override
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
if (!(object instanceof ReflectiveMethodInvocation)) {
return null;
}
ReflectiveMethodInvocation invokation = (ReflectiveMethodInvocation) object;
if (!(invokation.getThis() instanceof MyService)) {
return null;
}
MyService service = (MyService) invokation.getThis();
Map<String, String> map =getProtectedServiceMethodMap(service);
String roles = map.get(MethodKeyGenerator.generate(invokation.getMethod()));
return roles == null ? null : new ConfigAttributeDefinition(StringUtils.delimitedListToStringArray(roles, ","));
}
- Note that I had to put in a cache the methods wich I wanted to secure for each object instance.
The trickiest part was to register my MethodDefinitionSource impl into the applicationContext, so that the MethodSecurityInterceptor became aware of it:
private void addCrudDefinitionSource() {
DelegatingMethodDefinitionSource source = (DelegatingMethodDefinitionSource) beanFactory.getBean(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE);
try {
Field field = source.getClass().getDeclaredField("methodDefinitionSources");
field.setAccessible(true);
List list = (List) field.get(source);
list.add(new MyMethodDefinitionSource());
} catch (Exception e) {
e.printStackTrace();
}
}
Last, for checking Method entrypoints in a aop-style I used code like the following:
private void addToCache(){ // Ommiting parameters
PointcutExpression expression = parser.parsePointcutExpression(fullExpression);
Method[] methods = clazzToCheck.getMethods();
for (int i = 0; i < methods.length; i++) {
Method currentMethod = methods[i];
boolean matches = expression.matchesMethodExecution(currentMethod).alwaysMatches();
if (matches){
//Add to Cache
}
}