Преглед изворни кода

ReactiveAuthorizationManager replace deprecated #check calls with #authorize

Closes gh-16936

Signed-off-by: Evgeniy Cheban <mister.cheban@gmail.com>
Evgeniy Cheban пре 4 месеци
родитељ
комит
092bbfc8e7

+ 15 - 4
core/src/main/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManager.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -62,6 +62,17 @@ public final class ObservationReactiveAuthorizationManager<T>
 	@Deprecated
 	@Override
 	public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
+		return authorize(authentication, object).flatMap((result) -> {
+			if (result instanceof AuthorizationDecision decision) {
+				return Mono.just(decision);
+			}
+			return Mono.error(new IllegalArgumentException(
+					"Please call #authorize or ensure that the returned result is of type Mono<AuthorizationDecision>"));
+		});
+	}
+
+	@Override
+	public Mono<AuthorizationResult> authorize(Mono<Authentication> authentication, T object) {
 		AuthorizationObservationContext<T> context = new AuthorizationObservationContext<>(object);
 		Mono<Authentication> wrapped = authentication.map((auth) -> {
 			context.setAuthentication(auth);
@@ -71,9 +82,9 @@ public final class ObservationReactiveAuthorizationManager<T>
 			Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry)
 				.parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null))
 				.start();
-			return this.delegate.check(wrapped, object).doOnSuccess((decision) -> {
-				context.setAuthorizationResult(decision);
-				if (decision == null || !decision.isGranted()) {
+			return this.delegate.authorize(wrapped, object).doOnSuccess((result) -> {
+				context.setAuthorizationResult(result);
+				if (result == null || !result.isGranted()) {
 					observation.error(new AccessDeniedException("Access Denied"));
 				}
 				observation.stop();

+ 3 - 3
core/src/main/java/org/springframework/security/authorization/ReactiveAuthorizationManager.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -50,8 +50,8 @@ public interface ReactiveAuthorizationManager<T> {
 	 */
 	default Mono<Void> verify(Mono<Authentication> authentication, T object) {
 		// @formatter:off
-		return check(authentication, object)
-				.filter(AuthorizationDecision::isGranted)
+		return authorize(authentication, object)
+				.filter(AuthorizationResult::isGranted)
 				.switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Access Denied"))))
 				.flatMap((decision) -> Mono.empty());
 		// @formatter:on

+ 4 - 1
core/src/test/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManagerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2023 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -70,6 +70,7 @@ public class ObservationReactiveAuthorizationManagerTests {
 	void verifyWhenDefaultsThenObserves() {
 		given(this.handler.supportsContext(any())).willReturn(true);
 		given(this.authorizationManager.check(any(), any())).willReturn(Mono.just(this.grant));
+		given(this.authorizationManager.authorize(any(), any())).willCallRealMethod();
 		this.tested.verify(this.token, this.object).block();
 		ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
 		verify(this.handler).onStart(captor.capture());
@@ -86,6 +87,7 @@ public class ObservationReactiveAuthorizationManagerTests {
 	void verifyWhenErrorsThenObserves() {
 		given(this.handler.supportsContext(any())).willReturn(true);
 		given(this.authorizationManager.check(any(), any())).willReturn(Mono.just(this.deny));
+		given(this.authorizationManager.authorize(any(), any())).willCallRealMethod();
 		assertThatExceptionOfType(AccessDeniedException.class)
 			.isThrownBy(() -> this.tested.verify(this.token, this.object).block());
 		ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
@@ -106,6 +108,7 @@ public class ObservationReactiveAuthorizationManagerTests {
 			((Mono<Authentication>) invocation.getArgument(0)).block();
 			return Mono.just(this.grant);
 		});
+		given(this.authorizationManager.authorize(any(), any())).willCallRealMethod();
 		this.tested.verify(this.token, this.object).block();
 		ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
 		verify(this.handler).onStart(captor.capture());

+ 15 - 3
rsocket/src/main/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManager.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -23,6 +23,7 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationResult;
 import org.springframework.security.authorization.ReactiveAuthorizationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.rsocket.api.PayloadExchange;
@@ -51,18 +52,29 @@ public final class PayloadExchangeMatcherReactiveAuthorizationManager
 	}
 
 	/**
-	 * @deprecated please use {@link #authorize(Mono, Object)} instead
+	 * @deprecated please use {@link #authorize(Mono, PayloadExchange)} instead
 	 */
 	@Deprecated
 	@Override
 	public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, PayloadExchange exchange) {
+		return authorize(authentication, exchange).flatMap((result) -> {
+			if (result instanceof AuthorizationDecision decision) {
+				return Mono.just(decision);
+			}
+			return Mono.error(new IllegalArgumentException(
+					"Please call #authorize or ensure that the returned result is of type Mono<AuthorizationDecision>"));
+		});
+	}
+
+	@Override
+	public Mono<AuthorizationResult> authorize(Mono<Authentication> authentication, PayloadExchange exchange) {
 		return Flux.fromIterable(this.mappings)
 			.concatMap((mapping) -> mapping.getMatcher()
 				.matches(exchange)
 				.filter(PayloadExchangeMatcher.MatchResult::isMatch)
 				.map(MatchResult::getVariables)
 				.flatMap((variables) -> mapping.getEntry()
-					.check(authentication, new PayloadExchangeAuthorizationContext(exchange, variables))))
+					.authorize(authentication, new PayloadExchangeAuthorizationContext(exchange, variables))))
 			.next()
 			.switchIfEmpty(Mono.fromCallable(() -> new AuthorizationDecision(false)));
 	}

+ 5 - 1
rsocket/src/test/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManagerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -53,6 +53,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests {
 	public void checkWhenGrantedThenGranted() {
 		AuthorizationDecision expected = new AuthorizationDecision(true);
 		given(this.authz.check(any(), any())).willReturn(Mono.just(expected));
+		given(this.authz.authorize(any(), any())).willCallRealMethod();
 		PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
 			.builder()
 			.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
@@ -64,6 +65,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests {
 	public void checkWhenDeniedThenDenied() {
 		AuthorizationDecision expected = new AuthorizationDecision(false);
 		given(this.authz.check(any(), any())).willReturn(Mono.just(expected));
+		given(this.authz.authorize(any(), any())).willCallRealMethod();
 		PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
 			.builder()
 			.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
@@ -75,6 +77,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests {
 	public void checkWhenFirstMatchThenSecondUsed() {
 		AuthorizationDecision expected = new AuthorizationDecision(true);
 		given(this.authz.check(any(), any())).willReturn(Mono.just(expected));
+		given(this.authz.authorize(any(), any())).willCallRealMethod();
 		PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
 			.builder()
 			.add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz))
@@ -87,6 +90,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests {
 	public void checkWhenSecondMatchThenSecondUsed() {
 		AuthorizationDecision expected = new AuthorizationDecision(true);
 		given(this.authz2.check(any(), any())).willReturn(Mono.just(expected));
+		given(this.authz2.authorize(any(), any())).willCallRealMethod();
 		PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager
 			.builder()
 			.add(new PayloadExchangeMatcherEntry<>((e) -> PayloadExchangeMatcher.MatchResult.notMatch(), this.authz))

+ 17 - 4
web/src/main/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManager.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
 
 import org.springframework.core.log.LogMessage;
 import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationResult;
 import org.springframework.security.authorization.ReactiveAuthorizationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult;
@@ -35,6 +36,7 @@ import org.springframework.web.server.ServerWebExchange;
 /**
  * @author Rob Winch
  * @author Mathieu Ouellet
+ * @author Evgeniy Cheban
  * @since 5.0
  */
 public final class DelegatingReactiveAuthorizationManager implements ReactiveAuthorizationManager<ServerWebExchange> {
@@ -49,11 +51,22 @@ public final class DelegatingReactiveAuthorizationManager implements ReactiveAut
 	}
 
 	/**
-	 * @deprecated please use {@link #authorize(Mono, Object)} instead
+	 * @deprecated please use {@link #authorize(Mono, ServerWebExchange)} instead
 	 */
 	@Deprecated
 	@Override
 	public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, ServerWebExchange exchange) {
+		return authorize(authentication, exchange).flatMap((result) -> {
+			if (result instanceof AuthorizationDecision decision) {
+				return Mono.just(decision);
+			}
+			return Mono.error(new IllegalArgumentException(
+					"Please call #authorize or ensure that the returned result is of type Mono<AuthorizationDecision>"));
+		});
+	}
+
+	@Override
+	public Mono<AuthorizationResult> authorize(Mono<Authentication> authentication, ServerWebExchange exchange) {
 		return Flux.fromIterable(this.mappings)
 			.concatMap((mapping) -> mapping.getMatcher()
 				.matches(exchange)
@@ -63,10 +76,10 @@ public final class DelegatingReactiveAuthorizationManager implements ReactiveAut
 					logger.debug(LogMessage.of(() -> "Checking authorization on '"
 							+ exchange.getRequest().getPath().pathWithinApplication() + "' using "
 							+ mapping.getEntry()));
-					return mapping.getEntry().check(authentication, new AuthorizationContext(exchange, variables));
+					return mapping.getEntry().authorize(authentication, new AuthorizationContext(exchange, variables));
 				}))
 			.next()
-			.defaultIfEmpty(new AuthorizationDecision(false));
+			.switchIfEmpty(Mono.fromCallable(() -> new AuthorizationDecision(false)));
 	}
 
 	public static DelegatingReactiveAuthorizationManager.Builder builder() {

+ 3 - 1
web/src/test/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManagerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -81,6 +81,7 @@ public class DelegatingReactiveAuthorizationManagerTests {
 		given(this.match1.matches(any())).willReturn(ServerWebExchangeMatcher.MatchResult.match());
 		given(this.delegate1.check(eq(this.authentication), any(AuthorizationContext.class)))
 			.willReturn(Mono.just(this.decision));
+		given(this.delegate1.authorize(eq(this.authentication), any(AuthorizationContext.class))).willCallRealMethod();
 		assertThat(this.manager.check(this.authentication, this.exchange).block()).isEqualTo(this.decision);
 		verifyNoMoreInteractions(this.match2, this.delegate2);
 	}
@@ -91,6 +92,7 @@ public class DelegatingReactiveAuthorizationManagerTests {
 		given(this.match2.matches(any())).willReturn(ServerWebExchangeMatcher.MatchResult.match());
 		given(this.delegate2.check(eq(this.authentication), any(AuthorizationContext.class)))
 			.willReturn(Mono.just(this.decision));
+		given(this.delegate2.authorize(eq(this.authentication), any(AuthorizationContext.class))).willCallRealMethod();
 		assertThat(this.manager.check(this.authentication, this.exchange).block()).isEqualTo(this.decision);
 		verifyNoMoreInteractions(this.delegate1);
 	}