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
Comment From: jnfeinstein
The reactive version is bean-based. Is this as simple as adding a conditional?
Comment From: sunildabburi
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
Comment From: ssozonoff
@Bean @Primary public DefaultMethodSecurityExpressionHandler getCustomMethodSecurityExpressionHandler() { return new CustomMethodSecurityExpressionHandler(); }
Seems to work as well
Comment From: wickedev
How about avoiding this problem by calling setRoleHierarchy inside ReactiveMethodSecurityConfiguration.methodSecurityExpressionHandler method or adding @ConditionalOnMissingBean annotation?
Comment From: jzheaux
Let's take a look at this after #9401 is merged.
Comment From: LajosPolya
@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
Comment From: jzheaux
Closed in https://github.com/spring-projects/spring-security/pull/15719/commits/60cd8fdc552a340d9b7f7b7085c6e0a7107ecb0b