Browse Source

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

Issue gh-1560
pull/1609/head
Joe Grandja 2 years ago
parent
commit
ff4b542b83
  1. 6
      samples/demo-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java
  2. 37
      samples/demo-client/src/main/java/sample/config/WebClientConfig.java
  3. 2
      samples/demo-client/src/main/resources/application.yml
  4. 8
      samples/messages-resource/src/main/java/sample/config/ResourceServerConfig.java
  5. 46
      samples/messages-resource/src/main/java/sample/config/TomcatServerConfig.java
  6. 20
      samples/messages-resource/src/main/resources/application.yml

6
samples/demo-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

@ -50,6 +50,7 @@ import org.springframework.security.oauth2.server.authorization.config.annotatio @@ -50,6 +50,7 @@ import org.springframework.security.oauth2.server.authorization.config.annotatio
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.web.SecurityFilterChain;
@ -179,6 +180,11 @@ public class AuthorizationServerConfig { @@ -179,6 +180,11 @@ public class AuthorizationServerConfig {
.jwkSetUrl("http://127.0.0.1:8080/jwks")
.build()
)
.tokenSettings(
TokenSettings.builder()
.x509CertificateBoundAccessTokens(true)
.build()
)
.build();
// Save registered client's in db as if in-memory

37
samples/demo-client/src/main/java/sample/config/WebClientConfig.java

@ -18,13 +18,24 @@ package sample.config; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 =

2
samples/demo-client/src/main/resources/application.yml

@ -101,7 +101,7 @@ spring: @@ -101,7 +101,7 @@ spring:
token-uri: https://localhost:9443/oauth2/token
messages:
base-uri: http://127.0.0.1:8090/messages
base-uri: https://127.0.0.1:8443/messages
user-messages:
base-uri: http://127.0.0.1:8091/user/messages

8
samples/messages-resource/src/main/java/sample/config/ResourceServerConfig.java

@ -30,6 +30,14 @@ import org.springframework.security.web.SecurityFilterChain; @@ -30,6 +30,14 @@ import org.springframework.security.web.SecurityFilterChain;
@Configuration(proxyBeanMethods = false)
public class ResourceServerConfig {
/*
NOTE:
The `NimbusJwtDecoder` `@Bean` autoconfigured by Spring Boot will contain
an `OAuth2TokenValidator<Jwt>` of type `X509CertificateThumbprintValidator`.
This is the validator responsible for validating the `x5t#S256` claim (if available)
in the `Jwt` against the SHA-256 Thumbprint of the supplied `X509Certificate`.
*/
// @formatter:off
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

46
samples/messages-resource/src/main/java/sample/config/TomcatServerConfig.java

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
/*
* Copyright 2020-2024 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.config;
import org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Joe Grandja
* @since 1.3
*/
@Configuration(proxyBeanMethods = false)
public class TomcatServerConfig {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() {
return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createHttpConnector());
}
private Connector createHttpConnector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8090);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}

20
samples/messages-resource/src/main/resources/application.yml

@ -1,5 +1,8 @@ @@ -1,5 +1,8 @@
server:
port: 8090
port: 8443
ssl:
bundle: messages-resource
client-auth: need
logging:
level:
@ -10,6 +13,21 @@ logging: @@ -10,6 +13,21 @@ logging:
# org.springframework.boot.autoconfigure: DEBUG
spring:
ssl:
bundle:
jks:
messages-resource:
key:
alias: messages-resource-sample
password: password
keystore:
location: classpath:keystore.p12
password: password
type: PKCS12
truststore:
location: classpath:keystore.p12
password: password
type: PKCS12
security:
oauth2:
resourceserver:

Loading…
Cancel
Save