2
0
Эх сурвалжийг харах

OAuth2AuthorizedClientArgumentResolver resolves ReactiveOAuth2AuthorizedClientManager

Closes gh-10846
m0k045e 3 жил өмнө
parent
commit
8cc18fa9dc

+ 31 - 7
config/src/main/java/org/springframework/security/config/annotation/web/reactive/ReactiveOAuth2ClientImportSelector.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * 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.
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.ImportSelector;
 import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder;
 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
@@ -41,6 +42,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve
  * This {@code Configuration} is imported by {@link EnableWebFluxSecurity}
  *
  * @author Rob Winch
+ * @author Alavudin Kuttikkattil
  * @since 5.1
  */
 final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
@@ -64,14 +66,12 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
 
 		private ReactiveOAuth2AuthorizedClientService authorizedClientService;
 
+		private ReactiveOAuth2AuthorizedClientManager authorizedClientManager;
+
 		@Override
 		public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
-			if (this.authorizedClientRepository != null && this.clientRegistrationRepository != null) {
-				ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
-						.builder().authorizationCode().refreshToken().clientCredentials().password().build();
-				DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
-						this.clientRegistrationRepository, getAuthorizedClientRepository());
-				authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
+			ReactiveOAuth2AuthorizedClientManager authorizedClientManager = getAuthorizedClientManager();
+			if (authorizedClientManager != null) {
 				configurer.addCustomResolver(new OAuth2AuthorizedClientArgumentResolver(authorizedClientManager));
 			}
 		}
@@ -93,6 +93,13 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
 			}
 		}
 
+		@Autowired(required = false)
+		void setAuthorizedClientManager(List<ReactiveOAuth2AuthorizedClientManager> authorizedClientManager) {
+			if (authorizedClientManager.size() == 1) {
+				this.authorizedClientManager = authorizedClientManager.get(0);
+			}
+		}
+
 		private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
 			if (this.authorizedClientRepository != null) {
 				return this.authorizedClientRepository;
@@ -103,6 +110,23 @@ final class ReactiveOAuth2ClientImportSelector implements ImportSelector {
 			return null;
 		}
 
+		private ReactiveOAuth2AuthorizedClientManager getAuthorizedClientManager() {
+			if (this.authorizedClientManager != null) {
+				return this.authorizedClientManager;
+			}
+			ReactiveOAuth2AuthorizedClientManager authorizedClientManager = null;
+			if (this.authorizedClientRepository != null && this.clientRegistrationRepository != null) {
+				ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder
+						.builder().authorizationCode().refreshToken().clientCredentials().password().build();
+				DefaultReactiveOAuth2AuthorizedClientManager defaultReactiveOAuth2AuthorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
+						this.clientRegistrationRepository, getAuthorizedClientRepository());
+				defaultReactiveOAuth2AuthorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
+				authorizedClientManager = defaultReactiveOAuth2AuthorizedClientManager;
+			}
+
+			return authorizedClientManager;
+		}
+
 	}
 
 }

+ 169 - 0
config/src/test/java/org/springframework/security/config/annotation/web/reactive/ReactiveOAuth2ClientImportSelectorTest.java

@@ -0,0 +1,169 @@
+/*
+ * 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.web.reactive;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.test.SpringTestContext;
+import org.springframework.security.config.test.SpringTestContextExtension;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
+import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
+import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
+import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
+import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
+import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.reactive.config.EnableWebFlux;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+/**
+ * Tests for {@link ReactiveOAuth2ClientImportSelector}.
+ *
+ * @author Alavudin Kuttikkattil
+ */
+@ExtendWith(SpringTestContextExtension.class)
+public class ReactiveOAuth2ClientImportSelectorTest {
+
+	public final SpringTestContext spring = new SpringTestContext(this);
+
+	WebTestClient client;
+
+	@Autowired
+	public void setApplicationContext(ApplicationContext context) {
+		// @formatter:off
+		this.client = WebTestClient
+				.bindToApplicationContext(context)
+				.build();
+		// @formatter:on
+	}
+
+	@Test
+	public void requestWhenAuthorizedClientManagerConfiguredThenUsed() {
+		String clientRegistrationId = "client";
+		String principalName = "user";
+		ReactiveClientRegistrationRepository clientRegistrationRepository = mock(
+				ReactiveClientRegistrationRepository.class);
+		ServerOAuth2AuthorizedClientRepository authorizedClientRepository = mock(
+				ServerOAuth2AuthorizedClientRepository.class);
+		ReactiveOAuth2AuthorizedClientManager authorizedClientManager = mock(
+				ReactiveOAuth2AuthorizedClientManager.class);
+		ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials()
+				.registrationId(clientRegistrationId).build();
+		OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, principalName,
+				TestOAuth2AccessTokens.noScopes());
+		given(authorizedClientManager.authorize(any())).willReturn(Mono.just(authorizedClient));
+		OAuth2AuthorizedClientManagerRegisteredConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
+		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
+		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
+		this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
+		// @formatter:off
+		this.client
+				.get()
+				.uri("http://localhost/authorized-client")
+				.headers((headers) -> headers.setBasicAuth("user", "password")).exchange().expectStatus().isOk()
+				.expectBody(String.class).isEqualTo("resolved");
+		// @formatter:on
+		verify(authorizedClientManager).authorize(any());
+		verifyNoInteractions(clientRegistrationRepository);
+		verifyNoInteractions(authorizedClientRepository);
+	}
+
+	@Test
+	public void requestWhenAuthorizedClientManagerNotConfigureThenUseDefaultAuthorizedClientManager() {
+		String clientRegistrationId = "client";
+		String principalName = "user";
+		ReactiveClientRegistrationRepository clientRegistrationRepository = mock(
+				ReactiveClientRegistrationRepository.class);
+		ServerOAuth2AuthorizedClientRepository authorizedClientRepository = mock(
+				ServerOAuth2AuthorizedClientRepository.class);
+		ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials()
+				.registrationId(clientRegistrationId).build();
+		OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, principalName,
+				TestOAuth2AccessTokens.noScopes());
+		OAuth2AuthorizedClientManagerRegisteredConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
+		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
+		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = null;
+		given(authorizedClientRepository.loadAuthorizedClient(any(), any(), any()))
+				.willReturn(Mono.just(authorizedClient));
+		this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
+		// @formatter:off
+		this.client
+				.get()
+				.uri("http://localhost/authorized-client")
+				.headers((headers) -> headers.setBasicAuth("user", "password")).exchange().expectStatus().isOk()
+				.expectBody(String.class).isEqualTo("resolved");
+		// @formatter:on
+	}
+
+	@EnableWebFlux
+	@EnableWebFluxSecurity
+	static class OAuth2AuthorizedClientManagerRegisteredConfig {
+
+		static ReactiveClientRegistrationRepository CLIENT_REGISTRATION_REPOSITORY;
+		static ServerOAuth2AuthorizedClientRepository AUTHORIZED_CLIENT_REPOSITORY;
+		static ReactiveOAuth2AuthorizedClientManager AUTHORIZED_CLIENT_MANAGER;
+
+		@Bean
+		SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
+			return http.build();
+		}
+
+		@Bean
+		ReactiveClientRegistrationRepository clientRegistrationRepository() {
+			return CLIENT_REGISTRATION_REPOSITORY;
+		}
+
+		@Bean
+		ServerOAuth2AuthorizedClientRepository authorizedClientRepository() {
+			return AUTHORIZED_CLIENT_REPOSITORY;
+		}
+
+		@Bean
+		ReactiveOAuth2AuthorizedClientManager authorizedClientManager() {
+			return AUTHORIZED_CLIENT_MANAGER;
+		}
+
+		@RestController
+		class Controller {
+
+			@GetMapping("/authorized-client")
+			String authorizedClient(
+					@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
+				return (authorizedClient != null) ? "resolved" : "not-resolved";
+			}
+
+		}
+
+	}
+
+}