mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-09 06:50:05 +00:00
Produce Exactly One AuthorizationAdvisor Per Annotation
Closes gh-15592
This commit is contained in:
parent
27af1df87d
commit
ae8e4d148e
@ -16,12 +16,24 @@
|
|||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
|
import org.aopalliance.aop.Advice;
|
||||||
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.aop.Advisor;
|
import org.springframework.aop.Advisor;
|
||||||
|
import org.springframework.aop.Pointcut;
|
||||||
|
import org.springframework.aop.PointcutAdvisor;
|
||||||
|
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
||||||
|
|
||||||
class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
|
class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
|
||||||
|
|
||||||
@ -49,9 +61,49 @@ class MethodSecurityAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
|
|||||||
if (!(definition instanceof RootBeanDefinition)) {
|
if (!(definition instanceof RootBeanDefinition)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RootBeanDefinition advisor = new RootBeanDefinition((RootBeanDefinition) definition);
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(AdvisorWrapper.class);
|
||||||
|
builder.setFactoryMethod("of");
|
||||||
|
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
builder.addConstructorArgReference(interceptorName);
|
||||||
|
RootBeanDefinition advisor = (RootBeanDefinition) builder.getBeanDefinition();
|
||||||
advisor.setTargetType(Advisor.class);
|
advisor.setTargetType(Advisor.class);
|
||||||
registry.registerBeanDefinition(prefix + "Advisor", advisor);
|
registry.registerBeanDefinition(advisorName, advisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class AdvisorWrapper
|
||||||
|
implements PointcutAdvisor, MethodInterceptor, Ordered, AopInfrastructureBean {
|
||||||
|
|
||||||
|
private final AuthorizationAdvisor advisor;
|
||||||
|
|
||||||
|
private AdvisorWrapper(AuthorizationAdvisor advisor) {
|
||||||
|
this.advisor = advisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdvisorWrapper of(AuthorizationAdvisor advisor) {
|
||||||
|
return new AdvisorWrapper(advisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Advice getAdvice() {
|
||||||
|
return this.advisor.getAdvice();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pointcut getPointcut() {
|
||||||
|
return this.advisor.getPointcut();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return this.advisor.getOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
|
||||||
|
return this.advisor.invoke(invocation);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,13 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
import org.springframework.aop.Advisor;
|
import org.springframework.aop.Advisor;
|
||||||
|
import org.springframework.aop.config.AopConfigUtils;
|
||||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||||
import org.springframework.aop.support.JdkRegexpMethodPointcut;
|
import org.springframework.aop.support.JdkRegexpMethodPointcut;
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
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.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||||
import org.springframework.context.annotation.AdviceMode;
|
import org.springframework.context.annotation.AdviceMode;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -63,6 +66,7 @@ import org.springframework.security.access.prepost.PreFilter;
|
|||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor;
|
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor;
|
||||||
import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
|
import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
|
||||||
@ -82,6 +86,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
|||||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||||
import org.springframework.security.test.context.support.WithMockUser;
|
import org.springframework.security.test.context.support.WithMockUser;
|
||||||
import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
|
import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.TestExecutionListeners;
|
import org.springframework.test.context.TestExecutionListeners;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
@ -953,6 +958,32 @@ public class PrePostMethodSecurityConfigurationTests {
|
|||||||
this.spring.getContext().getBean(ClassInheritingAbstractClassWithNoAnnotations.class).method();
|
this.spring.getContext().getBean(ClassInheritingAbstractClassWithNoAnnotations.class).method();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-15592
|
||||||
|
@Test
|
||||||
|
void autowireWhenDefaultsThenCreatesExactlyOneAdvisorPerAnnotation() {
|
||||||
|
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||||
|
AuthorizationAdvisorProxyFactory proxyFactory = this.spring.getContext()
|
||||||
|
.getBean(AuthorizationAdvisorProxyFactory.class);
|
||||||
|
assertThat(proxyFactory).hasSize(5);
|
||||||
|
assertThat(this.spring.getContext().getBeanNamesForType(AuthorizationAdvisor.class)).hasSize(5)
|
||||||
|
.containsExactlyInAnyOrder("preFilterAuthorizationMethodInterceptor",
|
||||||
|
"preAuthorizeAuthorizationMethodInterceptor", "postAuthorizeAuthorizationMethodInterceptor",
|
||||||
|
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
// gh-15592
|
||||||
|
@Test
|
||||||
|
void autowireWhenAspectJAutoProxyAndFactoryBeanThenExactlyOneAdvisorPerAnnotation() {
|
||||||
|
this.spring.register(AspectJAwareAutoProxyAndFactoryBeansConfig.class).autowire();
|
||||||
|
AuthorizationAdvisorProxyFactory proxyFactory = this.spring.getContext()
|
||||||
|
.getBean(AuthorizationAdvisorProxyFactory.class);
|
||||||
|
assertThat(proxyFactory).hasSize(5);
|
||||||
|
assertThat(this.spring.getContext().getBeanNamesForType(AuthorizationAdvisor.class)).hasSize(5)
|
||||||
|
.containsExactlyInAnyOrder("preFilterAuthorizationMethodInterceptor",
|
||||||
|
"preAuthorizeAuthorizationMethodInterceptor", "postAuthorizeAuthorizationMethodInterceptor",
|
||||||
|
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
|
||||||
|
}
|
||||||
|
|
||||||
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
|
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
|
||||||
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
|
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
|
||||||
}
|
}
|
||||||
@ -1514,4 +1545,30 @@ public class PrePostMethodSecurityConfigurationTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableMethodSecurity
|
||||||
|
static class AspectJAwareAutoProxyAndFactoryBeansConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
static BeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor() {
|
||||||
|
return AopConfigUtils::registerAspectJAnnotationAutoProxyCreatorIfNecessary;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
static class MyFactoryBean implements FactoryBean<Object> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getObject() throws Exception {
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return Object.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user