Enable skipping ssl validation for vault (#989)
This commit is contained in:
committed by
Spencer Gibb
parent
bb4d6b08a4
commit
0fd0c7b801
@@ -15,10 +15,19 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.config;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
|
||||
@@ -59,7 +68,9 @@ import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -101,6 +112,75 @@ public class EnvironmentRepositoryConfiguration {
|
||||
return new EnvironmentWatch.Default();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(TransportConfigCallback.class)
|
||||
static class JGitFactoryConfig {
|
||||
@Bean
|
||||
public MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory(
|
||||
ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, customTransportConfigCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(SVNException.class)
|
||||
static class SvnFactoryConfig {
|
||||
@Bean
|
||||
public SvnEnvironmentRepositoryFactory svnEnvironmentRepositoryFactory(ConfigurableEnvironment environment,
|
||||
ConfigServerProperties server) {
|
||||
return new SvnEnvironmentRepositoryFactory(environment, server);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class VaultFactoryConfig {
|
||||
@Bean
|
||||
public VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory(
|
||||
ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
Optional<RestTemplate> skipSslValidationRestTemplate) {
|
||||
return new VaultEnvironmentRepositoryFactory(request, watch, skipSslValidationRestTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(JdbcTemplate.class)
|
||||
static class JdbcCompositeConfig {
|
||||
@Bean
|
||||
@ConditionalOnBean(JdbcTemplate.class)
|
||||
public JdbcEnvironmentRepositoryFactory jdbcEnvironmentRepositoryFactory(JdbcTemplate jdbc) {
|
||||
return new JdbcEnvironmentRepositoryFactory(jdbc);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class NativeFactoryConfig {
|
||||
@Bean
|
||||
public NativeEnvironmentRepositoryFactory nativeEnvironmentRepositoryFactory(ConfigurableEnvironment environment,
|
||||
ConfigServerProperties properties) {
|
||||
return new NativeEnvironmentRepositoryFactory(environment, properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(HttpClient.class)
|
||||
public RestTemplate skipSslValidationRestTemplate() {
|
||||
try {
|
||||
SSLContext sslContext = new SSLContextBuilder()
|
||||
.loadTrustMaterial(null, (certificate, authType) -> true)
|
||||
.build();
|
||||
CloseableHttpClient httpClient = HttpClients.custom()
|
||||
.setSSLContext(sslContext)
|
||||
.setSSLHostnameVerifier(new NoopHostnameVerifier())
|
||||
.build();
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
requestFactory.setHttpClient(httpClient);
|
||||
return new RestTemplate(requestFactory);
|
||||
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -117,10 +197,8 @@ class DefaultRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository(
|
||||
MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,
|
||||
MultipleJGitEnvironmentProperties environmentProperties) {
|
||||
MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory =
|
||||
new MultipleJGitEnvironmentRepositoryFactory(environment, server,
|
||||
Optional.ofNullable(customTransportConfigCallback));
|
||||
return gitEnvironmentRepositoryFactory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
@@ -129,19 +207,11 @@ class DefaultRepositoryConfiguration {
|
||||
@ConditionalOnMissingBean(EnvironmentRepository.class)
|
||||
@Profile("native")
|
||||
class NativeRepositoryConfiguration {
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Autowired
|
||||
private ConfigServerProperties configServerProperties;
|
||||
|
||||
@Bean
|
||||
public NativeEnvironmentRepository nativeEnvironmentRepository(
|
||||
public NativeEnvironmentRepository nativeEnvironmentRepository(NativeEnvironmentRepositoryFactory factory,
|
||||
NativeEnvironmentProperties environmentProperties) {
|
||||
NativeEnvironmentRepository repository = new NativeEnvironmentRepository(this.environment,
|
||||
environmentProperties);
|
||||
repository.setDefaultLabel(configServerProperties.getDefaultLabel());
|
||||
return repository;
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,25 +223,22 @@ class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {
|
||||
@Configuration
|
||||
@Profile("subversion")
|
||||
class SvnRepositoryConfiguration {
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Autowired
|
||||
private ConfigServerProperties server;
|
||||
|
||||
@Bean
|
||||
public SvnKitEnvironmentRepository svnKitEnvironmentRepository(SvnKitEnvironmentProperties environmentProperties) {
|
||||
return new SvnEnvironmentRepositoryFactory(environment, server).build(environmentProperties);
|
||||
public SvnKitEnvironmentRepository svnKitEnvironmentRepository(SvnKitEnvironmentProperties environmentProperties,
|
||||
SvnEnvironmentRepositoryFactory factory) {
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Profile("vault")
|
||||
class VaultRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public VaultEnvironmentRepository vaultEnvironmentRepository(ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
VaultEnvironmentProperties environmentProperties) {
|
||||
return new VaultEnvironmentRepositoryFactory(request, watch).build(environmentProperties);
|
||||
public VaultEnvironmentRepository vaultEnvironmentRepository(VaultEnvironmentRepositoryFactory factory,
|
||||
VaultEnvironmentProperties environmentProperties) {
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,9 +249,9 @@ class JdbcRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(JdbcTemplate.class)
|
||||
public JdbcEnvironmentRepository jdbcEnvironmentRepository(JdbcTemplate jdbc,
|
||||
public JdbcEnvironmentRepository jdbcEnvironmentRepository(JdbcEnvironmentRepositoryFactory factory,
|
||||
JdbcEnvironmentProperties environmentProperties) {
|
||||
return new JdbcEnvironmentRepositoryFactory(jdbc).build(environmentProperties);
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,47 +259,6 @@ class JdbcRepositoryConfiguration {
|
||||
@Profile("composite")
|
||||
class CompositeRepositoryConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(TransportConfigCallback.class)
|
||||
static class JGitCompositeConfig {
|
||||
@Bean
|
||||
public MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory(
|
||||
ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, customTransportConfigCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(SVNException.class)
|
||||
static class SvnCompositeConfig {
|
||||
@Bean
|
||||
public SvnEnvironmentRepositoryFactory svnEnvironmentRepositoryFactory(ConfigurableEnvironment environment,
|
||||
ConfigServerProperties server) {
|
||||
return new SvnEnvironmentRepositoryFactory(environment, server);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory(ObjectProvider<HttpServletRequest> request,
|
||||
EnvironmentWatch watch) {
|
||||
return new VaultEnvironmentRepositoryFactory(request, watch);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(JdbcTemplate.class)
|
||||
static class JdbcCompositeConfig {
|
||||
@Bean
|
||||
public JdbcEnvironmentRepositoryFactory jdbcEnvironmentRepositoryFactory(JdbcTemplate jdbc) {
|
||||
return new JdbcEnvironmentRepositoryFactory(jdbc);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NativeEnvironmentRepositoryFactory nativeEnvironmentRepositoryFactory(ConfigurableEnvironment environment) {
|
||||
return new NativeEnvironmentRepositoryFactory(environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static CompositeEnvironmentBeanFactoryPostProcessor compositeEnvironmentRepositoryBeanFactoryPostProcessor(
|
||||
Environment environment) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import org.springframework.cloud.config.server.config.ConfigServerProperties;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
@@ -23,13 +24,17 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
public class NativeEnvironmentRepositoryFactory implements EnvironmentRepositoryFactory<NativeEnvironmentRepository,
|
||||
NativeEnvironmentProperties> {
|
||||
private ConfigurableEnvironment environment;
|
||||
private ConfigServerProperties properties;
|
||||
|
||||
public NativeEnvironmentRepositoryFactory(ConfigurableEnvironment environment) {
|
||||
public NativeEnvironmentRepositoryFactory(ConfigurableEnvironment environment, ConfigServerProperties properties) {
|
||||
this.environment = environment;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NativeEnvironmentRepository build(NativeEnvironmentProperties environmentProperties) {
|
||||
return new NativeEnvironmentRepository(environment, environmentProperties);
|
||||
NativeEnvironmentRepository repository = new NativeEnvironmentRepository(environment, environmentProperties);
|
||||
repository.setDefaultLabel(properties.getDefaultLabel());
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,11 @@ public class VaultEnvironmentProperties implements EnvironmentRepositoryProperti
|
||||
private String defaultKey = "application";
|
||||
/** Vault profile separator. Defaults to comma. */
|
||||
private String profileSeparator = ",";
|
||||
/**
|
||||
* Flag to indicate that SSL certificate validation should be bypassed when communicating with a repository served
|
||||
* over an HTTPS connection.
|
||||
*/
|
||||
private boolean skipSslValidation = false;
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
public String getHost() {
|
||||
@@ -86,6 +91,14 @@ public class VaultEnvironmentProperties implements EnvironmentRepositoryProperti
|
||||
this.profileSeparator = profileSeparator;
|
||||
}
|
||||
|
||||
public boolean isSkipSslValidation() {
|
||||
return skipSslValidation;
|
||||
}
|
||||
|
||||
public void setSkipSslValidation(boolean skipSslValidation) {
|
||||
this.skipSslValidation = skipSslValidation;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
@@ -27,16 +28,21 @@ public class VaultEnvironmentRepositoryFactory implements EnvironmentRepositoryF
|
||||
VaultEnvironmentProperties> {
|
||||
private ObjectProvider<HttpServletRequest> request;
|
||||
private EnvironmentWatch watch;
|
||||
private Optional<RestTemplate> skipSslValidationRestTemplate;
|
||||
|
||||
public VaultEnvironmentRepositoryFactory(ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch) {
|
||||
public VaultEnvironmentRepositoryFactory(ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
Optional<RestTemplate> skipSslValidationRestTemplate) {
|
||||
this.request = request;
|
||||
this.watch = watch;
|
||||
this.skipSslValidationRestTemplate = skipSslValidationRestTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultEnvironmentRepository build(VaultEnvironmentProperties environmentProperties) {
|
||||
VaultEnvironmentRepository repository = new VaultEnvironmentRepository(request, watch, new RestTemplate(),
|
||||
environmentProperties);
|
||||
return repository;
|
||||
if (environmentProperties.isSkipSslValidation() && skipSslValidationRestTemplate.isPresent()) {
|
||||
return new VaultEnvironmentRepository(request, watch, skipSslValidationRestTemplate.get(),
|
||||
environmentProperties);
|
||||
}
|
||||
return new VaultEnvironmentRepository(request, watch, new RestTemplate(), environmentProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Optional;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* author Dylan Roberts
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = VaultEnvironmentRepositoryIntegrationTests.TestApplication.class,
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {
|
||||
"server.ssl.key-store=classpath:ssl-test.jks",
|
||||
"server.ssl.key-store-password=password",
|
||||
"server.ssl.key-password=password",
|
||||
"server.key-alias=ssl-test"})
|
||||
public class VaultEnvironmentRepositoryIntegrationTests {
|
||||
|
||||
@LocalServerPort
|
||||
private String localServerPort;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void withSslValidation() {
|
||||
VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory =
|
||||
new VaultEnvironmentRepositoryFactory(withRequest(), new EnvironmentWatch.Default(),
|
||||
Optional.of(skipSslValidationRestTemplate()));
|
||||
VaultEnvironmentRepository vaultEnvironmentRepository =
|
||||
vaultEnvironmentRepositoryFactory.build(withEnvironmentProperties(false));
|
||||
expectedException.expectCause(instanceOf(SSLHandshakeException.class));
|
||||
|
||||
vaultEnvironmentRepository.findOne("application", "profile", "label");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipSslValidation() {
|
||||
VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory =
|
||||
new VaultEnvironmentRepositoryFactory(withRequest(), new EnvironmentWatch.Default(),
|
||||
Optional.of(skipSslValidationRestTemplate()));
|
||||
VaultEnvironmentRepository vaultEnvironmentRepository =
|
||||
vaultEnvironmentRepositoryFactory.build(withEnvironmentProperties(true));
|
||||
|
||||
Environment actual = vaultEnvironmentRepository.findOne("application", "profile", "label");
|
||||
|
||||
assertThat(actual).isNotNull();
|
||||
}
|
||||
|
||||
private RestTemplate skipSslValidationRestTemplate() {
|
||||
try {
|
||||
SSLContext sslContext = new SSLContextBuilder()
|
||||
.loadTrustMaterial(null, (certificate, authType) -> true)
|
||||
.build();
|
||||
CloseableHttpClient httpClient = HttpClients.custom()
|
||||
.setSSLContext(sslContext)
|
||||
.setSSLHostnameVerifier(new NoopHostnameVerifier())
|
||||
.build();
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
requestFactory.setHttpClient(httpClient);
|
||||
return new RestTemplate(requestFactory);
|
||||
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private VaultEnvironmentProperties withEnvironmentProperties(boolean skipSslValidation) {
|
||||
VaultEnvironmentProperties environmentProperties = new VaultEnvironmentProperties();
|
||||
environmentProperties.setPort(Integer.decode(localServerPort));
|
||||
environmentProperties.setScheme("https");
|
||||
environmentProperties.setSkipSslValidation(skipSslValidation);
|
||||
return environmentProperties;
|
||||
}
|
||||
|
||||
private ObjectProvider<HttpServletRequest> withRequest() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getHeader("X-Config-Token")).thenReturn("configToken");
|
||||
ObjectProvider<HttpServletRequest> requestProvider = mock(ObjectProvider.class);
|
||||
when(requestProvider.getIfAvailable()).thenReturn(request);
|
||||
return requestProvider;
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
public static class TestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
spring-cloud-config-server/src/test/resources/ssl-test.jks
Normal file
BIN
spring-cloud-config-server/src/test/resources/ssl-test.jks
Normal file
Binary file not shown.
Reference in New Issue
Block a user