Skip to content

Commit c792c6d

Browse files
committed
Allow reuse of library-specific configuration code in ClientHttpRequestFactoryFactory and ClientHttpConnectorFactory.
See gh-760
1 parent 5f28579 commit c792c6d

File tree

4 files changed

+127
-63
lines changed

4 files changed

+127
-63
lines changed

spring-vault-core/src/main/java/org/springframework/vault/client/ClientHttpConnectorFactory.java

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import reactor.netty.http.Http11SslContextSpec;
2626
import reactor.netty.http.client.HttpClient;
2727

28+
import org.springframework.http.client.ClientHttpRequestFactory;
2829
import org.springframework.http.client.reactive.ClientHttpConnector;
2930
import org.springframework.http.client.reactive.JettyClientHttpConnector;
3031
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
@@ -81,52 +82,42 @@ public static ClientHttpConnector create(ClientOptions options, SslConfiguration
8182
Assert.notNull(options, "ClientOptions must not be null");
8283
Assert.notNull(sslConfiguration, "SslConfiguration must not be null");
8384

84-
if (REACTOR_NETTY_PRESENT) {
85-
return ReactorNetty.usingReactorNetty(options, sslConfiguration);
86-
}
87-
88-
if (JETTY_PRESENT) {
89-
return JettyClient.usingJetty(options, sslConfiguration);
90-
}
91-
92-
throw new IllegalStateException("No supported Reactive Http Client library available (Reactor Netty, Jetty)");
93-
}
94-
95-
private static void configureSsl(SslConfiguration sslConfiguration, SslContextBuilder sslContextBuilder) {
96-
9785
try {
98-
99-
if (sslConfiguration.getTrustStoreConfiguration().isPresent()) {
100-
sslContextBuilder
101-
.trustManager(createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration()));
102-
}
103-
104-
if (sslConfiguration.getKeyStoreConfiguration().isPresent()) {
105-
sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(),
106-
sslConfiguration.getKeyConfiguration()));
86+
if (REACTOR_NETTY_PRESENT) {
87+
return ReactorNetty.usingReactorNetty(options, sslConfiguration);
10788
}
10889

109-
if (!sslConfiguration.getEnabledProtocols().isEmpty()) {
110-
sslContextBuilder.protocols(sslConfiguration.getEnabledProtocols());
111-
}
112-
113-
if (!sslConfiguration.getEnabledCipherSuites().isEmpty()) {
114-
sslContextBuilder.ciphers(sslConfiguration.getEnabledCipherSuites());
90+
if (JETTY_PRESENT) {
91+
return JettyClient.usingJetty(options, sslConfiguration);
11592
}
11693
}
11794
catch (GeneralSecurityException | IOException e) {
11895
throw new IllegalStateException(e);
11996
}
97+
98+
throw new IllegalStateException("No supported Reactive Http Client library available (Reactor Netty, Jetty)");
12099
}
121100

122101
/**
123102
* {@link ClientHttpConnector} for Reactor Netty.
124103
*
125104
* @author Mark Paluch
126105
*/
127-
static class ReactorNetty {
106+
public static class ReactorNetty {
107+
108+
/**
109+
* Create a {@link ClientHttpConnector} using Reactor Netty.
110+
* @param options must not be {@literal null}
111+
* @param sslConfiguration must not be {@literal null}
112+
* @return a new and configured {@link ReactorClientHttpConnector} instance.
113+
*/
114+
public static ReactorClientHttpConnector usingReactorNetty(ClientOptions options,
115+
SslConfiguration sslConfiguration) {
116+
return new ReactorClientHttpConnector(createClient(options, sslConfiguration));
117+
}
118+
119+
public static HttpClient createClient(ClientOptions options, SslConfiguration sslConfiguration) {
128120

129-
static ClientHttpConnector usingReactorNetty(ClientOptions options, SslConfiguration sslConfiguration) {
130121
HttpClient client = HttpClient.create();
131122

132123
if (hasSslConfiguration(sslConfiguration)) {
@@ -140,24 +131,59 @@ static ClientHttpConnector usingReactorNetty(ClientOptions options, SslConfigura
140131
client = client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
141132
Math.toIntExact(options.getConnectionTimeout().toMillis())).proxyWithSystemProperties();
142133

143-
return new ReactorClientHttpConnector(client);
134+
return client;
144135
}
145136

146-
}
137+
private static void configureSsl(SslConfiguration sslConfiguration, SslContextBuilder sslContextBuilder) {
147138

148-
static class JettyClient {
139+
try {
149140

150-
static ClientHttpConnector usingJetty(ClientOptions options, SslConfiguration sslConfiguration) {
141+
if (sslConfiguration.getTrustStoreConfiguration().isPresent()) {
142+
sslContextBuilder
143+
.trustManager(createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration()));
144+
}
151145

152-
try {
153-
return new JettyClientHttpConnector(configureClient(getHttpClient(sslConfiguration), options));
146+
if (sslConfiguration.getKeyStoreConfiguration().isPresent()) {
147+
sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(),
148+
sslConfiguration.getKeyConfiguration()));
149+
}
150+
151+
if (!sslConfiguration.getEnabledProtocols().isEmpty()) {
152+
sslContextBuilder.protocols(sslConfiguration.getEnabledProtocols());
153+
}
154+
155+
if (!sslConfiguration.getEnabledCipherSuites().isEmpty()) {
156+
sslContextBuilder.ciphers(sslConfiguration.getEnabledCipherSuites());
157+
}
154158
}
155159
catch (GeneralSecurityException | IOException e) {
156160
throw new IllegalStateException(e);
157161
}
158162
}
159163

160-
private static org.eclipse.jetty.client.HttpClient configureClient(
164+
}
165+
166+
/**
167+
* Utility methods to create {@link ClientHttpRequestFactory} using the Jetty Client.
168+
*
169+
* @author Mark Paluch
170+
*/
171+
static class JettyClient {
172+
173+
/**
174+
* Create a {@link ClientHttpConnector} using Jetty.
175+
* @param options must not be {@literal null}
176+
* @param sslConfiguration must not be {@literal null}
177+
* @return a new and configured {@link JettyClientHttpConnector} instance.
178+
* @throws GeneralSecurityException
179+
* @throws IOException
180+
*/
181+
public static JettyClientHttpConnector usingJetty(ClientOptions options, SslConfiguration sslConfiguration)
182+
throws GeneralSecurityException, IOException {
183+
return new JettyClientHttpConnector(configureClient(getHttpClient(sslConfiguration), options));
184+
}
185+
186+
public static org.eclipse.jetty.client.HttpClient configureClient(
161187
org.eclipse.jetty.client.HttpClient httpClient, ClientOptions options) {
162188

163189
httpClient.setConnectTimeout(options.getConnectionTimeout().toMillis());
@@ -166,7 +192,7 @@ private static org.eclipse.jetty.client.HttpClient configureClient(
166192
return httpClient;
167193
}
168194

169-
private static org.eclipse.jetty.client.HttpClient getHttpClient(SslConfiguration sslConfiguration)
195+
public static org.eclipse.jetty.client.HttpClient getHttpClient(SslConfiguration sslConfiguration)
170196
throws IOException, GeneralSecurityException {
171197

172198
if (hasSslConfiguration(sslConfiguration)) {

spring-vault-core/src/main/java/org/springframework/vault/client/ClientHttpRequestFactoryFactory.java

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,18 @@ public static ClientHttpRequestFactory create(ClientOptions options, SslConfigur
150150
return new SimpleClientHttpRequestFactory();
151151
}
152152

153-
private static SSLContext getSSLContext(SslConfiguration sslConfiguration, TrustManager[] trustManagers)
153+
private static SSLContext getSSLContext(SslConfiguration sslConfiguration)
154154
throws GeneralSecurityException, IOException {
155155

156-
KeyConfiguration keyConfiguration = sslConfiguration.getKeyConfiguration();
157-
KeyManager[] keyManagers = sslConfiguration.getKeyStoreConfiguration().isPresent()
158-
? createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(), keyConfiguration)
159-
.getKeyManagers()
160-
: null;
156+
return getSSLContext(sslConfiguration.getKeyStoreConfiguration(), sslConfiguration.getKeyConfiguration(),
157+
getTrustManagers(sslConfiguration));
158+
}
159+
160+
static SSLContext getSSLContext(KeyStoreConfiguration keyStoreConfiguration, KeyConfiguration keyConfiguration,
161+
@Nullable TrustManager[] trustManagers) throws GeneralSecurityException, IOException {
162+
163+
KeyManager[] keyManagers = keyStoreConfiguration.isPresent()
164+
? createKeyManagerFactory(keyStoreConfiguration, keyConfiguration).getKeyManagers() : null;
161165

162166
SSLContext sslContext = SSLContext.getInstance("TLS");
163167
sslContext.init(keyManagers, trustManagers, null);
@@ -166,7 +170,7 @@ private static SSLContext getSSLContext(SslConfiguration sslConfiguration, Trust
166170
}
167171

168172
@Nullable
169-
private static TrustManager[] getTrustManagers(SslConfiguration sslConfiguration)
173+
static TrustManager[] getTrustManagers(SslConfiguration sslConfiguration)
170174
throws GeneralSecurityException, IOException {
171175

172176
return sslConfiguration.getTrustStoreConfiguration().isPresent()
@@ -282,13 +286,30 @@ static boolean hasSslConfiguration(SslConfiguration sslConfiguration) {
282286
}
283287

284288
/**
285-
* {@link ClientHttpRequestFactory} for Apache Http Components.
289+
* Utilities to create a {@link ClientHttpRequestFactory} for Apache Http Components.
286290
*
287291
* @author Mark Paluch
288292
*/
289-
static class HttpComponents {
293+
public static class HttpComponents {
294+
295+
/**
296+
* Create a {@link ClientHttpRequestFactory} using Apache Http Components.
297+
* @param options must not be {@literal null}
298+
* @param sslConfiguration must not be {@literal null}
299+
* @return a new and configured {@link HttpComponentsClientHttpRequestFactory}
300+
* instance.
301+
* @throws GeneralSecurityException
302+
* @throws IOException
303+
*/
304+
public static HttpComponentsClientHttpRequestFactory usingHttpComponents(ClientOptions options,
305+
SslConfiguration sslConfiguration) throws GeneralSecurityException, IOException {
306+
307+
HttpClientBuilder httpClientBuilder = getHttpClientBuilder(options, sslConfiguration);
290308

291-
static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, SslConfiguration sslConfiguration)
309+
return new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
310+
}
311+
312+
public static HttpClientBuilder getHttpClientBuilder(ClientOptions options, SslConfiguration sslConfiguration)
292313
throws GeneralSecurityException, IOException {
293314

294315
HttpClientBuilder httpClientBuilder = HttpClients.custom();
@@ -298,7 +319,7 @@ static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, SslCo
298319

299320
if (hasSslConfiguration(sslConfiguration)) {
300321

301-
SSLContext sslContext = getSSLContext(sslConfiguration, getTrustManagers(sslConfiguration));
322+
SSLContext sslContext = getSSLContext(sslConfiguration);
302323

303324
String[] enabledProtocols = null;
304325

@@ -330,19 +351,36 @@ static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, SslCo
330351
// Support redirects
331352
httpClientBuilder.setRedirectStrategy(new LaxRedirectStrategy());
332353

333-
return new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
354+
return httpClientBuilder;
334355
}
335356

336357
}
337358

338359
/**
339-
* {@link ClientHttpRequestFactory} for the {@link okhttp3.OkHttpClient}.
360+
* Utilities to create a {@link ClientHttpRequestFactory} for the
361+
* {@link okhttp3.OkHttpClient}.
340362
*
341363
* @author Mark Paluch
342364
*/
343-
static class OkHttp3 {
365+
public static class OkHttp3 {
344366

345-
static ClientHttpRequestFactory usingOkHttp3(ClientOptions options, SslConfiguration sslConfiguration)
367+
/**
368+
* Create a {@link ClientHttpRequestFactory} using {@link okhttp3.OkHttpClient}.
369+
* @param options must not be {@literal null}
370+
* @param sslConfiguration must not be {@literal null}
371+
* @return a new and configured {@link OkHttp3ClientHttpRequestFactory} instance.
372+
* @throws GeneralSecurityException
373+
* @throws IOException
374+
*/
375+
public static OkHttp3ClientHttpRequestFactory usingOkHttp3(ClientOptions options,
376+
SslConfiguration sslConfiguration) throws GeneralSecurityException, IOException {
377+
378+
Builder builder = getBuilder(options, sslConfiguration);
379+
380+
return new OkHttp3ClientHttpRequestFactory(builder.build());
381+
}
382+
383+
public static Builder getBuilder(ClientOptions options, SslConfiguration sslConfiguration)
346384
throws GeneralSecurityException, IOException {
347385

348386
Builder builder = new Builder();
@@ -353,13 +391,14 @@ static ClientHttpRequestFactory usingOkHttp3(ClientOptions options, SslConfigura
353391

354392
TrustManager[] trustManagers = getTrustManagers(sslConfiguration);
355393

356-
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
394+
if (trustManagers == null || trustManagers.length != 1
395+
|| !(trustManagers[0] instanceof X509TrustManager)) {
357396
throw new IllegalStateException(
358397
"Unexpected default trust managers:" + Arrays.toString(trustManagers));
359398
}
360399

361-
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
362-
SSLContext sslContext = getSSLContext(sslConfiguration, trustManagers);
400+
SSLContext sslContext = getSSLContext(sslConfiguration.getKeyStoreConfiguration(),
401+
sslConfiguration.getKeyConfiguration(), trustManagers);
363402

364403
ConnectionSpec.Builder sslConnectionSpecBuilder = new ConnectionSpec.Builder(sslConnectionSpec);
365404

@@ -374,15 +413,14 @@ static ClientHttpRequestFactory usingOkHttp3(ClientOptions options, SslConfigura
374413

375414
sslConnectionSpec = sslConnectionSpecBuilder.build();
376415

377-
builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
416+
builder.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0]);
378417
}
379418

380419
builder.connectionSpecs(Arrays.asList(sslConnectionSpec, ConnectionSpec.CLEARTEXT));
381420

382421
builder.connectTimeout(options.getConnectionTimeout().toMillis(), TimeUnit.MILLISECONDS)
383422
.readTimeout(options.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS);
384-
385-
return new OkHttp3ClientHttpRequestFactory(builder.build());
423+
return builder;
386424
}
387425

388426
}

spring-vault-core/src/test/java/org/springframework/vault/client/ClientHttpConnectorFactoryIntegrationTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ void reactorNettyClientWithExplicitEnabledProtocolsShouldWork() {
8686
}
8787

8888
@Test
89-
void jettyClientShouldWork() {
89+
void jettyClientShouldWork() throws Exception {
9090

9191
ClientHttpConnector factory = JettyClient.usingJetty(new ClientOptions(), Settings.createSslConfiguration());
9292

@@ -98,7 +98,7 @@ void jettyClientShouldWork() {
9898
}
9999

100100
@Test
101-
void jettyClientWithExplicitEnabledCipherSuitesShouldWork() {
101+
void jettyClientWithExplicitEnabledCipherSuitesShouldWork() throws Exception {
102102

103103
List<String> enabledCipherSuites = new ArrayList<String>();
104104
enabledCipherSuites.add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
@@ -115,7 +115,7 @@ void jettyClientWithExplicitEnabledCipherSuitesShouldWork() {
115115
}
116116

117117
@Test
118-
void jettyClientWithExplicitEnabledProtocolsShouldWork() {
118+
void jettyClientWithExplicitEnabledProtocolsShouldWork() throws Exception {
119119

120120
List<String> enabledProtocols = new ArrayList<String>();
121121
enabledProtocols.add("TLSv1.2");

spring-vault-core/src/test/java/org/springframework/vault/core/VaultKeyValueMetadataTemplateIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void shouldDeleteMetadata() {
160160
this.kvOperations.delete(SECRET_NAME);
161161
VaultMetadataResponse metadataResponse = this.vaultKeyValueMetadataOperations.get(SECRET_NAME);
162162
Versioned.Metadata version1 = metadataResponse.getVersions().get(0);
163-
assertThat(version1.getDeletedAt()).isBefore(Instant.now());
163+
assertThat(version1.getDeletedAt()).isBefore(Instant.now().plusSeconds(5));
164164

165165
this.vaultKeyValueMetadataOperations.delete(SECRET_NAME);
166166

0 commit comments

Comments
 (0)