Spring Security AspectJMode with @EnableGlobalMeth

2019-09-06 15:11发布

问题:

I am trying to move from XML Config to JavaConfig with spring-security 4.0.0.M1

This is my Configuration which works:

@Configuration
@ImportResource("classpath:applicationContext-security.xml")
public class MethodSecurityXmlConfig
{}

and applicationContext-security.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd
     ">
    <security:global-method-security mode="aspectj" proxy-target-class="false" pre-post-annotations="enabled">
        <security:expression-handler ref="expressionHandler" />
    </security:global-method-security>

    <bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
        <property name="permissionEvaluator" ref="delegatingPermissionEvaluator" />
    </bean>
</beans>

I have service methods like this:

@Transactional(readOnly = false)
@PreAuthorize("hasPermission(#form, 'idForm')")
public boolean runAction ( IdForm form, Errors errors ) throws Exception {...}

Additionally I have an Aspect Ordering Advice like this as my PermissionEvaluator needs a Transaction too. So Transactional should run before Security.

public aspect AspectOrdering
{
    declare precedence : AnnotationTransactionAspect, *SecurityAspect;
}

I do compile time weaving with maven with spring-security-aspects. If I debug it I can see AspectJMethodSecurityInterceptor is being invoked on this method (after Transactional..).
So, this just works fine.

Now I only switch from my MethodSecurityXmlConfig to this configuration class:

@Configuration
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
{
    @Resource
    private DelegatingPermissionEvaluator   delegatingPermissionEvaluator;

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler ( )
    {
        DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
        defaultMethodSecurityExpressionHandler.setPermissionEvaluator(delegatingPermissionEvaluator);
        return defaultMethodSecurityExpressionHandler;
    }
}

The method call is still intercepted by Spring Security but it does not do it with AspectJ Mode, it uses AopProxy!

And because of not using AspectJ my ordering isn't working, so Spring Security runs before @Transactional.

When I debug this, I can see MethodSecurityInterceptor being invoked, but not AspectJMethodSecurityInterceptor. The method is still advised but AspectJMethodSecurityInterceptor might never get called because the AnnotationSecurityAspect is not configured and calls return proceed() as it does not have access to an AspectJMethodSecurityInterceptor.

For me it seems to be a bug. Before raising an issue I would like to ask:

Did I miss some configuration to get Method Security with AspectJ working?

回答1:

This element is incoherent :

<security:global-method-security mode="aspectj" proxy-target-class="false" pre-post-annotations="enabled">

According to Spring Security Reference Manual / Appendix / The Security Namespace / Method Security / <global-method-security> :

  • mode="aspectj" : This attribute can be set to "aspectj" to specify that AspectJ should be used instead of the default Spring AOP
  • proxy-target-class="false" : proxy-target-class If true, class based proxying will be used instead of interface based proxying

You are asking both for JDK proxying and AspectJ mode. First remove proxy-target-class="false", and install an AspectJ weaving mechanism if you have not already done.



回答2:

It is a bug in Spring Security 4.0.0.M1, see https://jira.spring.io/browse/SEC-2698