From ae17cc255b523d0ccaf24bb6e6aec5f61c481853 Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Thu, 1 Jun 2017 11:46:22 -0400 Subject: [PATCH] Implement protected resource call flow in oauth2login sample Fixes gh-4362 --- ...g-security-samples-boot-oauth2login.gradle | 2 + .../samples/OAuth2LoginApplicationTests.java | 12 +++--- .../main/java/sample/web/MainController.java | 37 ++++++++++++++++++- .../src/main/resources/templates/index.html | 14 +++---- .../main/resources/templates/userinfo.html | 19 ++++++++++ 5 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 samples/boot/oauth2login/src/main/resources/templates/userinfo.html diff --git a/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle b/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle index 7d8dbdfd83..28ab539c51 100644 --- a/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle +++ b/samples/boot/oauth2login/spring-security-samples-boot-oauth2login.gradle @@ -3,9 +3,11 @@ apply plugin: 'io.spring.convention.spring-sample-boot' dependencies { compile project(':spring-security-config') compile project(':spring-security-oauth2-client') + compile 'org.springframework:spring-webflux' compile 'org.springframework.boot:spring-boot-starter-thymeleaf' compile 'org.springframework.boot:spring-boot-starter-web' compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity4' + compile 'io.projectreactor.ipc:reactor-netty' testCompile project(':spring-security-test') testCompile 'net.sourceforge.htmlunit:htmlunit' diff --git a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java index 07a109a6de..c449e2c6b8 100644 --- a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java +++ b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java @@ -98,7 +98,7 @@ public class OAuth2LoginApplicationTests { } @Test - public void requestRootPageWhenNotAuthenticatedThenDisplayLoginPage() throws Exception { + public void requestIndexPageWhenNotAuthenticatedThenDisplayLoginPage() throws Exception { HtmlPage page = this.webClient.getPage("/"); this.assertLoginPage(page); } @@ -158,7 +158,7 @@ public class OAuth2LoginApplicationTests { } @Test - public void requestAuthorizationCodeGrantWhenValidAuthorizationResponseThenDisplayUserInfoPage() throws Exception { + public void requestAuthorizationCodeGrantWhenValidAuthorizationResponseThenDisplayIndexPage() throws Exception { HtmlPage page = this.webClient.getPage("/"); HtmlAnchor clientAnchorElement = this.getClientAnchorElement(page, this.githubClientRegistration); @@ -181,7 +181,7 @@ public class OAuth2LoginApplicationTests { .build().encode().toUriString(); page = this.webClient.getPage(new URL(authorizationResponseUri)); - this.assertUserInfoPage(page); + this.assertIndexPage(page); } @Test @@ -324,12 +324,12 @@ public class OAuth2LoginApplicationTests { } } - private void assertUserInfoPage(HtmlPage page) throws Exception { - assertThat(page.getTitleText()).isEqualTo("Spring Security - OAuth2 User Info"); + private void assertIndexPage(HtmlPage page) throws Exception { + assertThat(page.getTitleText()).isEqualTo("Spring Security - OAuth 2.0 Login"); DomNodeList divElements = page.getBody().getElementsByTagName("div"); assertThat(divElements.get(1).asText()).contains("User: joeg@springsecurity.io"); - assertThat(divElements.get(4).asText()).contains("Name: joeg@springsecurity.io"); + assertThat(divElements.get(4).asText()).contains("You are successfully logged in joeg@springsecurity.io"); } private HtmlAnchor getClientAnchorElement(HtmlPage page, ClientRegistration clientRegistration) { diff --git a/samples/boot/oauth2login/src/main/java/sample/web/MainController.java b/samples/boot/oauth2login/src/main/java/sample/web/MainController.java index 200ae037cd..90697b3f83 100644 --- a/samples/boot/oauth2login/src/main/java/sample/web/MainController.java +++ b/samples/boot/oauth2login/src/main/java/sample/web/MainController.java @@ -15,22 +15,55 @@ */ package sample.web; +import org.springframework.http.HttpHeaders; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.Map; /** * @author Joe Grandja */ @Controller public class MainController { + private WebClient webClient = WebClient.create(); + @RequestMapping("/") - public String index(Model model, @AuthenticationPrincipal OAuth2User user) { + public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2AuthenticationToken authentication) { model.addAttribute("userName", user.getName()); - model.addAttribute("userAttributes", user.getAttributes()); + model.addAttribute("clientName", authentication.getClientRegistration().getClientName()); return "index"; } + + @RequestMapping("/userinfo") + public String userinfo(Model model, OAuth2AuthenticationToken authentication) { + Map userAttributes = this.webClient + .filter(oauth2Credentials(authentication)) + .get() + .uri(authentication.getClientRegistration().getProviderDetails().getUserInfoUri()) + .retrieve() + .bodyToMono(Map.class) + .block(); + model.addAttribute("userAttributes", userAttributes); + return "userinfo"; + } + + private ExchangeFilterFunction oauth2Credentials(OAuth2AuthenticationToken authentication) { + return ExchangeFilterFunction.ofRequestProcessor( + clientRequest -> { + ClientRequest authorizedRequest = ClientRequest.from(clientRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + authentication.getAccessToken().getTokenValue()) + .build(); + return Mono.just(authorizedRequest); + }); + } } diff --git a/samples/boot/oauth2login/src/main/resources/templates/index.html b/samples/boot/oauth2login/src/main/resources/templates/index.html index cd7c31f9d1..c30b73de69 100644 --- a/samples/boot/oauth2login/src/main/resources/templates/index.html +++ b/samples/boot/oauth2login/src/main/resources/templates/index.html @@ -1,7 +1,7 @@ - Spring Security - OAuth2 User Info + Spring Security - OAuth 2.0 Login @@ -16,18 +16,14 @@ -

OAuth2 User Info

+

OAuth 2.0 Login with Spring Security

- Name: + You are successfully logged in + via the OAuth 2.0 Client
 
- Attributes: -
    -
  • - : -
  • -
+ Display User Info
diff --git a/samples/boot/oauth2login/src/main/resources/templates/userinfo.html b/samples/boot/oauth2login/src/main/resources/templates/userinfo.html new file mode 100644 index 0000000000..2f7102469b --- /dev/null +++ b/samples/boot/oauth2login/src/main/resources/templates/userinfo.html @@ -0,0 +1,19 @@ + + + + Spring Security - OAuth 2.0 User Info + + + +
+

OAuth 2.0 User Info

+
+ User Attributes: +
    +
  • + : +
  • +
+
+ +