spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

Allow the customization of the Reactive Method Security MethodSecurityExpressionHandler

Open codependent opened this issue 6 years ago • 6 comments

Summary

I need to customize the behavior of the reactive method security expression handler. In the non reactive version this could be done extending GlobalMethodSecurityConfiguration as stated in the documentation:

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        // ... create and return custom MethodSecurityExpressionHandler ...
        return expressionHandler;
    }
}

However, the reactive equivalent ReactiveMethodSecurityConfiguration is a package-private class and can't be extended to modify the framework.

Actual Behavior

We can't modify the expression handler.

Expected Behavior

Allow the definition of a custom MethodSecurityExpressionHandler

Configuration

...

Version

5.2.0.RC1

codependent avatar Sep 19 '19 22:09 codependent

The reactive version is bean-based. Is this as simple as adding a conditional?

jnfeinstein avatar Jan 29 '20 02:01 jnfeinstein

I had a similar problem. I tried this approach and it worked.

Create the following configuration class that initializes the required security beans along with my custom expression handler bean.

class AuthorizationConfig {

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    DelegatingMethodSecurityMetadataSource methodMetadataSource(
            MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
        var attributeFactory = new ExpressionBasedAnnotationAttributeFactory(methodSecurityExpressionHandler);
        var prePostSource = new PrePostAnnotationSecurityMetadataSource(attributeFactory);
        return new DelegatingMethodSecurityMetadataSource(List.of(prePostSource));
    }

    @Bean
    PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(AbstractMethodSecurityMetadataSource source,
            MethodSecurityExpressionHandler handler) {
        var postAdvice = new ExpressionBasedPostInvocationAdvice(handler);
        var preAdvice = new ExpressionBasedPreInvocationAdvice();
        preAdvice.setExpressionHandler(handler);
        return new PrePostAdviceReactiveMethodInterceptor(source, preAdvice, postAdvice);
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMethodSecurityMetadataSource source) {
        return new MethodSecurityMetadataSourceAdvisor("securityMethodInterceptor", source,
                "methodMetadataSource");
    }

    @Bean
    MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
        return new CustomMethodSecurityExpressionHandler(); // my custom expression handler
    }
}

DO NOT use @EnableReactiveMethodSecurity as the above code does what it does but not completely as the above implementation does not take into consideration the import order and default role prefixes which were not required in my case. If you want to use them too, you can clone the code from ReactiveMethodSecurityConfiguration

Hope this helps

sunildabburi avatar May 03 '21 17:05 sunildabburi

@Bean @Primary public DefaultMethodSecurityExpressionHandler getCustomMethodSecurityExpressionHandler() { return new CustomMethodSecurityExpressionHandler(); }

Seems to work as well

ssozonoff avatar Oct 18 '21 10:10 ssozonoff

How about avoiding this problem by calling setRoleHierarchy inside ReactiveMethodSecurityConfiguration.methodSecurityExpressionHandler method or adding @ConditionalOnMissingBean annotation?

wickedev avatar Jan 08 '22 17:01 wickedev

Let's take a look at this after #9401 is merged.

jzheaux avatar Mar 31 '22 00:03 jzheaux

@bean @primary public DefaultMethodSecurityExpressionHandler getCustomMethodSecurityExpressionHandler() { return new CustomMethodSecurityExpressionHandler(); }

Seems to work as well

This worked for me but my CustomMethodSecurityExpressionHandler class has to be annotated with @Component and @Primary

LajosPolya avatar May 31 '23 19:05 LajosPolya

Closed in https://github.com/spring-projects/spring-security/pull/15719/commits/60cd8fdc552a340d9b7f7b7085c6e0a7107ecb0b

jzheaux avatar Sep 10 '24 19:09 jzheaux