Skip to content

Commit a85fa86

Browse files
mryangzamp911de
authored andcommitted
Add ability to configure client TLS enabled protocol versions and cipher suites via Spring properties.
- Adding the ability to explicitly configure the enabled SSL protocol versions and cipher suites used by the Vault HTTP client via the following Spring properties: * vault.ssl.enabled-protocols * vault.ssl.enabled-cipher-suites - Properties should be a comma-separated list of String constants that correspond to those used by the enabled SSL provider. Closes gh-635 Original pull request: gh-640.
1 parent 69ba330 commit a85fa86

File tree

8 files changed

+439
-21
lines changed

8 files changed

+439
-21
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ private static void configureSsl(SslConfiguration sslConfiguration, SslContextBu
105105
sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(),
106106
sslConfiguration.getKeyConfiguration()));
107107
}
108+
109+
if (sslConfiguration.getEnabledProtocols() != null) {
110+
sslContextBuilder.protocols(sslConfiguration.getEnabledProtocols());
111+
}
112+
113+
if (sslConfiguration.getEnabledCipherSuites() != null) {
114+
sslContextBuilder.ciphers(sslConfiguration.getEnabledCipherSuites());
115+
}
108116
}
109117
catch (GeneralSecurityException | IOException e) {
110118
throw new IllegalStateException(e);
@@ -189,6 +197,16 @@ private static org.eclipse.jetty.client.HttpClient getHttpClient(SslConfiguratio
189197
sslContextFactory.setKeyManagerPassword(new String(keyConfiguration.getKeyPassword()));
190198
}
191199

200+
if (sslConfiguration.getEnabledProtocols() != null) {
201+
sslContextFactory
202+
.setIncludeProtocols(sslConfiguration.getEnabledProtocols().toArray(new String[0]));
203+
}
204+
205+
if (sslConfiguration.getEnabledCipherSuites() != null) {
206+
sslContextFactory
207+
.setIncludeCipherSuites(sslConfiguration.getEnabledCipherSuites().toArray(new String[0]));
208+
}
209+
192210
return new org.eclipse.jetty.client.HttpClient(sslContextFactory);
193211
}
194212

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

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@
4343
import javax.net.ssl.X509ExtendedKeyManager;
4444
import javax.net.ssl.X509TrustManager;
4545

46-
import io.netty.handler.ssl.SslContextBuilder;
47-
import io.netty.handler.ssl.SslProvider;
48-
import okhttp3.OkHttpClient.Builder;
4946
import org.apache.commons.logging.Log;
5047
import org.apache.commons.logging.LogFactory;
5148
import org.apache.http.client.config.RequestConfig;
@@ -55,7 +52,6 @@
5552
import org.apache.http.impl.client.LaxRedirectStrategy;
5653
import org.apache.http.impl.conn.DefaultSchemePortResolver;
5754
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
58-
5955
import org.springframework.http.client.ClientHttpRequestFactory;
6056
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
6157
import org.springframework.http.client.Netty4ClientHttpRequestFactory;
@@ -69,9 +65,13 @@
6965
import org.springframework.vault.support.ClientOptions;
7066
import org.springframework.vault.support.PemObject;
7167
import org.springframework.vault.support.SslConfiguration;
68+
import org.springframework.vault.support.SslConfiguration.KeyConfiguration;
7269
import org.springframework.vault.support.SslConfiguration.KeyStoreConfiguration;
7370

74-
import static org.springframework.vault.support.SslConfiguration.KeyConfiguration;
71+
import io.netty.handler.ssl.SslContextBuilder;
72+
import io.netty.handler.ssl.SslProvider;
73+
import okhttp3.ConnectionSpec;
74+
import okhttp3.OkHttpClient.Builder;
7575

7676
/**
7777
* Factory for {@link ClientHttpRequestFactory} that supports Apache HTTP Components,
@@ -298,7 +298,21 @@ static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, SslCo
298298
if (hasSslConfiguration(sslConfiguration)) {
299299

300300
SSLContext sslContext = getSSLContext(sslConfiguration, getTrustManagers(sslConfiguration));
301-
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
301+
302+
String[] enabledProtocols = null;
303+
304+
if (sslConfiguration.getEnabledProtocols() != null) {
305+
enabledProtocols = sslConfiguration.getEnabledProtocols().toArray(new String[0]);
306+
}
307+
308+
String[] enabledCipherSuites = null;
309+
310+
if (sslConfiguration.getEnabledCipherSuites() != null) {
311+
enabledCipherSuites = sslConfiguration.getEnabledCipherSuites().toArray(new String[0]);
312+
}
313+
314+
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,
315+
enabledProtocols, enabledCipherSuites, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
302316
httpClientBuilder.setSSLSocketFactory(sslSocketFactory);
303317
httpClientBuilder.setSSLContext(sslContext);
304318
}
@@ -332,6 +346,8 @@ static ClientHttpRequestFactory usingOkHttp3(ClientOptions options, SslConfigura
332346

333347
Builder builder = new Builder();
334348

349+
ConnectionSpec sslConnectionSpec = ConnectionSpec.MODERN_TLS;
350+
335351
if (hasSslConfiguration(sslConfiguration)) {
336352

337353
TrustManager[] trustManagers = getTrustManagers(sslConfiguration);
@@ -344,9 +360,24 @@ static ClientHttpRequestFactory usingOkHttp3(ClientOptions options, SslConfigura
344360
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
345361
SSLContext sslContext = getSSLContext(sslConfiguration, trustManagers);
346362

363+
ConnectionSpec.Builder sslConnectionSpecBuilder = new ConnectionSpec.Builder(sslConnectionSpec);
364+
365+
if (sslConfiguration.getEnabledProtocols() != null) {
366+
sslConnectionSpecBuilder.tlsVersions(sslConfiguration.getEnabledProtocols().toArray(new String[0]));
367+
}
368+
369+
if (sslConfiguration.getEnabledCipherSuites() != null) {
370+
sslConnectionSpecBuilder
371+
.cipherSuites(sslConfiguration.getEnabledCipherSuites().toArray(new String[0]));
372+
}
373+
374+
sslConnectionSpec = sslConnectionSpecBuilder.build();
375+
347376
builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
348377
}
349378

379+
builder.connectionSpecs(Arrays.asList(sslConnectionSpec, ConnectionSpec.CLEARTEXT));
380+
350381
builder.connectTimeout(options.getConnectionTimeout().toMillis(), TimeUnit.MILLISECONDS)
351382
.readTimeout(options.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS);
352383

@@ -382,6 +413,14 @@ static ClientHttpRequestFactory usingNetty(ClientOptions options, SslConfigurati
382413
sslConfiguration.getKeyConfiguration()));
383414
}
384415

416+
if (sslConfiguration.getEnabledProtocols() != null) {
417+
sslContextBuilder.protocols(sslConfiguration.getEnabledProtocols());
418+
}
419+
420+
if (sslConfiguration.getEnabledCipherSuites() != null) {
421+
sslContextBuilder.ciphers(sslConfiguration.getEnabledCipherSuites());
422+
}
423+
385424
requestFactory.setSslContext(sslContextBuilder.sslProvider(SslProvider.JDK).build());
386425
}
387426

spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
package org.springframework.vault.config;
1717

1818
import java.net.URI;
19+
import java.util.Arrays;
20+
import java.util.List;
1921

2022
import org.apache.commons.logging.Log;
2123
import org.apache.commons.logging.LogFactory;
22-
2324
import org.springframework.beans.BeansException;
2425
import org.springframework.context.ApplicationContext;
2526
import org.springframework.context.ApplicationContextAware;
@@ -231,7 +232,12 @@ public SslConfiguration sslConfiguration() {
231232
KeyStoreConfiguration trustStoreConfiguration = getKeyStoreConfiguration("vault.ssl.trust-store",
232233
"vault.ssl.trust-store-password", "vault.ssl.trust-store-type");
233234

234-
return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration);
235+
List<String> enabledProtocols = getList("vault.ssl.enabled-protocols");
236+
237+
List<String> enabledCipherSuites = getList("vault.ssl.enabled-cipher-suites");
238+
239+
return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration, enabledProtocols,
240+
enabledCipherSuites);
235241
}
236242

237243
private KeyStoreConfiguration getKeyStoreConfiguration(String resourceProperty, String passwordProperty,
@@ -421,6 +427,16 @@ protected ClientAuthentication kubeAuthentication() {
421427
return new KubernetesAuthentication(builder.build(), restOperations());
422428
}
423429

430+
private List<String> getList(String key) {
431+
String val = getEnvironment().getProperty(key);
432+
433+
if (val == null) {
434+
return null;
435+
}
436+
437+
return Arrays.asList(val.split(","));
438+
}
439+
424440
@Nullable
425441
private String getProperty(String key) {
426442
return getEnvironment().getProperty(key);

spring-vault-core/src/main/java/org/springframework/vault/support/SslConfiguration.java

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
import java.io.IOException;
1919
import java.io.InputStream;
2020
import java.security.KeyStore;
21+
import java.util.ArrayList;
2122
import java.util.Arrays;
23+
import java.util.Collections;
24+
import java.util.List;
2225

2326
import org.springframework.core.io.AbstractResource;
2427
import org.springframework.core.io.Resource;
@@ -60,6 +63,10 @@ public class SslConfiguration {
6063

6164
private final KeyConfiguration keyConfiguration;
6265

66+
private final List<String> enabledProtocols;
67+
68+
private final List<String> enabledCipherSuites;
69+
6370
/**
6471
* Create a new {@link SslConfiguration} with the default {@link KeyStore} type.
6572
* @param keyStore the key store resource, must not be {@literal null}.
@@ -96,14 +103,23 @@ public SslConfiguration(KeyStoreConfiguration keyStoreConfiguration,
96103
* Create a new {@link SslConfiguration}.
97104
* @param keyStoreConfiguration the key store configuration, must not be
98105
* {@literal null}.
99-
* @param keyConfiguration the configuration for a specific key in
100-
* {@code keyStoreConfiguration} to use.
101106
* @param trustStoreConfiguration the trust store configuration, must not be
102107
* {@literal null}.
103-
* @since 2.2
108+
* @param enabledProtocols the enabled SSL protocols, elements must match protocol
109+
* version strings used by the enabled Java SSL provider. May be {@literal null} to
110+
* indicate the SSL socket factory should use a default list of enabled protocol
111+
* versions.
112+
* @param enabledCipherSuites the enabled SSL cipher suites, elements must match
113+
* cipher suite strings used by the enabled Java SSL provider. May be {@literal null}
114+
* to indicate the SSL socket factory should use a default list of enabled cipher
115+
* suites.
116+
* @since 2.4
117+
* @see sun.security.ssl.ProtocolVersion
118+
* @see sun.security.ssl.CipherSuite
104119
*/
105120
public SslConfiguration(KeyStoreConfiguration keyStoreConfiguration, KeyConfiguration keyConfiguration,
106-
KeyStoreConfiguration trustStoreConfiguration) {
121+
KeyStoreConfiguration trustStoreConfiguration, List<String> enabledProtocols,
122+
List<String> enabledCipherSuites) {
107123

108124
Assert.notNull(keyStoreConfiguration, "KeyStore configuration must not be null");
109125
Assert.notNull(keyConfiguration, "KeyConfiguration must not be null");
@@ -112,6 +128,50 @@ public SslConfiguration(KeyStoreConfiguration keyStoreConfiguration, KeyConfigur
112128
this.keyStoreConfiguration = keyStoreConfiguration;
113129
this.keyConfiguration = keyConfiguration;
114130
this.trustStoreConfiguration = trustStoreConfiguration;
131+
this.enabledProtocols = enabledProtocols != null
132+
? Collections.unmodifiableList(new ArrayList<>(enabledProtocols)) : null;
133+
this.enabledCipherSuites = enabledCipherSuites != null
134+
? Collections.unmodifiableList(new ArrayList<>(enabledCipherSuites)) : null;
135+
}
136+
137+
/**
138+
* Create a new {@link SslConfiguration}.
139+
* @param keyStoreConfiguration the key store configuration, must not be
140+
* {@literal null}.
141+
* @param keyConfiguration the configuration for a specific key in
142+
* {@code keyStoreConfiguration} to use.
143+
* @param trustStoreConfiguration the trust store configuration, must not be
144+
* {@literal null}.
145+
* @since 2.2
146+
*/
147+
public SslConfiguration(KeyStoreConfiguration keyStoreConfiguration, KeyConfiguration keyConfiguration,
148+
KeyStoreConfiguration trustStoreConfiguration) {
149+
this(keyStoreConfiguration, keyConfiguration, trustStoreConfiguration, null, null);
150+
}
151+
152+
/**
153+
* Create a new {@link SslConfiguration}.
154+
* @param keyStoreConfiguration the key store configuration, must not be
155+
* {@literal null}.
156+
* @param trustStoreConfiguration the trust store configuration, must not be
157+
* {@literal null}.
158+
* @param enabledProtocols the enabled SSL protocols, elements must match protocol
159+
* version strings used by the enabled Java SSL provider. May be {@literal null} to
160+
* indicate the SSL socket factory should use a default list of enabled protocol
161+
* versions.
162+
* @param enabledCipherSuites the enabled SSL cipher suites, elements must match
163+
* cipher suite strings used by the enabled Java SSL provider. May be {@literal null}
164+
* to indicate the SSL socket factory should use a default list of enabled cipher
165+
* suites.
166+
* @since 2.4
167+
* @see sun.security.ssl.ProtocolVersion
168+
* @see sun.security.ssl.CipherSuite
169+
*/
170+
public SslConfiguration(KeyStoreConfiguration keyStoreConfiguration, KeyStoreConfiguration trustStoreConfiguration,
171+
List<String> enabledProtocols, List<String> enabledCipherSuites) {
172+
173+
this(keyStoreConfiguration, KeyConfiguration.unconfigured(), trustStoreConfiguration, enabledProtocols,
174+
enabledCipherSuites);
115175
}
116176

117177
/**
@@ -299,6 +359,54 @@ public static SslConfiguration unconfigured() {
299359
return new SslConfiguration(KeyStoreConfiguration.unconfigured(), KeyStoreConfiguration.unconfigured());
300360
}
301361

362+
/**
363+
* The list of SSL protocol versions that must be enabled. A value of {@literal null}
364+
* indicates that the SSL socket factory should use a default list of enabled protocol
365+
* versions.
366+
* @return the list of enabled SSL protocol versions.
367+
* @since 2.4
368+
*/
369+
public List<String> getEnabledProtocols() {
370+
return this.enabledProtocols;
371+
}
372+
373+
/**
374+
* Create a new {@link SslConfiguration} with the enabled protocol versions applied
375+
* retaining the other configuration from this instance.
376+
* @param enabledProtocols may be {@literal null}.
377+
* @return a new {@link SslConfiguration} with the enabled protocol versions applied.
378+
* @since 2.4
379+
* @see sun.security.ssl.ProtocolVersion
380+
*/
381+
public SslConfiguration withEnabledProtocols(List<String> enabledProtocols) {
382+
return new SslConfiguration(this.keyStoreConfiguration, this.keyConfiguration, this.trustStoreConfiguration,
383+
enabledProtocols, this.enabledCipherSuites);
384+
}
385+
386+
/**
387+
* The list of SSL cipher suites that must be enabled. A value of {@literal null}
388+
* indicates that the SSL socket factory should use a default list of enabled cipher
389+
* suites.
390+
* @return the list of enabled SSL cipher suites.
391+
* @since 2.4
392+
*/
393+
public List<String> getEnabledCipherSuites() {
394+
return this.enabledCipherSuites;
395+
}
396+
397+
/**
398+
* Create a new {@link SslConfiguration} with the enabled cipher suites applied
399+
* retaining the other configuration from this instance.
400+
* @param enabledCipherSuites may be {@literal null}.
401+
* @return a new {@link SslConfiguration} with the enabled cipher suites applied.
402+
* @since 2.4
403+
* @see sun.security.ssl.CipherSuite
404+
*/
405+
public SslConfiguration withEnabledCipherSuites(List<String> enabledCipherSuites) {
406+
return new SslConfiguration(this.keyStoreConfiguration, this.keyConfiguration, this.trustStoreConfiguration,
407+
this.enabledProtocols, enabledCipherSuites);
408+
}
409+
302410
/**
303411
* @return the {@link java.security.KeyStore key store} resource or {@literal null} if
304412
* not configured.

0 commit comments

Comments
 (0)