From 2bb3787d2b2c9d3a0a19c161df467f425861212f Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Thu, 12 Sep 2024 11:42:03 -0600 Subject: [PATCH] Use addAdvisors in Reactive Proxy Configuration Issue gh-15497 --- ...ionManagerMethodSecurityConfiguration.java | 183 ++++++++---------- ...activeAuthorizationProxyConfiguration.java | 63 ------ .../ReactiveMethodSecuritySelector.java | 2 +- 3 files changed, 86 insertions(+), 162 deletions(-) delete mode 100644 config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationProxyConfiguration.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java index 6acd05d2f4..e9388dfc2c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java @@ -16,22 +16,17 @@ package org.springframework.security.config.annotation.method.configuration; -import java.util.function.Consumer; -import java.util.function.Supplier; - import io.micrometer.observation.ObservationRegistry; -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.Pointcut; import org.springframework.aop.framework.AopInfrastructureBean; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Fallback; @@ -39,18 +34,15 @@ import org.springframework.context.annotation.Role; import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.authorization.ReactiveAuthorizationManager; -import org.springframework.security.authorization.method.AuthorizationAdvisor; +import org.springframework.security.authorization.ObservationReactiveAuthorizationManager; import org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor; import org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor; -import org.springframework.security.authorization.method.MethodInvocationResult; import org.springframework.security.authorization.method.PostAuthorizeReactiveAuthorizationManager; import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor; import org.springframework.security.authorization.method.PreAuthorizeReactiveAuthorizationManager; import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor; import org.springframework.security.authorization.method.PrePostTemplateDefaults; import org.springframework.security.config.core.GrantedAuthorityDefaults; -import org.springframework.util.function.SingletonSupplier; /** * Configuration for a {@link ReactiveAuthenticationManager} based Method Security. @@ -58,59 +50,105 @@ import org.springframework.util.function.SingletonSupplier; * @author Evgeniy Cheban * @since 5.8 */ -@Configuration(proxyBeanMethods = false) -final class ReactiveAuthorizationManagerMethodSecurityConfiguration implements AopInfrastructureBean { +@Configuration(value = "_reactiveMethodSecurityConfiguration", proxyBeanMethods = false) +final class ReactiveAuthorizationManagerMethodSecurityConfiguration + implements AopInfrastructureBean, ApplicationContextAware { + + private static final Pointcut preFilterPointcut = new PreFilterAuthorizationReactiveMethodInterceptor() + .getPointcut(); + + private static final Pointcut preAuthorizePointcut = AuthorizationManagerBeforeReactiveMethodInterceptor + .preAuthorize() + .getPointcut(); + + private static final Pointcut postAuthorizePointcut = AuthorizationManagerAfterReactiveMethodInterceptor + .postAuthorize() + .getPointcut(); + + private static final Pointcut postFilterPointcut = new PostFilterAuthorizationReactiveMethodInterceptor() + .getPointcut(); + + private PreFilterAuthorizationReactiveMethodInterceptor preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(); + + private PreAuthorizeReactiveAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(); + + private PostAuthorizeReactiveAuthorizationManager postAuthorizeAuthorizationManager = new PostAuthorizeReactiveAuthorizationManager(); + + private PostFilterAuthorizationReactiveMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor(); + + private AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeMethodInterceptor; + + private AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor; + + @Autowired(required = false) + ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler) { + if (expressionHandler != null) { + this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler); + this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler); + this.postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor(expressionHandler); + this.postAuthorizeAuthorizationManager = new PostAuthorizeReactiveAuthorizationManager(expressionHandler); + } + this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeReactiveMethodInterceptor + .preAuthorize(this.preAuthorizeAuthorizationManager); + this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterReactiveMethodInterceptor + .postAuthorize(this.postAuthorizeAuthorizationManager); + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + this.preAuthorizeAuthorizationManager.setApplicationContext(context); + this.postAuthorizeAuthorizationManager.setApplicationContext(context); + } + + @Autowired(required = false) + void setTemplateDefaults(PrePostTemplateDefaults templateDefaults) { + this.preFilterMethodInterceptor.setTemplateDefaults(templateDefaults); + this.preAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults); + this.postAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults); + this.postFilterMethodInterceptor.setTemplateDefaults(templateDefaults); + } + + @Autowired(required = false) + void setObservationRegistry(ObservationRegistry registry) { + if (registry.isNoop()) { + return; + } + this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize( + new ObservationReactiveAuthorizationManager<>(registry, this.preAuthorizeAuthorizationManager)); + this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize( + new ObservationReactiveAuthorizationManager<>(registry, this.postAuthorizeAuthorizationManager)); + } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static MethodInterceptor preFilterAuthorizationMethodInterceptor(MethodSecurityExpressionHandler expressionHandler, - ObjectProvider defaultsObjectProvider) { - PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor( - expressionHandler); - return new DeferringMethodInterceptor<>(interceptor, - (i) -> defaultsObjectProvider.ifAvailable(i::setTemplateDefaults)); + static MethodInterceptor preFilterAuthorizationMethodInterceptor( + ObjectProvider _reactiveMethodSecurityConfiguration) { + return new DeferringMethodInterceptor<>(preFilterPointcut, + () -> _reactiveMethodSecurityConfiguration.getObject().preFilterMethodInterceptor); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor( - MethodSecurityExpressionHandler expressionHandler, - ObjectProvider defaultsObjectProvider, - ObjectProvider registryProvider, ApplicationContext context) { - PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager( - expressionHandler); - manager.setApplicationContext(context); - ReactiveAuthorizationManager authorizationManager = manager(manager, registryProvider); - AuthorizationAdvisor interceptor = AuthorizationManagerBeforeReactiveMethodInterceptor - .preAuthorize(authorizationManager); - return new DeferringMethodInterceptor<>(interceptor, - (i) -> defaultsObjectProvider.ifAvailable(manager::setTemplateDefaults)); + ObjectProvider _reactiveMethodSecurityConfiguration) { + return new DeferringMethodInterceptor<>(preAuthorizePointcut, + () -> _reactiveMethodSecurityConfiguration.getObject().preAuthorizeMethodInterceptor); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static MethodInterceptor postFilterAuthorizationMethodInterceptor(MethodSecurityExpressionHandler expressionHandler, - ObjectProvider defaultsObjectProvider) { - PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor( - expressionHandler); - return new DeferringMethodInterceptor<>(interceptor, - (i) -> defaultsObjectProvider.ifAvailable(i::setTemplateDefaults)); + static MethodInterceptor postFilterAuthorizationMethodInterceptor( + ObjectProvider _reactiveMethodSecurityConfiguration) { + return new DeferringMethodInterceptor<>(postFilterPointcut, + () -> _reactiveMethodSecurityConfiguration.getObject().postFilterMethodInterceptor); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor( - MethodSecurityExpressionHandler expressionHandler, - ObjectProvider defaultsObjectProvider, - ObjectProvider registryProvider, ApplicationContext context) { - PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager( - expressionHandler); - manager.setApplicationContext(context); - ReactiveAuthorizationManager authorizationManager = manager(manager, registryProvider); - AuthorizationAdvisor interceptor = AuthorizationManagerAfterReactiveMethodInterceptor - .postAuthorize(authorizationManager); - return new DeferringMethodInterceptor<>(interceptor, - (i) -> defaultsObjectProvider.ifAvailable(manager::setTemplateDefaults)); + ObjectProvider _reactiveMethodSecurityConfiguration) { + return new DeferringMethodInterceptor<>(postAuthorizePointcut, + () -> _reactiveMethodSecurityConfiguration.getObject().postAuthorizeMethodInterceptor); } @Bean @@ -125,55 +163,4 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration implements A return handler; } - static ReactiveAuthorizationManager manager(ReactiveAuthorizationManager delegate, - ObjectProvider registryProvider) { - return new DeferringObservationReactiveAuthorizationManager<>(registryProvider, delegate); - } - - private static final class DeferringMethodInterceptor - implements AuthorizationAdvisor { - - private final Pointcut pointcut; - - private final int order; - - private final Supplier delegate; - - DeferringMethodInterceptor(M delegate, Consumer supplier) { - this.pointcut = delegate.getPointcut(); - this.order = delegate.getOrder(); - this.delegate = SingletonSupplier.of(() -> { - supplier.accept(delegate); - return delegate; - }); - } - - @Nullable - @Override - public Object invoke(@NotNull MethodInvocation invocation) throws Throwable { - return this.delegate.get().invoke(invocation); - } - - @Override - public Pointcut getPointcut() { - return this.pointcut; - } - - @Override - public Advice getAdvice() { - return this; - } - - @Override - public int getOrder() { - return this.order; - } - - @Override - public boolean isPerInstance() { - return true; - } - - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationProxyConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationProxyConfiguration.java deleted file mode 100644 index 7912991c4f..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationProxyConfiguration.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.method.configuration; - -import java.util.ArrayList; -import java.util.List; - -import org.aopalliance.intercept.MethodInterceptor; - -import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Role; -import org.springframework.security.authorization.method.AuthorizationAdvisor; -import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; -import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; -import org.springframework.security.config.Customizer; - -@Configuration(proxyBeanMethods = false) -final class ReactiveAuthorizationProxyConfiguration implements AopInfrastructureBean { - - @Bean - @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static AuthorizationAdvisorProxyFactory authorizationProxyFactory(ObjectProvider provider, - ObjectProvider> customizers) { - List advisors = new ArrayList<>(); - provider.forEach(advisors::add); - AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults(); - customizers.forEach((c) -> c.customize(factory)); - factory.setAdvisors(advisors); - return factory; - } - - @Bean - @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static MethodInterceptor authorizeReturnObjectMethodInterceptor(ObjectProvider provider, - AuthorizationAdvisorProxyFactory authorizationProxyFactory) { - AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor( - authorizationProxyFactory); - List advisors = new ArrayList<>(); - provider.forEach(advisors::add); - advisors.add(interceptor); - authorizationProxyFactory.setAdvisors(advisors); - return interceptor; - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java index b1c923383e..224d388b38 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java @@ -51,7 +51,7 @@ class ReactiveMethodSecuritySelector implements ImportSelector { else { imports.add(ReactiveMethodSecurityConfiguration.class.getName()); } - imports.add(ReactiveAuthorizationProxyConfiguration.class.getName()); + imports.add(AuthorizationProxyConfiguration.class.getName()); return imports.toArray(new String[0]); }