Sfoglia il codice sorgente

Defer ObservationRegistry Resolution

- If Method Security asks for  too early, it is no longer
eligible for post-processing. As such, this commit defers loading it until
the first authorization request.

Issue gh-11990
Josh Cummings 2 anni fa
parent
commit
c45cd6ec9f

+ 50 - 0
config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationAuthorizationManager.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2002-2022 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.function.Supplier;
+
+import io.micrometer.observation.ObservationRegistry;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.authorization.ObservationAuthorizationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.util.function.SingletonSupplier;
+
+final class DeferringObservationAuthorizationManager<T> implements AuthorizationManager<T> {
+
+	private final Supplier<AuthorizationManager<T>> delegate;
+
+	DeferringObservationAuthorizationManager(ObjectProvider<ObservationRegistry> provider,
+			AuthorizationManager<T> delegate) {
+		this.delegate = SingletonSupplier.of(() -> {
+			ObservationRegistry registry = provider.getIfAvailable(() -> ObservationRegistry.NOOP);
+			if (registry.isNoop()) {
+				return delegate;
+			}
+			return new ObservationAuthorizationManager<>(registry, delegate);
+		});
+	}
+
+	@Override
+	public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
+		return this.delegate.get().check(authentication, object);
+	}
+
+}

+ 2 - 10
config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java

@@ -26,7 +26,6 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Role;
 import org.springframework.security.authorization.AuthorizationManager;
-import org.springframework.security.authorization.ObservationAuthorizationManager;
 import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
 import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
 import org.springframework.security.config.core.GrantedAuthorityDefaults;
@@ -54,19 +53,12 @@ final class Jsr250MethodSecurityConfiguration {
 		defaultsProvider.ifAvailable((d) -> jsr250.setRolePrefix(d.getRolePrefix()));
 		SecurityContextHolderStrategy strategy = strategyProvider
 				.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
-		ObservationRegistry registry = registryProvider.getIfAvailable(() -> ObservationRegistry.NOOP);
-		AuthorizationManager<MethodInvocation> manager = manager(jsr250, registry);
+		AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(
+				registryProvider, jsr250);
 		AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
 				.jsr250(manager);
 		interceptor.setSecurityContextHolderStrategy(strategy);
 		return interceptor;
 	}
 
-	static <T> AuthorizationManager<T> manager(AuthorizationManager<T> jsr250, ObservationRegistry registry) {
-		if (registry.isNoop()) {
-			return jsr250;
-		}
-		return new ObservationAuthorizationManager<>(registry, jsr250);
-	}
-
 }

+ 1 - 6
config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java

@@ -29,7 +29,6 @@ import org.springframework.security.access.expression.method.DefaultMethodSecuri
 import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
 import org.springframework.security.authorization.AuthorizationEventPublisher;
 import org.springframework.security.authorization.AuthorizationManager;
-import org.springframework.security.authorization.ObservationAuthorizationManager;
 import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
 import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
 import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
@@ -120,11 +119,7 @@ final class PrePostMethodSecurityConfiguration {
 
 	static <T> AuthorizationManager<T> manager(AuthorizationManager<T> delegate,
 			ObjectProvider<ObservationRegistry> registryProvider) {
-		ObservationRegistry registry = registryProvider.getIfAvailable(() -> ObservationRegistry.NOOP);
-		if (registry.isNoop()) {
-			return delegate;
-		}
-		return new ObservationAuthorizationManager<>(registry, delegate);
+		return new DeferringObservationAuthorizationManager<>(registryProvider, delegate);
 	}
 
 }

+ 2 - 10
config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java

@@ -27,7 +27,6 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Role;
 import org.springframework.security.access.annotation.Secured;
 import org.springframework.security.authorization.AuthorizationManager;
-import org.springframework.security.authorization.ObservationAuthorizationManager;
 import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
 import org.springframework.security.authorization.method.SecuredAuthorizationManager;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -52,19 +51,12 @@ final class SecuredMethodSecurityConfiguration {
 		SecuredAuthorizationManager secured = new SecuredAuthorizationManager();
 		SecurityContextHolderStrategy strategy = strategyProvider
 				.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
-		ObservationRegistry registry = registryProvider.getIfAvailable(() -> ObservationRegistry.NOOP);
-		AuthorizationManager<MethodInvocation> manager = manager(secured, registry);
+		AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(
+				registryProvider, secured);
 		AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
 				.secured(manager);
 		interceptor.setSecurityContextHolderStrategy(strategy);
 		return interceptor;
 	}
 
-	static <T> AuthorizationManager<T> manager(AuthorizationManager<T> jsr250, ObservationRegistry registry) {
-		if (registry.isNoop()) {
-			return jsr250;
-		}
-		return new ObservationAuthorizationManager<>(registry, jsr250);
-	}
-
 }