committed by
Ryan Baxter
parent
ab35034b98
commit
8e8f8c3ab4
@@ -48,6 +48,11 @@
|
||||
<artifactId>org.eclipse.jgit.junit.http</artifactId>
|
||||
<version>${jgit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit.http.apache</artifactId>
|
||||
<version>${jgit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch</artifactId>
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit.http.apache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
|
||||
@@ -15,20 +15,12 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -47,6 +39,9 @@ import org.springframework.cloud.config.server.environment.CompositeEnvironmentR
|
||||
import org.springframework.cloud.config.server.environment.ConsulEnvironmentWatch;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
|
||||
import org.springframework.cloud.config.server.environment.HttpClientConfigurableHttpConnectionFactory;
|
||||
import org.springframework.cloud.config.server.environment.HttpClientVaultRestTemplateFactory;
|
||||
import org.springframework.cloud.config.server.environment.ConfigurableHttpConnectionFactory;
|
||||
import org.springframework.cloud.config.server.environment.JdbcEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.environment.JdbcEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.JdbcEnvironmentRepositoryFactory;
|
||||
@@ -70,9 +65,7 @@ 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
|
||||
@@ -124,11 +117,24 @@ public class EnvironmentRepositoryConfiguration {
|
||||
@Configuration
|
||||
@ConditionalOnClass(TransportConfigCallback.class)
|
||||
static class JGitFactoryConfig {
|
||||
|
||||
@Bean
|
||||
public MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory(
|
||||
ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<ConfigurableHttpConnectionFactory> jgitHttpConnectionFactory,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, customTransportConfigCallback);
|
||||
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, jgitHttpConnectionFactory,
|
||||
customTransportConfigCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ HttpClient.class, TransportConfigCallback.class })
|
||||
static class JGitHttpClientConfig {
|
||||
|
||||
@Bean
|
||||
public ConfigurableHttpConnectionFactory httpClientConnectionFactory() {
|
||||
return new HttpClientConfigurableHttpConnectionFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,17 +150,28 @@ public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
@Configuration
|
||||
static class VaultFactoryConfig {
|
||||
|
||||
@Bean
|
||||
public VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory(
|
||||
ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
Optional<RestTemplate> skipSslValidationRestTemplate) {
|
||||
return new VaultEnvironmentRepositoryFactory(request, watch, skipSslValidationRestTemplate);
|
||||
Optional<VaultEnvironmentRepositoryFactory.VaultRestTemplateFactory> vaultRestTemplateFactory) {
|
||||
return new VaultEnvironmentRepositoryFactory(request, watch, vaultRestTemplateFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(HttpClient.class)
|
||||
static class VaultHttpClientConfig {
|
||||
|
||||
@Bean
|
||||
public VaultEnvironmentRepositoryFactory.VaultRestTemplateFactory vaultRestTemplateFactory() {
|
||||
return new HttpClientVaultRestTemplateFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(JdbcTemplate.class)
|
||||
static class JdbcCompositeConfig {
|
||||
static class JdbcFactoryConfig {
|
||||
@Bean
|
||||
@ConditionalOnBean(JdbcTemplate.class)
|
||||
public JdbcEnvironmentRepositoryFactory jdbcEnvironmentRepositoryFactory(JdbcTemplate jdbc) {
|
||||
@@ -171,24 +188,6 @@ public class EnvironmentRepositoryConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
@@ -206,7 +205,7 @@ class DefaultRepositoryConfiguration {
|
||||
@Bean
|
||||
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository(
|
||||
MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,
|
||||
MultipleJGitEnvironmentProperties environmentProperties) {
|
||||
MultipleJGitEnvironmentProperties environmentProperties) throws Exception {
|
||||
return gitEnvironmentRepositoryFactory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
@@ -245,7 +244,8 @@ class VaultRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public VaultEnvironmentRepository vaultEnvironmentRepository(VaultEnvironmentRepositoryFactory factory,
|
||||
VaultEnvironmentProperties environmentProperties) {
|
||||
VaultEnvironmentProperties environmentProperties)
|
||||
throws Exception {
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 org.eclipse.jgit.transport.http.HttpConnectionFactory;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public interface ConfigurableHttpConnectionFactory extends HttpConnectionFactory {
|
||||
void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.eclipse.jgit.transport.http.HttpConnection;
|
||||
import org.eclipse.jgit.transport.http.apache.HttpClientConnection;
|
||||
|
||||
import org.springframework.cloud.config.server.support.HttpClientSupport;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class HttpClientConfigurableHttpConnectionFactory implements ConfigurableHttpConnectionFactory {
|
||||
|
||||
private Map<String, HttpClientBuilder> httpClientsByUri = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void addConfiguration(MultipleJGitEnvironmentProperties environmentProperties)
|
||||
throws GeneralSecurityException {
|
||||
addHttpClient(environmentProperties);
|
||||
for (JGitEnvironmentProperties repo : environmentProperties.getRepos().values()) {
|
||||
addHttpClient(repo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpConnection create(URL url) throws IOException {
|
||||
return create(url, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpConnection create(URL url, Proxy proxy) throws IOException {
|
||||
return new HttpClientConnection(url.toString(), proxy, lookupHttpClientBuilder(url).build());
|
||||
}
|
||||
|
||||
private void addHttpClient(JGitEnvironmentProperties properties) throws GeneralSecurityException {
|
||||
if (properties.getUri().startsWith("http")) {
|
||||
httpClientsByUri.put(properties.getUri(), HttpClientSupport.builder(properties));
|
||||
}
|
||||
}
|
||||
|
||||
private HttpClientBuilder lookupHttpClientBuilder(URL url) throws MalformedURLException {
|
||||
String spec = url.toString();
|
||||
HttpClientBuilder builder = httpClientsByUri.get(spec);
|
||||
while (builder == null) {
|
||||
spec = spec.substring(0, spec.lastIndexOf(File.separator));
|
||||
builder = httpClientsByUri.get(spec);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.GeneralSecurityException;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import org.springframework.cloud.config.server.support.HttpClientSupport;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class HttpClientVaultRestTemplateFactory implements VaultEnvironmentRepositoryFactory.VaultRestTemplateFactory {
|
||||
|
||||
@Override
|
||||
public RestTemplate build(VaultEnvironmentProperties environmentProperties) throws GeneralSecurityException {
|
||||
HttpClient httpClient = HttpClientSupport.builder(environmentProperties).build();
|
||||
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,20 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
|
||||
import org.springframework.cloud.config.server.support.AbstractScmAccessorProperties;
|
||||
import org.springframework.cloud.config.server.support.HttpEnvironmentRepositoryProperties;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
* @author Gareth Clay
|
||||
*/
|
||||
public class JGitEnvironmentProperties extends AbstractScmAccessorProperties {
|
||||
public class JGitEnvironmentProperties extends AbstractScmAccessorProperties
|
||||
implements HttpEnvironmentRepositoryProperties {
|
||||
private static final String DEFAULT_LABEL = "master";
|
||||
|
||||
/** Flag to indicate that the repository should be cloned on startup (not on demand). Generally leads to slower startup but faster first query. */
|
||||
@@ -85,6 +90,11 @@ public class JGitEnvironmentProperties extends AbstractScmAccessorProperties {
|
||||
*/
|
||||
private boolean strictHostKeyChecking = true;
|
||||
|
||||
/**
|
||||
* HTTP proxy configuration.
|
||||
*/
|
||||
private Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxy = new HashMap<>();
|
||||
|
||||
public JGitEnvironmentProperties() {
|
||||
super();
|
||||
setDefaultLabel(DEFAULT_LABEL);
|
||||
@@ -188,6 +198,7 @@ public class JGitEnvironmentProperties extends AbstractScmAccessorProperties {
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipSslValidation() {
|
||||
return skipSslValidation;
|
||||
}
|
||||
@@ -195,4 +206,13 @@ public class JGitEnvironmentProperties extends AbstractScmAccessorProperties {
|
||||
public void setSkipSslValidation(boolean skipSslValidation) {
|
||||
this.skipSslValidation = skipSslValidation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public void setProxy(Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxy) {
|
||||
this.proxy = proxy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cloud.config.server.environment;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.eclipse.jgit.transport.HttpTransport;
|
||||
|
||||
import org.springframework.cloud.config.server.config.ConfigServerProperties;
|
||||
import org.springframework.cloud.config.server.ssh.FileBasedSshTransportConfigCallback;
|
||||
@@ -31,17 +32,33 @@ public class MultipleJGitEnvironmentRepositoryFactory implements EnvironmentRepo
|
||||
MultipleJGitEnvironmentProperties> {
|
||||
private ConfigurableEnvironment environment;
|
||||
private ConfigServerProperties server;
|
||||
private Optional<ConfigurableHttpConnectionFactory> connectionFactory;
|
||||
private Optional<TransportConfigCallback> customTransportConfigCallback;
|
||||
|
||||
public MultipleJGitEnvironmentRepositoryFactory(ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
@Deprecated
|
||||
public MultipleJGitEnvironmentRepositoryFactory(ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
this(environment, server, Optional.empty(), customTransportConfigCallback);
|
||||
}
|
||||
|
||||
public MultipleJGitEnvironmentRepositoryFactory(
|
||||
ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<ConfigurableHttpConnectionFactory> connectionFactory,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
this.environment = environment;
|
||||
this.server = server;
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.customTransportConfigCallback = customTransportConfigCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultipleJGitEnvironmentRepository build(MultipleJGitEnvironmentProperties environmentProperties) {
|
||||
public MultipleJGitEnvironmentRepository build(MultipleJGitEnvironmentProperties environmentProperties)
|
||||
throws Exception {
|
||||
if (connectionFactory.isPresent()) {
|
||||
HttpTransport.setConnectionFactory(connectionFactory.get());
|
||||
connectionFactory.get().addConfiguration(environmentProperties);
|
||||
}
|
||||
|
||||
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(environment,
|
||||
environmentProperties);
|
||||
repository.setTransportConfigCallback(customTransportConfigCallback
|
||||
@@ -52,10 +69,11 @@ public class MultipleJGitEnvironmentRepositoryFactory implements EnvironmentRepo
|
||||
return repository;
|
||||
}
|
||||
|
||||
private TransportConfigCallback buildTransportConfigCallback(final MultipleJGitEnvironmentProperties gitEnvironmentProperties) {
|
||||
private TransportConfigCallback buildTransportConfigCallback(MultipleJGitEnvironmentProperties gitEnvironmentProperties) {
|
||||
if (gitEnvironmentProperties.isIgnoreLocalSshSettings()) {
|
||||
return new PropertiesBasedSshTransportConfigCallback(gitEnvironmentProperties);
|
||||
}
|
||||
return new FileBasedSshTransportConfigCallback(gitEnvironmentProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,15 +15,19 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.config.server.support.EnvironmentRepositoryProperties;
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
|
||||
import org.springframework.cloud.config.server.support.HttpEnvironmentRepositoryProperties;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.vault")
|
||||
public class VaultEnvironmentProperties implements EnvironmentRepositoryProperties {
|
||||
public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProperties {
|
||||
/** Vault host. Defaults to 127.0.0.1. */
|
||||
private String host = "127.0.0.1";
|
||||
/** Vault port. Defaults to 8200. */
|
||||
@@ -41,6 +45,12 @@ public class VaultEnvironmentProperties implements EnvironmentRepositoryProperti
|
||||
* over an HTTPS connection.
|
||||
*/
|
||||
private boolean skipSslValidation = false;
|
||||
|
||||
/**
|
||||
* HTTP proxy configuration.
|
||||
*/
|
||||
private Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxy = new HashMap<>();
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
public String getHost() {
|
||||
@@ -91,6 +101,7 @@ public class VaultEnvironmentProperties implements EnvironmentRepositoryProperti
|
||||
this.profileSeparator = profileSeparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipSslValidation() {
|
||||
return skipSslValidation;
|
||||
}
|
||||
@@ -99,6 +110,15 @@ public class VaultEnvironmentProperties implements EnvironmentRepositoryProperti
|
||||
this.skipSslValidation = skipSslValidation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public void setProxy(Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxy) {
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -28,21 +28,26 @@ public class VaultEnvironmentRepositoryFactory implements EnvironmentRepositoryF
|
||||
VaultEnvironmentProperties> {
|
||||
private ObjectProvider<HttpServletRequest> request;
|
||||
private EnvironmentWatch watch;
|
||||
private Optional<RestTemplate> skipSslValidationRestTemplate;
|
||||
private Optional<VaultRestTemplateFactory> vaultRestTemplateFactory;
|
||||
|
||||
public VaultEnvironmentRepositoryFactory(ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
|
||||
Optional<RestTemplate> skipSslValidationRestTemplate) {
|
||||
Optional<VaultRestTemplateFactory> vaultRestTemplateFactory) {
|
||||
this.request = request;
|
||||
this.watch = watch;
|
||||
this.skipSslValidationRestTemplate = skipSslValidationRestTemplate;
|
||||
this.vaultRestTemplateFactory = vaultRestTemplateFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultEnvironmentRepository build(VaultEnvironmentProperties environmentProperties) {
|
||||
if (environmentProperties.isSkipSslValidation() && skipSslValidationRestTemplate.isPresent()) {
|
||||
return new VaultEnvironmentRepository(request, watch, skipSslValidationRestTemplate.get(),
|
||||
environmentProperties);
|
||||
public VaultEnvironmentRepository build(VaultEnvironmentProperties environmentProperties) throws Exception {
|
||||
if (vaultRestTemplateFactory.isPresent()) {
|
||||
RestTemplate restTemplate = vaultRestTemplateFactory.get().build(environmentProperties);
|
||||
return new VaultEnvironmentRepository(request, watch, restTemplate, environmentProperties);
|
||||
}
|
||||
return new VaultEnvironmentRepository(request, watch, new RestTemplate(), environmentProperties);
|
||||
}
|
||||
|
||||
public interface VaultRestTemplateFactory {
|
||||
|
||||
RestTemplate build(VaultEnvironmentProperties environmentProperties) throws Exception;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.proxy;
|
||||
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class ProxyHostCredentialsProvider extends BasicCredentialsProvider {
|
||||
|
||||
public ProxyHostCredentialsProvider(ProxyHostProperties... proxyHostProperties) {
|
||||
|
||||
for (ProxyHostProperties proxy : proxyHostProperties) {
|
||||
|
||||
if (proxy != null && proxy.getUsername() != null && proxy.getPassword() != null) {
|
||||
AuthScope authscope = new AuthScope(proxy.getHost(), proxy.getPort());
|
||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(proxy.getUsername(),
|
||||
proxy.getPassword());
|
||||
setCredentials(authscope, credentials);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.proxy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
public class ProxyHostProperties {
|
||||
private String host;
|
||||
private int port;
|
||||
private String nonProxyHosts;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getNonProxyHosts() {
|
||||
return nonProxyHosts;
|
||||
}
|
||||
|
||||
public void setNonProxyHosts(String nonProxyHosts) {
|
||||
this.nonProxyHosts = nonProxyHosts;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public enum ProxyForScheme {
|
||||
HTTP,
|
||||
HTTPS;
|
||||
|
||||
@JsonCreator
|
||||
public static ProxyForScheme forLowerCaseName(String lowerCaseName) {
|
||||
return ProxyForScheme.valueOf(lowerCaseName.toUpperCase());
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
public String lowercaseName() {
|
||||
return this.name().toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.proxy;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.impl.conn.DefaultRoutePlanner;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class SchemeBasedRoutePlanner extends DefaultRoutePlanner {
|
||||
|
||||
private final ProxyHostProperties httpsProxy;
|
||||
private final ProxyHostProperties httpProxy;
|
||||
|
||||
public SchemeBasedRoutePlanner(ProxyHostProperties httpsProxy, ProxyHostProperties httpProxy) {
|
||||
super(null);
|
||||
this.httpsProxy = httpsProxy;
|
||||
this.httpProxy = httpProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) {
|
||||
return "https".equals(target.getSchemeName()) ?
|
||||
determineProxy(httpsProxy) :
|
||||
determineProxy(httpProxy);
|
||||
}
|
||||
|
||||
private HttpHost determineProxy(ProxyHostProperties properties) {
|
||||
if (properties == null) {
|
||||
return null;
|
||||
}
|
||||
return new HttpHost(properties.getHost(), properties.getPort());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostCredentialsProvider;
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
|
||||
import org.springframework.cloud.config.server.proxy.SchemeBasedRoutePlanner;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class HttpClientSupport {
|
||||
|
||||
public static HttpClientBuilder builder(HttpEnvironmentRepositoryProperties environmentProperties)
|
||||
throws GeneralSecurityException {
|
||||
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom();
|
||||
|
||||
if (environmentProperties.isSkipSslValidation()) {
|
||||
sslContextBuilder.loadTrustMaterial(null, (certificate, authType) -> true);
|
||||
httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier());
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(environmentProperties.getProxy())) {
|
||||
ProxyHostProperties httpsProxy = environmentProperties.getProxy().get(ProxyHostProperties.ProxyForScheme.HTTPS);
|
||||
ProxyHostProperties httpProxy = environmentProperties.getProxy().get(ProxyHostProperties.ProxyForScheme.HTTP);
|
||||
|
||||
httpClientBuilder.setRoutePlanner(new SchemeBasedRoutePlanner(httpsProxy, httpProxy));
|
||||
httpClientBuilder.setDefaultCredentialsProvider(new ProxyHostCredentialsProvider(httpProxy, httpsProxy));
|
||||
}
|
||||
|
||||
return httpClientBuilder.setSSLContext(sslContextBuilder.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
|
||||
import org.springframework.cloud.config.server.support.EnvironmentRepositoryProperties;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public interface HttpEnvironmentRepositoryProperties extends EnvironmentRepositoryProperties {
|
||||
|
||||
Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> getProxy();
|
||||
|
||||
boolean isSkipSslValidation();
|
||||
}
|
||||
@@ -45,6 +45,26 @@ public class CompositeClasspathTests {
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions("httpclient-*.jar")
|
||||
public static class HttpClientTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
new WebApplicationContextRunner()
|
||||
.withUserConfiguration(ConfigServerApplication.class)
|
||||
.withPropertyValues("spring.profiles.active:test,composite",
|
||||
"spring.config.name:compositeconfigserver",
|
||||
"spring.cloud.config.server.composite[0].uri:file:./target/repos/config-repo",
|
||||
"spring.cloud.config.server.composite[0].type:git",
|
||||
"spring.cloud.config.server.composite[1].uri:file:///./target/repos/svn-config-repo",
|
||||
"spring.cloud.config.server.composite[1].type:svn")
|
||||
.run(context -> {
|
||||
CompositeUtils.getCompositeTypeList(context.getEnvironment());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions("svnkit-*.jar")
|
||||
public static class SvnTests {
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.cloud.config.server.environment.HttpClientVaultRestTemplateFactory;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class HttpClientVaultRestTemplateFactoryTest {
|
||||
private static final ProxyHostProperties AUTHENTICATED_HTTP_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
AUTHENTICATED_HTTP_PROXY.setHost("http://authenticated.http.proxy");
|
||||
AUTHENTICATED_HTTP_PROXY.setPort(8080);
|
||||
AUTHENTICATED_HTTP_PROXY.setUsername("username");
|
||||
AUTHENTICATED_HTTP_PROXY.setPassword("password");
|
||||
}
|
||||
private static final ProxyHostProperties AUTHENTICATED_HTTPS_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
AUTHENTICATED_HTTPS_PROXY.setHost("http://authenticated.https.proxy");
|
||||
AUTHENTICATED_HTTPS_PROXY.setPort(8081);
|
||||
AUTHENTICATED_HTTPS_PROXY.setUsername("username2");
|
||||
AUTHENTICATED_HTTPS_PROXY.setPassword("password2");
|
||||
}
|
||||
private static final ProxyHostProperties HTTP_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
HTTP_PROXY.setHost("http://http.proxy");
|
||||
HTTP_PROXY.setPort(8080);
|
||||
}
|
||||
private static final ProxyHostProperties HTTPS_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
HTTPS_PROXY.setHost("http://https.proxy");
|
||||
HTTPS_PROXY.setPort(8081);
|
||||
}
|
||||
|
||||
private HttpClientVaultRestTemplateFactory factory;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
factory = new HttpClientVaultRestTemplateFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedHttpsProxy() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(null, AUTHENTICATED_HTTPS_PROXY);
|
||||
RestTemplate restTemplate = factory.build(properties);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(AUTHENTICATED_HTTPS_PROXY.getHost()))));
|
||||
|
||||
restTemplate.getForObject("https://somehost", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsProxy() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(null, HTTPS_PROXY);
|
||||
RestTemplate restTemplate = factory.build(properties);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTPS_PROXY.getHost()))));
|
||||
|
||||
restTemplate.getForObject("https://somehost", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsProxy_notCalled() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(null, HTTPS_PROXY);
|
||||
RestTemplate restTemplate = factory.build(properties);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString("somehost"))));
|
||||
|
||||
restTemplate.getForObject("http://somehost", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedHttpProxy() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(AUTHENTICATED_HTTP_PROXY, null);
|
||||
RestTemplate restTemplate = factory.build(properties);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(AUTHENTICATED_HTTP_PROXY.getHost()))));
|
||||
|
||||
restTemplate.getForObject("http://somehost", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpProxy() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(HTTP_PROXY, null);
|
||||
RestTemplate restTemplate = factory.build(properties);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTP_PROXY.getHost()))));
|
||||
|
||||
restTemplate.getForObject("http://somehost", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpProxy_notCalled() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(HTTP_PROXY, null);
|
||||
RestTemplate restTemplate = factory.build(properties);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString("somehost"))));
|
||||
|
||||
restTemplate.getForObject("https://somehost", String.class);
|
||||
}
|
||||
|
||||
private VaultEnvironmentProperties getVaultEnvironmentProperties(ProxyHostProperties httpProxy, ProxyHostProperties httpsProxy) {
|
||||
Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxyMap = new HashMap<>();
|
||||
proxyMap.put(ProxyHostProperties.ProxyForScheme.HTTP, httpProxy);
|
||||
proxyMap.put(ProxyHostProperties.ProxyForScheme.HTTPS, httpsProxy);
|
||||
VaultEnvironmentProperties properties = new VaultEnvironmentProperties();
|
||||
properties.setProxy(proxyMap);
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.eclipse.jgit.transport.HttpTransport;
|
||||
import org.eclipse.jgit.transport.http.HttpConnection;
|
||||
import org.eclipse.jgit.transport.http.HttpConnectionFactory;
|
||||
import org.eclipse.jgit.transport.http.apache.HttpClientConnection;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.config.server.config.ConfigServerProperties;
|
||||
import org.springframework.cloud.config.server.config.EnvironmentRepositoryConfiguration;
|
||||
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* @author Dylan Roberts
|
||||
*/
|
||||
public class JGitEnvironmentRepositoryHttpProxyTests {
|
||||
private static final ProxyHostProperties AUTHENTICATED_HTTP_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
AUTHENTICATED_HTTP_PROXY.setHost("http://authenticated.http.proxy");
|
||||
AUTHENTICATED_HTTP_PROXY.setPort(8080);
|
||||
AUTHENTICATED_HTTP_PROXY.setUsername("username");
|
||||
AUTHENTICATED_HTTP_PROXY.setPassword("password");
|
||||
}
|
||||
private static final ProxyHostProperties AUTHENTICATED_HTTPS_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
AUTHENTICATED_HTTPS_PROXY.setHost("http://authenticated.https.proxy");
|
||||
AUTHENTICATED_HTTPS_PROXY.setPort(8081);
|
||||
AUTHENTICATED_HTTPS_PROXY.setUsername("username2");
|
||||
AUTHENTICATED_HTTPS_PROXY.setPassword("password2");
|
||||
}
|
||||
private static final ProxyHostProperties HTTP_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
HTTP_PROXY.setHost("http://http.proxy");
|
||||
HTTP_PROXY.setPort(8080);
|
||||
}
|
||||
private static final ProxyHostProperties HTTPS_PROXY = new ProxyHostProperties();
|
||||
static {
|
||||
HTTPS_PROXY.setHost("http://https.proxy");
|
||||
HTTPS_PROXY.setPort(8081);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void authenticatedHttpsProxy() throws Exception {
|
||||
String repoUrl = "https://myrepo/repo.git";
|
||||
new SpringApplicationBuilder(TestConfiguration.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.properties(gitProperties(repoUrl, null, AUTHENTICATED_HTTPS_PROXY))
|
||||
.run();
|
||||
HttpClient httpClient = getHttpClientForUrl(repoUrl);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(AUTHENTICATED_HTTPS_PROXY.getHost()))));
|
||||
|
||||
makeRequest(httpClient, "https://somehost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsProxy() throws Exception {
|
||||
String repoUrl = "https://myrepo/repo.git";
|
||||
new SpringApplicationBuilder(TestConfiguration.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.properties(gitProperties(repoUrl, null, HTTPS_PROXY))
|
||||
.run();
|
||||
HttpClient httpClient = getHttpClientForUrl(repoUrl);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTPS_PROXY.getHost()))));
|
||||
|
||||
makeRequest(httpClient, "https://somehost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsProxy_notCalled() throws Exception {
|
||||
String repoUrl = "https://myrepo/repo.git";
|
||||
new SpringApplicationBuilder(TestConfiguration.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.properties(gitProperties(repoUrl, null, HTTPS_PROXY))
|
||||
.run();
|
||||
HttpClient httpClient = getHttpClientForUrl(repoUrl);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString("somehost"))));
|
||||
|
||||
makeRequest(httpClient, "http://somehost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedHttpProxy() throws Exception {
|
||||
String repoUrl = "https://myrepo/repo.git";
|
||||
new SpringApplicationBuilder(TestConfiguration.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.properties(gitProperties(repoUrl, AUTHENTICATED_HTTP_PROXY, null))
|
||||
.run();
|
||||
HttpClient httpClient = getHttpClientForUrl(repoUrl);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(AUTHENTICATED_HTTP_PROXY.getHost()))));
|
||||
|
||||
makeRequest(httpClient, "http://somehost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpProxy() throws Exception {
|
||||
String repoUrl = "https://myrepo/repo.git";
|
||||
new SpringApplicationBuilder(TestConfiguration.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.properties(gitProperties(repoUrl, HTTP_PROXY, null))
|
||||
.run();
|
||||
HttpClient httpClient = getHttpClientForUrl(repoUrl);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTP_PROXY.getHost()))));
|
||||
|
||||
makeRequest(httpClient, "http://somehost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpProxy_notCalled() throws Exception {
|
||||
String repoUrl = "https://myrepo/repo.git";
|
||||
new SpringApplicationBuilder(TestConfiguration.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.properties(gitProperties(repoUrl, HTTP_PROXY, null))
|
||||
.run();
|
||||
HttpClient httpClient = getHttpClientForUrl(repoUrl);
|
||||
expectedException.expectCause(allOf(
|
||||
instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString("somehost"))));
|
||||
|
||||
makeRequest(httpClient, "https://somehost");
|
||||
}
|
||||
|
||||
private String[] gitProperties(String repoUrl, ProxyHostProperties httpProxy, ProxyHostProperties httpsProxy) {
|
||||
List<String> result = new ArrayList<>();
|
||||
result.add("spring.cloud.config.server.git.uri=" + repoUrl);
|
||||
if (httpProxy != null) {
|
||||
result.addAll(Arrays.asList(
|
||||
"spring.cloud.config.server.git.proxy.http.host=" + httpProxy.getHost(),
|
||||
"spring.cloud.config.server.git.proxy.http.port=" + httpProxy.getPort()
|
||||
));
|
||||
if (httpProxy.getUsername() != null && httpProxy.getPassword() != null) {
|
||||
result.addAll(Arrays.asList(
|
||||
"spring.cloud.config.server.git.proxy.http.username=" + httpProxy.getUsername(),
|
||||
"spring.cloud.config.server.git.proxy.http.password=" + httpProxy.getPassword()
|
||||
));
|
||||
}
|
||||
}
|
||||
if (httpsProxy != null) {
|
||||
result.addAll(Arrays.asList(
|
||||
"spring.cloud.config.server.git.proxy.https.host=" + httpsProxy.getHost(),
|
||||
"spring.cloud.config.server.git.proxy.https.port=" + httpsProxy.getPort()
|
||||
));
|
||||
if (httpsProxy.getUsername() != null && httpsProxy.getPassword() != null) {
|
||||
result.addAll(Arrays.asList(
|
||||
"spring.cloud.config.server.git.proxy.https.username=" + httpsProxy.getUsername(),
|
||||
"spring.cloud.config.server.git.proxy.https.password=" + httpsProxy.getPassword()
|
||||
));
|
||||
}
|
||||
}
|
||||
return result.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private void makeRequest(HttpClient httpClient, String url) {
|
||||
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
|
||||
restTemplate.getForObject(url, String.class);
|
||||
}
|
||||
|
||||
private HttpClient getHttpClientForUrl(String repoUrl) throws IOException {
|
||||
HttpConnectionFactory connectionFactory = HttpTransport.getConnectionFactory();
|
||||
HttpConnection httpConnection = connectionFactory.create(new URL(repoUrl));
|
||||
assertThat(httpConnection).isInstanceOf(HttpClientConnection.class);
|
||||
return (HttpClient) ReflectionTestUtils.getField(httpConnection, "client");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ConfigServerProperties.class)
|
||||
@Import({ PropertyPlaceholderAutoConfiguration.class, EnvironmentRepositoryConfiguration.class })
|
||||
protected static class TestConfiguration {
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,10 @@
|
||||
*/
|
||||
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;
|
||||
@@ -39,9 +31,7 @@ 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;
|
||||
@@ -55,10 +45,10 @@ import static org.mockito.Mockito.when;
|
||||
@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"})
|
||||
"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
|
||||
@@ -68,10 +58,10 @@ public class VaultEnvironmentRepositoryIntegrationTests {
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void withSslValidation() {
|
||||
public void withSslValidation() throws Exception {
|
||||
VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory =
|
||||
new VaultEnvironmentRepositoryFactory(withRequest(), new EnvironmentWatch.Default(),
|
||||
Optional.of(skipSslValidationRestTemplate()));
|
||||
Optional.of(new HttpClientVaultRestTemplateFactory()));
|
||||
VaultEnvironmentRepository vaultEnvironmentRepository =
|
||||
vaultEnvironmentRepositoryFactory.build(withEnvironmentProperties(false));
|
||||
expectedException.expectCause(instanceOf(SSLHandshakeException.class));
|
||||
@@ -80,10 +70,10 @@ public class VaultEnvironmentRepositoryIntegrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipSslValidation() {
|
||||
public void skipSslValidation() throws Exception {
|
||||
VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory =
|
||||
new VaultEnvironmentRepositoryFactory(withRequest(), new EnvironmentWatch.Default(),
|
||||
Optional.of(skipSslValidationRestTemplate()));
|
||||
Optional.of(new HttpClientVaultRestTemplateFactory()));
|
||||
VaultEnvironmentRepository vaultEnvironmentRepository =
|
||||
vaultEnvironmentRepositoryFactory.build(withEnvironmentProperties(true));
|
||||
|
||||
@@ -92,23 +82,6 @@ public class VaultEnvironmentRepositoryIntegrationTests {
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user