[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:
Benjamin Einaudi
2022-02-22 21:42:10 +01:00
committed by GitHub
parent cee78ddd86
commit 4ae403148e
5 changed files with 128 additions and 20 deletions

View File

@@ -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`.

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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");
}

View File

@@ -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;
}
}