[spring-cloud-config] Allow to use other scheme proxy when only one proxy is configured (#2049)
Allow to specify 'http' proxy for both protocols and viceversa Close #2048
This commit is contained in:
@@ -740,7 +740,11 @@ When `myApp` has the `dev` profile enabled, properties written to all of the abo
|
||||
|
||||
==== Accessing Backends Through a Proxy
|
||||
|
||||
The configuration server can access a Git or Vault backend through an HTTP or HTTPS proxy. This behavior is controlled for either Git or Vault by settings under `proxy.http` and `proxy.https`. These settings are per repository, so if you are using a <<composite-environment-repositories,composite environment repository>> you must configure proxy settings for each backend in the composite individually. If using a network which requires separate proxy servers for HTTP and HTTPS URLs, you can configure both the HTTP and the HTTPS proxy settings for a single backend.
|
||||
The configuration server can access a Git or Vault backend through an HTTP or HTTPS proxy.
|
||||
This behavior is controlled for either Git or Vault by settings under `proxy.http` and `proxy.https`.
|
||||
These settings are per repository, so if you are using a <<composite-environment-repositories,composite environment repository>> you must configure proxy settings for each backend in the composite individually.
|
||||
If using a network which requires separate proxy servers for HTTP and HTTPS URLs, you can configure both the HTTP and the HTTPS proxy settings for a single backend: in this case `http` access will use `http` proxy and `https` access the `https` one.
|
||||
Also, you may specify one sole proxy that will be used for both protocols using the proxy definition protocol between application and proxy.
|
||||
|
||||
The following table describes the proxy configuration properties for both HTTP and HTTPS proxies. All of these properties must be prefixed by `proxy.http` or `proxy.https`.
|
||||
|
||||
|
||||
@@ -26,23 +26,27 @@ import org.apache.http.protocol.HttpContext;
|
||||
*/
|
||||
public class SchemeBasedRoutePlanner extends DefaultRoutePlanner {
|
||||
|
||||
private final ProxyHostProperties httpsProxy;
|
||||
private final HttpHost httpsProxy;
|
||||
|
||||
private final ProxyHostProperties httpProxy;
|
||||
private final HttpHost defaultSchemeProxy;
|
||||
|
||||
public SchemeBasedRoutePlanner(ProxyHostProperties httpsProxy, ProxyHostProperties httpProxy) {
|
||||
super(null);
|
||||
this.httpsProxy = httpsProxy;
|
||||
this.httpProxy = httpProxy;
|
||||
this.httpsProxy = buildProxy(httpsProxy, "https");
|
||||
this.defaultSchemeProxy = buildProxy(httpProxy, HttpHost.DEFAULT_SCHEME_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) {
|
||||
return "https".equals(target.getSchemeName()) ? determineProxy(this.httpsProxy, "https")
|
||||
: determineProxy(this.httpProxy, HttpHost.DEFAULT_SCHEME_NAME);
|
||||
return "https".equals(target.getSchemeName()) ? determineProxy(this.httpsProxy, this.defaultSchemeProxy)
|
||||
: determineProxy(this.defaultSchemeProxy, this.httpsProxy);
|
||||
}
|
||||
|
||||
private HttpHost determineProxy(ProxyHostProperties properties, String scheme) {
|
||||
private HttpHost determineProxy(HttpHost proxy, HttpHost fallbackProxy) {
|
||||
return proxy != null ? proxy : fallbackProxy;
|
||||
}
|
||||
|
||||
private HttpHost buildProxy(ProxyHostProperties properties, String scheme) {
|
||||
if (properties == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -103,15 +103,16 @@ public class HttpClientVaultRestTemplateFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsProxy_notCalled() throws Exception {
|
||||
public void httpsProxy_called_for_http_request_when_no_httpProxy_specified() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(null, HTTPS_PROXY);
|
||||
RestTemplate restTemplate = this.factory.build(properties);
|
||||
this.expectedException.expectCause(
|
||||
allOf(instanceOf(UnknownHostException.class), hasProperty("message", containsString("somehost"))));
|
||||
this.expectedException.expectCause(allOf(instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTPS_PROXY.getHost()))));
|
||||
|
||||
restTemplate.getForObject("http://somehost", String.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void authenticatedHttpProxy() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(AUTHENTICATED_HTTP_PROXY, null);
|
||||
@@ -133,11 +134,11 @@ public class HttpClientVaultRestTemplateFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpProxy_notCalled() throws Exception {
|
||||
public void httpProxy_called_for_https_request_when_no_httpsProxy_specified() throws Exception {
|
||||
VaultEnvironmentProperties properties = getVaultEnvironmentProperties(HTTP_PROXY, null);
|
||||
RestTemplate restTemplate = this.factory.build(properties);
|
||||
this.expectedException.expectCause(
|
||||
allOf(instanceOf(UnknownHostException.class), hasProperty("message", containsString("somehost"))));
|
||||
this.expectedException.expectCause(allOf(instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTP_PROXY.getHost()))));
|
||||
|
||||
restTemplate.getForObject("https://somehost", String.class);
|
||||
}
|
||||
|
||||
@@ -135,13 +135,13 @@ public class ConfigurableHttpConnectionFactoryIntegrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsProxy_notCalled() throws Exception {
|
||||
public void httpsProxy_called_for_http_request_when_no_httpProxy_specified() 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);
|
||||
this.expectedException.expectCause(
|
||||
allOf(instanceOf(UnknownHostException.class), hasProperty("message", containsString("somehost"))));
|
||||
this.expectedException.expectCause(allOf(instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTPS_PROXY.getHost()))));
|
||||
|
||||
makeRequest(httpClient, "http://somehost");
|
||||
}
|
||||
@@ -182,13 +182,13 @@ public class ConfigurableHttpConnectionFactoryIntegrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpProxy_notCalled() throws Exception {
|
||||
public void httpProxy_called_for_https_request_when_no_httpsProxy_specified() 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);
|
||||
this.expectedException.expectCause(
|
||||
allOf(instanceOf(UnknownHostException.class), hasProperty("message", containsString("somehost"))));
|
||||
this.expectedException.expectCause(allOf(instanceOf(UnknownHostException.class),
|
||||
hasProperty("message", containsString(HTTP_PROXY.getHost()))));
|
||||
|
||||
makeRequest(httpClient, "https://somehost");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server.proxy;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class SchemeBasedRoutePlannerTest {
|
||||
|
||||
private static final ProxyHostProperties SECURED_PROXY_PROPERTIES = buildProxyProperties("http.host", 8080);
|
||||
|
||||
private static final ProxyHostProperties UNSECURED_PROXY_PROPERTIES = buildProxyProperties("https.host", 8443);
|
||||
|
||||
@Test
|
||||
void determineProxy_should_return_https_proxy_when_target_scheme_name_is_https_and_https_proxy_provided() {
|
||||
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(SECURED_PROXY_PROPERTIES, UNSECURED_PROXY_PROPERTIES);
|
||||
|
||||
final HttpHost result = planner.determineProxy(target("https"), anyRequest(), anyContext());
|
||||
|
||||
assertThat(result.getSchemeName()).isEqualTo("https");
|
||||
assertThat(result.getHostName()).isEqualTo(SECURED_PROXY_PROPERTIES.getHost());
|
||||
assertThat(result.getPort()).isEqualTo(SECURED_PROXY_PROPERTIES.getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
void determineProxy_should_return_https_proxy_when_target_scheme_name_is_http_and_no_http_proxy_specified() {
|
||||
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(SECURED_PROXY_PROPERTIES, null);
|
||||
|
||||
final HttpHost result = planner.determineProxy(target("http"), anyRequest(), anyContext());
|
||||
|
||||
assertThat(result.getSchemeName()).isEqualTo("https");
|
||||
assertThat(result.getHostName()).isEqualTo(SECURED_PROXY_PROPERTIES.getHost());
|
||||
assertThat(result.getPort()).isEqualTo(SECURED_PROXY_PROPERTIES.getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
void determineProxy_should_return_http_proxy_when_target_scheme_name_is_http_and_http_proxy_provided() {
|
||||
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(SECURED_PROXY_PROPERTIES, UNSECURED_PROXY_PROPERTIES);
|
||||
|
||||
final HttpHost result = planner.determineProxy(target("http"), anyRequest(), anyContext());
|
||||
|
||||
assertThat(result.getSchemeName()).isEqualTo("http");
|
||||
assertThat(result.getHostName()).isEqualTo(UNSECURED_PROXY_PROPERTIES.getHost());
|
||||
assertThat(result.getPort()).isEqualTo(UNSECURED_PROXY_PROPERTIES.getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
void determineProxy_should_return_http_proxy_when_target_scheme_name_is_https_and_https_proxy_provided() {
|
||||
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(null, UNSECURED_PROXY_PROPERTIES);
|
||||
|
||||
final HttpHost result = planner.determineProxy(target("https"), anyRequest(), anyContext());
|
||||
|
||||
assertThat(result.getSchemeName()).isEqualTo("http");
|
||||
assertThat(result.getHostName()).isEqualTo(UNSECURED_PROXY_PROPERTIES.getHost());
|
||||
assertThat(result.getPort()).isEqualTo(UNSECURED_PROXY_PROPERTIES.getPort());
|
||||
}
|
||||
|
||||
private HttpHost target(String scheme) {
|
||||
HttpHost host = mock(HttpHost.class);
|
||||
when(host.getSchemeName()).thenReturn(scheme);
|
||||
return host;
|
||||
}
|
||||
|
||||
private HttpRequest anyRequest() {
|
||||
return mock(HttpRequest.class);
|
||||
}
|
||||
|
||||
private HttpContext anyContext() {
|
||||
return mock(HttpContext.class);
|
||||
}
|
||||
|
||||
private static ProxyHostProperties buildProxyProperties(String host, int port) {
|
||||
ProxyHostProperties properties = new ProxyHostProperties();
|
||||
properties.setHost(host);
|
||||
properties.setPort(port);
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user