Summary

Tried expanding the Spring Security framework with a new Method level annotation, however, baked in classes and programmatic bean creation prevents this.

Actual Behavior

Replace PrePostAnnotationSecurityMetadataSource with a child bean is impossible without code repeating and unnecessary overriding, because of the original PrePostAnnotationSecurityMetadataSource class is baked into the code in GlobalMethodSecurityBeanDefinitionParser, where the bean is instantiated.

Expected Behavior

The implementation of MethodSecurityMetadataSource should be received from the BeanRegistry, instead of being baked into the code

Configuration

// Irrelevant

Version

spring-boot-starter-security:2.1.0.BUILD-SNAPSHOT -> 5.1.0.BUILD-SNAPSHOT

Comment From: jzheaux

Thanks for this suggestion, @rolaca11.

At this point, we are deprecating @EnableGlobalMethodSecurity in favor of @EnableMethodSecurity, etc. and so I'd recommend a different solution.

The preferred solution is to publish a custom @Bean that you refer to in your annotations, like so:

@PreAuthorize("@authz.myAuth(authentication)")
public String method() { ... }

// ...

@Bean 
public MyCustomAuthorizer authz() {
    return new MyCustomAuthorizer();
}

If this doesn't suffice, then you can create a custom implementation of AuthorizationManager<MethodInvocation> and publish like so:

@Bean 
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor preAuthorize(MyCustomAuthorizationManager rules) {
    AnnotationMatchingPointcut pattern = new AnnotationMatchingPointcut(PreAuthorize.class, PreAuthorize.class, true);
    AuthorizationManagerBeforeMethodInterceptor interceptor = 
        new AuthorizationManagerBeforeMethodInterceptor(pattern, rules);
    interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder());
    return interceptor;
}