Configure sample with Mutual-TLS client certificate-bound access tokens

Issue gh-1560
This commit is contained in:
Joe Grandja
2024-04-12 09:01:19 -04:00
parent f1e6ec1719
commit ff4b542b83
6 changed files with 115 additions and 4 deletions

View File

@@ -18,13 +18,24 @@ package sample.config;
import java.util.Arrays;
import java.util.function.Supplier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.SslProvider;
import sample.authorization.DeviceCodeOAuth2AuthorizedClientProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
@@ -54,11 +65,15 @@ import org.springframework.web.reactive.function.client.WebClient;
public class WebClientConfig {
@Bean("default-client-web-client")
public WebClient defaultClientWebClient(OAuth2AuthorizedClientManager authorizedClientManager) {
public WebClient defaultClientWebClient(
OAuth2AuthorizedClientManager authorizedClientManager,
SslBundles sslBundles) throws Exception {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
// @formatter:off
return WebClient.builder()
.clientConnector(createClientConnector(sslBundles.getBundle("demo-client")))
.apply(oauth2Client.oauth2Configuration())
.build();
// @formatter:on
@@ -69,7 +84,8 @@ public class WebClientConfig {
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository,
RestTemplateBuilder restTemplateBuilder,
@Qualifier("self-signed-demo-client-http-request-factory") Supplier<ClientHttpRequestFactory> clientHttpRequestFactory) {
@Qualifier("self-signed-demo-client-http-request-factory") Supplier<ClientHttpRequestFactory> clientHttpRequestFactory,
SslBundles sslBundles) throws Exception {
// @formatter:off
RestTemplate restTemplate = restTemplateBuilder
@@ -98,6 +114,7 @@ public class WebClientConfig {
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
// @formatter:off
return WebClient.builder()
.clientConnector(createClientConnector(sslBundles.getBundle("self-signed-demo-client")))
.apply(oauth2Client.oauth2Configuration())
.build();
// @formatter:on
@@ -143,6 +160,22 @@ public class WebClientConfig {
return authorizedClientManager;
}
private static ClientHttpConnector createClientConnector(SslBundle sslBundle) throws Exception {
KeyManagerFactory keyManagerFactory = sslBundle.getManagers().getKeyManagerFactory();
TrustManagerFactory trustManagerFactory = sslBundle.getManagers().getTrustManagerFactory();
// @formatter:off
SslContext sslContext = SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(trustManagerFactory)
.build();
// @formatter:on
SslProvider sslProvider = SslProvider.builder().sslContext(sslContext).build();
HttpClient httpClient = HttpClient.create().secure(sslProvider);
return new ReactorClientHttpConnector(httpClient);
}
private static OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> createClientCredentialsTokenResponseClient(
RestTemplate restTemplate) {
DefaultClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient =