Browse Source

Use addAdvisors in Reactive Proxy Configuration

Issue gh-15497
Josh Cummings 11 months ago
parent
commit
2bb3787d2b

+ 85 - 98
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<PrePostTemplateDefaults> defaultsObjectProvider) {
-		PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor(
-				expressionHandler);
-		return new DeferringMethodInterceptor<>(interceptor,
-				(i) -> defaultsObjectProvider.ifAvailable(i::setTemplateDefaults));
+	static MethodInterceptor preFilterAuthorizationMethodInterceptor(
+			ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
+		return new DeferringMethodInterceptor<>(preFilterPointcut,
+				() -> _reactiveMethodSecurityConfiguration.getObject().preFilterMethodInterceptor);
 	}
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 	static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor(
-			MethodSecurityExpressionHandler expressionHandler,
-			ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider,
-			ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
-		PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager(
-				expressionHandler);
-		manager.setApplicationContext(context);
-		ReactiveAuthorizationManager<MethodInvocation> authorizationManager = manager(manager, registryProvider);
-		AuthorizationAdvisor interceptor = AuthorizationManagerBeforeReactiveMethodInterceptor
-			.preAuthorize(authorizationManager);
-		return new DeferringMethodInterceptor<>(interceptor,
-				(i) -> defaultsObjectProvider.ifAvailable(manager::setTemplateDefaults));
+			ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
+		return new DeferringMethodInterceptor<>(preAuthorizePointcut,
+				() -> _reactiveMethodSecurityConfiguration.getObject().preAuthorizeMethodInterceptor);
 	}
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-	static MethodInterceptor postFilterAuthorizationMethodInterceptor(MethodSecurityExpressionHandler expressionHandler,
-			ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider) {
-		PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor(
-				expressionHandler);
-		return new DeferringMethodInterceptor<>(interceptor,
-				(i) -> defaultsObjectProvider.ifAvailable(i::setTemplateDefaults));
+	static MethodInterceptor postFilterAuthorizationMethodInterceptor(
+			ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
+		return new DeferringMethodInterceptor<>(postFilterPointcut,
+				() -> _reactiveMethodSecurityConfiguration.getObject().postFilterMethodInterceptor);
 	}
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 	static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor(
-			MethodSecurityExpressionHandler expressionHandler,
-			ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider,
-			ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
-		PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager(
-				expressionHandler);
-		manager.setApplicationContext(context);
-		ReactiveAuthorizationManager<MethodInvocationResult> authorizationManager = manager(manager, registryProvider);
-		AuthorizationAdvisor interceptor = AuthorizationManagerAfterReactiveMethodInterceptor
-			.postAuthorize(authorizationManager);
-		return new DeferringMethodInterceptor<>(interceptor,
-				(i) -> defaultsObjectProvider.ifAvailable(manager::setTemplateDefaults));
+			ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
+		return new DeferringMethodInterceptor<>(postAuthorizePointcut,
+				() -> _reactiveMethodSecurityConfiguration.getObject().postAuthorizeMethodInterceptor);
 	}
 
 	@Bean
@@ -125,55 +163,4 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration implements A
 		return handler;
 	}
 
-	static <T> ReactiveAuthorizationManager<T> manager(ReactiveAuthorizationManager<T> delegate,
-			ObjectProvider<ObservationRegistry> registryProvider) {
-		return new DeferringObservationReactiveAuthorizationManager<>(registryProvider, delegate);
-	}
-
-	private static final class DeferringMethodInterceptor<M extends AuthorizationAdvisor>
-			implements AuthorizationAdvisor {
-
-		private final Pointcut pointcut;
-
-		private final int order;
-
-		private final Supplier<M> delegate;
-
-		DeferringMethodInterceptor(M delegate, Consumer<M> 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;
-		}
-
-	}
-
 }

+ 0 - 63
config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationProxyConfiguration.java

@@ -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<AuthorizationAdvisor> provider,
-			ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) {
-		List<AuthorizationAdvisor> 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<AuthorizationAdvisor> provider,
-			AuthorizationAdvisorProxyFactory authorizationProxyFactory) {
-		AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor(
-				authorizationProxyFactory);
-		List<AuthorizationAdvisor> advisors = new ArrayList<>();
-		provider.forEach(advisors::add);
-		advisors.add(interceptor);
-		authorizationProxyFactory.setAdvisors(advisors);
-		return interceptor;
-	}
-
-}

+ 1 - 1
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]);
 	}