[BAEL-2315] spring-5-reactive-oauth & spring-5-security-oauth | WebClient and OAuth2 support (#6053)
* Cleaned shared properties in spring-5-security-oauth module, and made some final tunings on authorization service and the resource server * Added and modified example for webclient-oauth2 * Cleaned authorization service and resource service for webclient and oauth2 article * Added examples for auth code with client and with login cleaned properties and packages * Added examples fow webclient + oauth2
This commit is contained in:
parent
8311bde4bb
commit
bbb6c93598
|
@ -3,11 +3,13 @@ package com.baeldung.reactive.oauth;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
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.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
|
||||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@PropertySource("classpath:default-application.yml")
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class Spring5ReactiveOauthApplication {
|
public class Spring5ReactiveOauthApplication {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodeclient;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth
|
||||||
|
*
|
||||||
|
* As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server
|
||||||
|
*
|
||||||
|
* @author rozagerardo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PropertySource("classpath:webclient-auth-code-client-application.properties")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class OauthClientApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(OauthClientApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodeclient.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
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.server.ServerOAuth2AuthorizedClientRepository;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
WebClient webClientForAuthorized(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) {
|
||||||
|
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
|
||||||
|
return WebClient.builder()
|
||||||
|
.filter(oauth)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodeclient.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSecurityConfig {
|
||||||
|
@Bean
|
||||||
|
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
|
http.authorizeExchange()
|
||||||
|
.anyExchange()
|
||||||
|
.authenticated()
|
||||||
|
.and()
|
||||||
|
.oauth2Client()
|
||||||
|
.and()
|
||||||
|
.formLogin();
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodeclient.web;
|
||||||
|
|
||||||
|
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
|
||||||
|
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||||
|
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class ClientRestController {
|
||||||
|
|
||||||
|
private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
WebClient webClient;
|
||||||
|
|
||||||
|
@GetMapping("/auth-code")
|
||||||
|
Mono<String> useOauthWithAuthCode() {
|
||||||
|
Mono<String> retrievedResource = webClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/auth-code-annotated")
|
||||||
|
Mono<String> useOauthWithAuthCodeAndAnnotation(@RegisteredOAuth2AuthorizedClient("bael") OAuth2AuthorizedClient authorizedClient) {
|
||||||
|
Mono<String> retrievedResource = webClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string + ". Principal associated: " + authorizedClient.getPrincipalName() + ". Token will expire at: " + authorizedClient.getAccessToken()
|
||||||
|
.getExpiresAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/auth-code-explicit-client")
|
||||||
|
Mono<String> useOauthWithExpicitClient() {
|
||||||
|
Mono<String> retrievedResource = webClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.attributes(clientRegistrationId("bael"))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodelogin;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth
|
||||||
|
*
|
||||||
|
* As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server
|
||||||
|
*
|
||||||
|
* @author rozagerardo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PropertySource("classpath:webclient-auth-code-login-application.properties")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class OauthClientApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(OauthClientApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodelogin.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
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.server.ServerOAuth2AuthorizedClientRepository;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
WebClient webClientForAuthorized(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) {
|
||||||
|
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
|
||||||
|
oauth.setDefaultOAuth2AuthorizedClient(true);
|
||||||
|
return WebClient.builder()
|
||||||
|
.filter(oauth)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
WebClient otherWebClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) {
|
||||||
|
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
|
||||||
|
return WebClient.builder()
|
||||||
|
.filter(oauth)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodelogin.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSecurityConfig {
|
||||||
|
@Bean
|
||||||
|
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
|
http.authorizeExchange()
|
||||||
|
.anyExchange()
|
||||||
|
.authenticated()
|
||||||
|
.and()
|
||||||
|
.oauth2Login();
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.baeldung.webclient.authorizationcodelogin.web;
|
||||||
|
|
||||||
|
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
|
||||||
|
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||||
|
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class ClientRestController {
|
||||||
|
|
||||||
|
private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
WebClient webClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("otherWebClient")
|
||||||
|
WebClient otherWebClient;
|
||||||
|
|
||||||
|
@GetMapping("/auth-code")
|
||||||
|
Mono<String> useOauthWithAuthCode() {
|
||||||
|
Mono<String> retrievedResource = webClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/auth-code-no-client")
|
||||||
|
Mono<String> useOauthWithNoClient() {
|
||||||
|
// This call will fail, since we don't have the client properly set for this webClient
|
||||||
|
Mono<String> retrievedResource = otherWebClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/auth-code-annotated")
|
||||||
|
Mono<String> useOauthWithAuthCodeAndAnnotation(@RegisteredOAuth2AuthorizedClient("bael") OAuth2AuthorizedClient authorizedClient) {
|
||||||
|
Mono<String> retrievedResource = otherWebClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.attributes(oauth2AuthorizedClient(authorizedClient))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string + ". Principal associated: " + authorizedClient.getPrincipalName() + ". Token will expire at: " + authorizedClient.getAccessToken()
|
||||||
|
.getExpiresAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/auth-code-explicit-client")
|
||||||
|
Mono<String> useOauthWithExpicitClient() {
|
||||||
|
Mono<String> retrievedResource = otherWebClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.attributes(clientRegistrationId("bael"))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return retrievedResource.map(string -> "We retrieved the following resource using Oauth: " + string);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.webclient.clientcredentials;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth
|
||||||
|
*
|
||||||
|
* As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using credentials handled by the auth server (bael-user/bael-password)
|
||||||
|
*
|
||||||
|
* @author rozagerardo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PropertySource("classpath:webclient-client-credentials-oauth-application.properties")
|
||||||
|
@EnableScheduling
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ClientCredentialsOauthApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ClientCredentialsOauthApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.webclient.clientcredentials.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
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.server.UnAuthenticatedServerOAuth2AuthorizedClientRepository;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
|
||||||
|
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
|
||||||
|
oauth.setDefaultClientRegistrationId("bael");
|
||||||
|
return WebClient.builder()
|
||||||
|
.filter(oauth)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.baeldung.webclient.clientcredentials.service;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||||
|
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class WebClientChonJob {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(WebClientChonJob.class);
|
||||||
|
|
||||||
|
private static final String RESOURCE_URI = "http://localhost:8084/retrieve-resource";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebClient webClient;
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 1000)
|
||||||
|
public void logResourceServiceResponse() {
|
||||||
|
|
||||||
|
webClient.get()
|
||||||
|
.uri(RESOURCE_URI)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class)
|
||||||
|
.map(string -> "We retrieved the following resource using Client Credentials Grant Type: " + string)
|
||||||
|
.subscribe(logger::info);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.baeldung.webclient.manualrequest;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: This app is configured to use the authorization service and the resource service located in module spring-5-security-oauth
|
||||||
|
*
|
||||||
|
* As we usually do with other well-known auth providers (github/facebook/...) we have to log-in using user credentials (bael-user/bael-password) and client configurations (bael-client-id/bael-secret) handled by the auth server
|
||||||
|
*
|
||||||
|
* @author rozagerardo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ManualRequestApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ManualRequestApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.baeldung.webclient.manualrequest.configure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebClient configureWebClient() {
|
||||||
|
return WebClient.builder()
|
||||||
|
.build();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung.webclient.manualrequest.configure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSecurityConfig {
|
||||||
|
@Bean
|
||||||
|
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
|
http.authorizeExchange()
|
||||||
|
.anyExchange()
|
||||||
|
.permitAll();
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.baeldung.webclient.manualrequest.web;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.util.Base64Utils;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.nimbusds.oauth2.sdk.GrantType;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class ManualOauthRequestController {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(ManualOauthRequestController.class);
|
||||||
|
|
||||||
|
private static final String TOKEN_ENDPOINT = "localhost:8085/oauth/token";
|
||||||
|
private static final String RESOURCE_ENDPOINT = "localhost:8084/retrieve-resource";
|
||||||
|
private static final String CLIENT_ID = "bael-client-id";
|
||||||
|
private static final String CLIENT_SECRET = "bael-secret";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
WebClient client;
|
||||||
|
|
||||||
|
@GetMapping("/manual-request-oauth")
|
||||||
|
public Mono<String> obtainSecuredResource() {
|
||||||
|
logger.info("Creating web client...");
|
||||||
|
Mono<String> resource = client.post()
|
||||||
|
.uri(TOKEN_ENDPOINT)
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes()))
|
||||||
|
.body(BodyInserters.fromFormData(OAuth2ParameterNames.GRANT_TYPE, GrantType.CLIENT_CREDENTIALS.getValue()))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(JsonNode.class)
|
||||||
|
.flatMap(tokenResponse -> {
|
||||||
|
String accessTokenValue = tokenResponse.get("access_token")
|
||||||
|
.textValue();
|
||||||
|
logger.info("Retrieved the following access token: {}", accessTokenValue);
|
||||||
|
return client.get()
|
||||||
|
.uri(RESOURCE_ENDPOINT)
|
||||||
|
.headers(h -> h.setBearerAuth(accessTokenValue))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
});
|
||||||
|
logger.info("non-blocking Oauth calls registered...");
|
||||||
|
return resource.map(res -> "Retrieved the resource using a manual approach: " + res);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,20 +1,3 @@
|
||||||
spring:
|
logging:
|
||||||
security:
|
level:
|
||||||
oauth2:
|
root: DEBUG
|
||||||
client:
|
|
||||||
registration:
|
|
||||||
google:
|
|
||||||
client-id: YOUR_APP_CLIENT_ID
|
|
||||||
client-secret: YOUR_APP_CLIENT_SECRET
|
|
||||||
custom:
|
|
||||||
client-id: fooClientIdPassword
|
|
||||||
client-secret: secret
|
|
||||||
scopes: read,foo
|
|
||||||
authorization-grant-type: authorization_code
|
|
||||||
redirect-uri-template: http://localhost:8080/login/oauth2/code/custom
|
|
||||||
provider:
|
|
||||||
custom:
|
|
||||||
authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize
|
|
||||||
token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token
|
|
||||||
user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra
|
|
||||||
user-name-attribute: user_name
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
spring:
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
client:
|
||||||
|
registration:
|
||||||
|
google:
|
||||||
|
client-id: YOUR_APP_CLIENT_ID
|
||||||
|
client-secret: YOUR_APP_CLIENT_SECRET
|
||||||
|
custom:
|
||||||
|
client-id: fooClientIdPassword
|
||||||
|
client-secret: secret
|
||||||
|
scopes: read,foo
|
||||||
|
authorization-grant-type: authorization_code
|
||||||
|
redirect-uri-template: http://localhost:8080/login/oauth2/code/custom
|
||||||
|
provider:
|
||||||
|
custom:
|
||||||
|
authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize
|
||||||
|
token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token
|
||||||
|
user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra
|
||||||
|
user-name-attribute: user_name
|
|
@ -0,0 +1,10 @@
|
||||||
|
spring.security.oauth2.client.registration.bael.client-name=bael
|
||||||
|
spring.security.oauth2.client.registration.bael.client-id=bael-client-id
|
||||||
|
spring.security.oauth2.client.registration.bael.client-secret=bael-secret
|
||||||
|
spring.security.oauth2.client.registration.bael.authorization-grant-type=authorization_code
|
||||||
|
spring.security.oauth2.client.registration.bael.redirect-uri=http://localhost:8080/authorize/oauth2/code/bael
|
||||||
|
|
||||||
|
spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token
|
||||||
|
spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8085/oauth/authorize
|
||||||
|
|
||||||
|
spring.security.user.password=pass
|
|
@ -0,0 +1,10 @@
|
||||||
|
spring.security.oauth2.client.registration.bael.client-name=bael
|
||||||
|
spring.security.oauth2.client.registration.bael.client-id=bael-client-id
|
||||||
|
spring.security.oauth2.client.registration.bael.client-secret=bael-secret
|
||||||
|
spring.security.oauth2.client.registration.bael.authorization-grant-type=authorization_code
|
||||||
|
spring.security.oauth2.client.registration.bael.redirect-uri=http://localhost:8080/login/oauth2/code/bael
|
||||||
|
|
||||||
|
spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token
|
||||||
|
spring.security.oauth2.client.provider.bael.authorization-uri=http://localhost:8085/oauth/authorize
|
||||||
|
spring.security.oauth2.client.provider.bael.user-info-uri=http://localhost:8084/user
|
||||||
|
spring.security.oauth2.client.provider.bael.user-name-attribute=name
|
|
@ -0,0 +1,4 @@
|
||||||
|
spring.security.oauth2.client.registration.bael.authorization-grant-type=client_credentials
|
||||||
|
spring.security.oauth2.client.registration.bael.client-id=bael-client-id
|
||||||
|
spring.security.oauth2.client.registration.bael.client-secret=bael-secret
|
||||||
|
spring.security.oauth2.client.provider.bael.token-uri=http://localhost:8085/oauth/token
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.baeldung.webclient.clientcredentials;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import com.baeldung.webclient.clientcredentials.service.WebClientChonJob;
|
||||||
|
import com.baeldung.webclient.utils.ListAppender;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: this Live test requires the Authorization Service and the Resource service located in the spring-5-security-oauth module
|
||||||
|
*
|
||||||
|
* @author ger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = { ClientCredentialsOauthApplication.class })
|
||||||
|
public class OAuth2ClientCredentialsLiveTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
WebClientChonJob service;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void clearLogList() {
|
||||||
|
ListAppender.clearEventList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFooWithNullId_whenProcessFoo_thenLogsWithDebugTrace() throws Exception {
|
||||||
|
service.logResourceServiceResponse();
|
||||||
|
|
||||||
|
Thread.sleep(3000);
|
||||||
|
|
||||||
|
Collection<String> allLoggedEntries = ListAppender.getEvents()
|
||||||
|
.stream()
|
||||||
|
.map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertThat(allLoggedEntries).anyMatch(entry -> entry.contains("We retrieved the following resource using Client Credentials Grant Type: This is the resource!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.baeldung.webclient.manualrequest;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Note: this Live test requires not only the corresponding application running,
|
||||||
|
* but also the Authorization Service and the Resource service located in the spring-5-security-oauth module.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author ger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class OAuth2ManualRequestLiveTest {
|
||||||
|
|
||||||
|
private static final String BASE_URL = "http://localhost:8080";
|
||||||
|
private static final String MANUAL_REQUEST_URI = "/manual-request-oauth";
|
||||||
|
|
||||||
|
private static WebTestClient client;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
client = WebTestClient.bindToServer()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRequestingDebugHookOn_thenObtainExpectedMessage() {
|
||||||
|
ResponseSpec response = client.get()
|
||||||
|
.uri(MANUAL_REQUEST_URI)
|
||||||
|
.exchange();
|
||||||
|
|
||||||
|
response.expectStatus()
|
||||||
|
.isOk()
|
||||||
|
.expectBody(String.class)
|
||||||
|
.isEqualTo("Retrieved the resource using a manual approach: This is the resource!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.baeldung.webclient.utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.AppenderBase;
|
||||||
|
|
||||||
|
public class ListAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
|
static private List<ILoggingEvent> events = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent eventObject) {
|
||||||
|
events.add(eventObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ILoggingEvent> getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearEventList() {
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<include
|
||||||
|
resource="org/springframework/boot/logging/logback/base.xml" />
|
||||||
|
<appender name="LISTAPPENDER"
|
||||||
|
class="com.baeldung.webclient.utils.ListAppender">
|
||||||
|
</appender>
|
||||||
|
<logger
|
||||||
|
name="com.baeldung.webclient.clientcredentials.service.WebClientChonJob">
|
||||||
|
<appender-ref ref="LISTAPPENDER" />
|
||||||
|
</logger>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<appender-ref ref="LISTAPPENDER" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -2,7 +2,9 @@ package com.baeldung.oauth2;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
@PropertySource("classpath:default-application.properties")
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class SpringOAuthApplication {
|
public class SpringOAuthApplication {
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,12 @@ package com.baeldung.oauth2extractors;
|
||||||
import org.apache.logging.log4j.util.Strings;
|
import org.apache.logging.log4j.util.Strings;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.core.env.AbstractEnvironment;
|
import org.springframework.core.env.AbstractEnvironment;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
@PropertySource("classpath:default-application.properties")
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@Controller
|
@Controller
|
||||||
public class ExtractorsApplication {
|
public class ExtractorsApplication {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung.webclient.authorizationserver;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||||
|
|
||||||
|
@EnableAuthorizationServer
|
||||||
|
@PropertySource("classpath:webclient-authorization-application.properties")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class AuthorizationServerApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(AuthorizationServerApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.webclient.authorizationserver.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
@Configuration
|
||||||
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.authorizeRequests()
|
||||||
|
.antMatchers("/login", "/user")
|
||||||
|
.permitAll()
|
||||||
|
.and()
|
||||||
|
.authorizeRequests()
|
||||||
|
.anyRequest()
|
||||||
|
.authenticated()
|
||||||
|
.and()
|
||||||
|
.formLogin()
|
||||||
|
.and()
|
||||||
|
.httpBasic();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung.webclient.resourceserver;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||||
|
|
||||||
|
@EnableResourceServer
|
||||||
|
@PropertySource("webclient-resources-application.properties")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ResourceServerApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ResourceServerApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.baeldung.webclient.resourceserver.configuration;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
||||||
|
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class AuthorizationConfigs {
|
||||||
|
|
||||||
|
@Value("${oauth.authserver.client-id}")
|
||||||
|
String clientId;
|
||||||
|
|
||||||
|
@Value("${oauth.authserver.client-secret}")
|
||||||
|
String clientSecret;
|
||||||
|
|
||||||
|
@Value("${oauth.authserver.check-token-endpoint}")
|
||||||
|
String checkTokenEndpoint;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ResourceServerTokenServices tokenSvc() {
|
||||||
|
RemoteTokenServices remoteService = new RemoteTokenServices();
|
||||||
|
remoteService.setCheckTokenEndpointUrl(checkTokenEndpoint);
|
||||||
|
remoteService.setClientId(clientId);
|
||||||
|
remoteService.setClientSecret(clientSecret);
|
||||||
|
return remoteService;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.baeldung.webclient.resourceserver.web;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class ResourceRestController {
|
||||||
|
|
||||||
|
@GetMapping("/retrieve-resource")
|
||||||
|
public String retrieveResource() {
|
||||||
|
return "This is the resource!";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/user")
|
||||||
|
@ResponseBody
|
||||||
|
public Principal user(Principal user) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
server.port=8081
|
|
||||||
|
|
||||||
logging.level.root=INFO
|
logging.level.root=INFO
|
||||||
|
|
||||||
logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG
|
logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG
|
|
@ -0,0 +1 @@
|
||||||
|
server.port=8081
|
|
@ -0,0 +1,13 @@
|
||||||
|
server.port=8085
|
||||||
|
|
||||||
|
security.oauth2.client.client-id=bael-client-id
|
||||||
|
security.oauth2.client.client-secret=bael-secret
|
||||||
|
security.oauth2.client.scope=read,write
|
||||||
|
|
||||||
|
security.oauth2.authorization.check-token-access=isAuthenticated()
|
||||||
|
|
||||||
|
spring.security.user.name=bael-user
|
||||||
|
spring.security.user.password=bael-password
|
||||||
|
|
||||||
|
security.oauth2.client.registered-redirect-uri=http://localhost:8080/login/oauth2/code/bael, http://localhost:8080/authorize/oauth2/code/bael
|
||||||
|
security.oauth2.client.use-current-uri=false
|
|
@ -0,0 +1,6 @@
|
||||||
|
server.port=8084
|
||||||
|
|
||||||
|
#spring.security.oauth2.resourceserver.jwt.issuer-uri=localhost:8085
|
||||||
|
oauth.authserver.client-id=bael-client-id
|
||||||
|
oauth.authserver.client-secret=bael-secret
|
||||||
|
oauth.authserver.check-token-endpoint=http://localhost:8085/oauth/check_token
|
Loading…
Reference in New Issue