Correct PostFilterAuthorizationMethodInterceptor Target Type

Previously, `postFilterAuthorizationMethodInterceptor` mistakenly
was published as an `Advisor`. Because `MethodSecurityAdvisorRegistrar`
re-publishes each pre/post annotation interceptor also as an `Advisor`,
this resulted in a duplicate advisor for `@PostFilter`.

Closes gh-15651
This commit is contained in:
Josh Cummings 2024-08-22 11:44:01 -06:00
parent e92a945a2d
commit 5c604b95fb
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
2 changed files with 28 additions and 2 deletions

View File

@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.method.configuration;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -100,7 +99,7 @@ final class PrePostMethodSecurityConfiguration {
@Bean @Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor postFilterAuthorizationMethodInterceptor() { MethodInterceptor postFilterAuthorizationMethodInterceptor() {
return this.postFilterAuthorizationMethodInterceptor; return this.postFilterAuthorizationMethodInterceptor;
} }

View File

@ -73,6 +73,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
/** /**
@ -432,6 +434,18 @@ public class PrePostMethodSecurityConfigurationTests {
.autowire(); .autowire();
} }
// gh-15651
@Test
@WithMockUser(roles = "ADMIN")
public void adviseWhenPrePostEnabledThenEachInterceptorRunsExactlyOnce() {
this.spring.register(MethodSecurityServiceConfig.class, CustomMethodSecurityExpressionHandlerConfig.class)
.autowire();
MethodSecurityExpressionHandler expressionHandler = this.spring.getContext()
.getBean(MethodSecurityExpressionHandler.class);
this.methodSecurityService.manyAnnotations(new ArrayList<>(Arrays.asList("harold", "jonathan", "tim", "bo")));
verify(expressionHandler, times(4)).createEvaluationContext(any(Supplier.class), any());
}
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() { private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false); return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
} }
@ -491,6 +505,19 @@ public class PrePostMethodSecurityConfigurationTests {
} }
@EnableMethodSecurity
static class CustomMethodSecurityExpressionHandlerConfig {
private final MethodSecurityExpressionHandler expressionHandler = spy(
new DefaultMethodSecurityExpressionHandler());
@Bean
MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
return this.expressionHandler;
}
}
@EnableMethodSecurity @EnableMethodSecurity
static class CustomPermissionEvaluatorConfig { static class CustomPermissionEvaluatorConfig {