diff --git a/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle b/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle index afc00ff28d..286f80a581 100644 --- a/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle +++ b/samples/boot/oauth2webclient-webflux/spring-security-samples-boot-oauth2webclient-webflux.gradle @@ -11,4 +11,5 @@ dependencies { testCompile project(':spring-security-test') testCompile 'org.springframework.boot:spring-boot-starter-test' + testCompile 'com.squareup.okhttp3:mockwebserver' } diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java index bba3743937..6016aa2ef5 100644 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java +++ b/samples/boot/oauth2webclient-webflux/src/main/java/sample/config/WebClientConfig.java @@ -16,14 +16,15 @@ package sample.config; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +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.registration.ReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; import org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; import org.springframework.web.reactive.function.client.WebClient; @@ -34,12 +35,15 @@ import org.springframework.web.reactive.function.client.WebClient; @Configuration public class WebClientConfig { + @Value("${resource-uri}") String uri; + @Bean WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); oauth.setDefaultOAuth2AuthorizedClient(true); return WebClient.builder() + .baseUrl(this.uri) .filter(oauth) .build(); } diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java index 4a7f1dc766..f7daadb18b 100644 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java +++ b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/OAuth2WebClientController.java @@ -15,13 +15,13 @@ */ package sample.web; -import org.springframework.beans.factory.annotation.Value; +import reactor.core.publisher.Mono; + import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Mono; import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId; @@ -34,18 +34,14 @@ import static org.springframework.security.oauth2.client.web.reactive.function.c public class OAuth2WebClientController { private final WebClient webClient; - private final String uri; - - public OAuth2WebClientController(WebClient webClient, @Value("${resource-uri}") String uri) { + public OAuth2WebClientController(WebClient webClient) { this.webClient = webClient; - this.uri = uri; } @GetMapping("/explicit") String explicit(Model model) { Mono body = this.webClient .get() - .uri(this.uri) .attributes(clientRegistrationId("client-id")) .retrieve() .bodyToMono(String.class); @@ -57,7 +53,6 @@ public class OAuth2WebClientController { String implicit(Model model) { Mono body = this.webClient .get() - .uri(this.uri) .retrieve() .bodyToMono(String.class); model.addAttribute("body", body); diff --git a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java index 9ff18d6646..89961e84f2 100644 --- a/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java +++ b/samples/boot/oauth2webclient-webflux/src/main/java/sample/web/RegisteredOAuth2AuthorizedClientController.java @@ -15,7 +15,8 @@ */ package sample.web; -import org.springframework.beans.factory.annotation.Value; +import reactor.core.publisher.Mono; + import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; import org.springframework.stereotype.Controller; @@ -23,7 +24,6 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Mono; import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient; @@ -37,18 +37,14 @@ public class RegisteredOAuth2AuthorizedClientController { private final WebClient webClient; - private final String uri; - - public RegisteredOAuth2AuthorizedClientController(WebClient webClient, @Value("${resource-uri}") String uri) { + public RegisteredOAuth2AuthorizedClientController(WebClient webClient) { this.webClient = webClient; - this.uri = uri; } @GetMapping("/explicit") String explicit(Model model, @RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) { Mono body = this.webClient .get() - .uri(this.uri) .attributes(oauth2AuthorizedClient(authorizedClient)) .retrieve() .bodyToMono(String.class); @@ -60,7 +56,6 @@ public class RegisteredOAuth2AuthorizedClientController { String implicit(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient) { Mono body = this.webClient .get() - .uri(this.uri) .attributes(oauth2AuthorizedClient(authorizedClient)) .retrieve() .bodyToMono(String.class); diff --git a/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java b/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java new file mode 100644 index 0000000000..fc50c142a0 --- /dev/null +++ b/samples/boot/oauth2webclient-webflux/src/test/java/sample/OAuth2WebClientControllerTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2002-2020 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 sample; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import sample.config.SecurityConfig; +import sample.web.OAuth2WebClientController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Client; +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Login; + +@WebFluxTest +@Import({ SecurityConfig.class, OAuth2WebClientController.class }) +@AutoConfigureWebTestClient +@RunWith(SpringRunner.class) +public class OAuth2WebClientControllerTests { + private static MockWebServer web = new MockWebServer(); + + @Autowired + private WebTestClient client; + + @MockBean + ReactiveClientRegistrationRepository clientRegistrationRepository; + + @AfterClass + public static void shutdown() throws Exception { + web.shutdown(); + } + + @Test + public void explicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Login()) + .mutateWith(mockOAuth2Client("client-id")) + .get().uri("/webclient/explicit") + .exchange() + .expectStatus().isOk(); + } + + @Test + public void implicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Login()) + .get().uri("/webclient/implicit") + .exchange() + .expectStatus().isOk(); + } + + @Test + public void publicExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Client("client-id")) + .get().uri("/public/webclient/explicit") + .exchange() + .expectStatus().isOk(); + } + + @Test + public void publicImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Login()) + .get().uri("/public/webclient/implicit") + .exchange() + .expectStatus().isOk(); + } + + @Configuration + static class WebClientConfig { + @Bean + WebClient web() { + return WebClient.create(web.url("/").toString()); + } + + @Bean + ServerOAuth2AuthorizedClientRepository authorizedClientRepository() { + return new WebSessionServerOAuth2AuthorizedClientRepository(); + } + } +} diff --git a/samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java b/samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java new file mode 100644 index 0000000000..be4cc4a57c --- /dev/null +++ b/samples/boot/oauth2webclient-webflux/src/test/java/sample/RegisteredOAuth2AuthorizedClientControllerTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2002-2020 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 sample; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import sample.config.SecurityConfig; +import sample.web.RegisteredOAuth2AuthorizedClientController; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Client; +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockOAuth2Login; + +@WebFluxTest +@Import({ SecurityConfig.class, RegisteredOAuth2AuthorizedClientController.class }) +@AutoConfigureWebTestClient +@RunWith(SpringRunner.class) +public class RegisteredOAuth2AuthorizedClientControllerTests { + private static MockWebServer web = new MockWebServer(); + + @Autowired + private WebTestClient client; + + @MockBean + ReactiveClientRegistrationRepository clientRegistrationRepository; + + @AfterClass + public static void shutdown() throws Exception { + web.shutdown(); + } + + @Test + public void annotationExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Login()) + .mutateWith(mockOAuth2Client("client-id")) + .get().uri("/annotation/explicit") + .exchange() + .expectStatus().isOk(); + } + + @Test + public void annotationImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Login()) + .get().uri("/annotation/implicit") + .exchange() + .expectStatus().isOk(); + } + + @Test + public void publicAnnotationExplicitWhenAuthenticatedThenUsesClientIdRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Client("client-id")) + .get().uri("/public/annotation/explicit") + .exchange() + .expectStatus().isOk(); + } + + @Test + public void publicAnnotationImplicitWhenAuthenticatedThenUsesDefaultRegistration() throws Exception { + web.enqueue(new MockResponse().setBody("body").setResponseCode(200)); + this.client.mutateWith(mockOAuth2Login()) + .get().uri("/public/annotation/implicit") + .exchange() + .expectStatus().isOk(); + } + + @Configuration + static class WebClientConfig { + @Bean + WebClient web() { + return WebClient.create(web.url("/").toString()); + } + + @Bean + ServerOAuth2AuthorizedClientRepository authorizedClientRepository() { + return new WebSessionServerOAuth2AuthorizedClientRepository(); + } + } +}