Skip to content

Commit ae8e4d1

Browse files
committed
Produce Exactly One AuthorizationAdvisor Per Annotation
Closes gh-15592
1 parent 27af1df commit ae8e4d1

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityAdvisorRegistrar.java

+54-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,24 @@
1616

1717
package org.springframework.security.config.annotation.method.configuration;
1818

19+
import org.aopalliance.aop.Advice;
20+
import org.aopalliance.intercept.MethodInterceptor;
21+
import org.aopalliance.intercept.MethodInvocation;
22+
import org.jetbrains.annotations.NotNull;
23+
import org.jetbrains.annotations.Nullable;
24+
1925
import org.springframework.aop.Advisor;
26+
import org.springframework.aop.Pointcut;
27+
import org.springframework.aop.PointcutAdvisor;
28+
import org.springframework.aop.framework.AopInfrastructureBean;
2029
import org.springframework.beans.factory.config.BeanDefinition;
30+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2131
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2232
import org.springframework.beans.factory.support.RootBeanDefinition;
2333
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
34+
import org.springframework.core.Ordered;
2435
import org.springframework.core.type.AnnotationMetadata;
36+
import org.springframework.security.authorization.method.AuthorizationAdvisor;
2537

2638
class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
2739

@@ -49,9 +61,49 @@ private void registerAsAdvisor(String prefix, BeanDefinitionRegistry registry) {
4961
if (!(definition instanceof RootBeanDefinition)) {
5062
return;
5163
}
52-
RootBeanDefinition advisor = new RootBeanDefinition((RootBeanDefinition) definition);
64+
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(AdvisorWrapper.class);
65+
builder.setFactoryMethod("of");
66+
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
67+
builder.addConstructorArgReference(interceptorName);
68+
RootBeanDefinition advisor = (RootBeanDefinition) builder.getBeanDefinition();
5369
advisor.setTargetType(Advisor.class);
54-
registry.registerBeanDefinition(prefix + "Advisor", advisor);
70+
registry.registerBeanDefinition(advisorName, advisor);
71+
}
72+
73+
public static final class AdvisorWrapper
74+
implements PointcutAdvisor, MethodInterceptor, Ordered, AopInfrastructureBean {
75+
76+
private final AuthorizationAdvisor advisor;
77+
78+
private AdvisorWrapper(AuthorizationAdvisor advisor) {
79+
this.advisor = advisor;
80+
}
81+
82+
public static AdvisorWrapper of(AuthorizationAdvisor advisor) {
83+
return new AdvisorWrapper(advisor);
84+
}
85+
86+
@Override
87+
public Advice getAdvice() {
88+
return this.advisor.getAdvice();
89+
}
90+
91+
@Override
92+
public Pointcut getPointcut() {
93+
return this.advisor.getPointcut();
94+
}
95+
96+
@Override
97+
public int getOrder() {
98+
return this.advisor.getOrder();
99+
}
100+
101+
@Nullable
102+
@Override
103+
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
104+
return this.advisor.invoke(invocation);
105+
}
106+
55107
}
56108

57109
}

config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java

+57
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,13 @@
3535
import org.junit.jupiter.api.extension.ExtendWith;
3636

3737
import org.springframework.aop.Advisor;
38+
import org.springframework.aop.config.AopConfigUtils;
3839
import org.springframework.aop.support.DefaultPointcutAdvisor;
3940
import org.springframework.aop.support.JdkRegexpMethodPointcut;
41+
import org.springframework.beans.factory.FactoryBean;
4042
import org.springframework.beans.factory.annotation.Autowired;
4143
import org.springframework.beans.factory.config.BeanDefinition;
44+
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
4245
import org.springframework.context.annotation.AdviceMode;
4346
import org.springframework.context.annotation.Bean;
4447
import org.springframework.context.annotation.Configuration;
@@ -63,6 +66,7 @@
6366
import org.springframework.security.authorization.AuthorizationDecision;
6467
import org.springframework.security.authorization.AuthorizationEventPublisher;
6568
import org.springframework.security.authorization.AuthorizationManager;
69+
import org.springframework.security.authorization.method.AuthorizationAdvisor;
6670
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
6771
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor;
6872
import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
@@ -82,6 +86,7 @@
8286
import org.springframework.security.test.context.support.WithAnonymousUser;
8387
import org.springframework.security.test.context.support.WithMockUser;
8488
import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
89+
import org.springframework.stereotype.Component;
8590
import org.springframework.test.context.ContextConfiguration;
8691
import org.springframework.test.context.TestExecutionListeners;
8792
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -953,6 +958,32 @@ void annotationsInChildClassesDoNotAffectSuperclasses() {
953958
this.spring.getContext().getBean(ClassInheritingAbstractClassWithNoAnnotations.class).method();
954959
}
955960

961+
// gh-15592
962+
@Test
963+
void autowireWhenDefaultsThenCreatesExactlyOneAdvisorPerAnnotation() {
964+
this.spring.register(MethodSecurityServiceConfig.class).autowire();
965+
AuthorizationAdvisorProxyFactory proxyFactory = this.spring.getContext()
966+
.getBean(AuthorizationAdvisorProxyFactory.class);
967+
assertThat(proxyFactory).hasSize(5);
968+
assertThat(this.spring.getContext().getBeanNamesForType(AuthorizationAdvisor.class)).hasSize(5)
969+
.containsExactlyInAnyOrder("preFilterAuthorizationMethodInterceptor",
970+
"preAuthorizeAuthorizationMethodInterceptor", "postAuthorizeAuthorizationMethodInterceptor",
971+
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
972+
}
973+
974+
// gh-15592
975+
@Test
976+
void autowireWhenAspectJAutoProxyAndFactoryBeanThenExactlyOneAdvisorPerAnnotation() {
977+
this.spring.register(AspectJAwareAutoProxyAndFactoryBeansConfig.class).autowire();
978+
AuthorizationAdvisorProxyFactory proxyFactory = this.spring.getContext()
979+
.getBean(AuthorizationAdvisorProxyFactory.class);
980+
assertThat(proxyFactory).hasSize(5);
981+
assertThat(this.spring.getContext().getBeanNamesForType(AuthorizationAdvisor.class)).hasSize(5)
982+
.containsExactlyInAnyOrder("preFilterAuthorizationMethodInterceptor",
983+
"preAuthorizeAuthorizationMethodInterceptor", "postAuthorizeAuthorizationMethodInterceptor",
984+
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
985+
}
986+
956987
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
957988
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
958989
}
@@ -1514,4 +1545,30 @@ ClassInheritingAbstractClassWithNoAnnotations inheriting() {
15141545

15151546
}
15161547

1548+
@Configuration
1549+
@EnableMethodSecurity
1550+
static class AspectJAwareAutoProxyAndFactoryBeansConfig {
1551+
1552+
@Bean
1553+
static BeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor() {
1554+
return AopConfigUtils::registerAspectJAnnotationAutoProxyCreatorIfNecessary;
1555+
}
1556+
1557+
@Component
1558+
static class MyFactoryBean implements FactoryBean<Object> {
1559+
1560+
@Override
1561+
public Object getObject() throws Exception {
1562+
return new Object();
1563+
}
1564+
1565+
@Override
1566+
public Class<?> getObjectType() {
1567+
return Object.class;
1568+
}
1569+
1570+
}
1571+
1572+
}
1573+
15171574
}

0 commit comments

Comments
 (0)