Make moving to https urls consistent.

This fixes a case where the ribbon property is set `ribbon.IsSecure=false`, but because the eureka secure port was enabled, the uri created by ribbon was prefixed with https when it shouldn't have. All places where isSecure is need have been consolidated into RibbonUtils. fixes gh-1270
parent 8d6aeebb
...@@ -23,7 +23,6 @@ import java.util.LinkedHashMap; ...@@ -23,7 +23,6 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.web.util.UriComponentsBuilder;
import com.netflix.client.AbstractLoadBalancerAwareClient; import com.netflix.client.AbstractLoadBalancerAwareClient;
import com.netflix.client.ClientException; import com.netflix.client.ClientException;
...@@ -38,10 +37,11 @@ import com.netflix.loadbalancer.Server; ...@@ -38,10 +37,11 @@ import com.netflix.loadbalancer.Server;
import feign.Client; import feign.Client;
import feign.Request; import feign.Request;
import feign.RequestTemplate;
import feign.Response; import feign.Response;
import feign.Util; import feign.Util;
import static org.springframework.cloud.netflix.ribbon.RibbonUtils.updateToHttpsIfNeeded;
public class FeignLoadBalancer extends public class FeignLoadBalancer extends
AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> { AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> {
...@@ -98,13 +98,8 @@ public class FeignLoadBalancer extends ...@@ -98,13 +98,8 @@ public class FeignLoadBalancer extends
@Override @Override
public URI reconstructURIWithServer(Server server, URI original) { public URI reconstructURIWithServer(Server server, URI original) {
String scheme = original.getScheme(); URI uri = updateToHttpsIfNeeded(original, this.clientConfig, this.serverIntrospector, server);
if (!"https".equals(scheme) && (this.serverIntrospector.isSecure(server) return super.reconstructURIWithServer(server, uri);
|| this.clientConfig.get(CommonClientConfigKey.IsSecure, false))) {
original = UriComponentsBuilder.fromUri(original).scheme("https").build()
.toUri();
}
return super.reconstructURIWithServer(server, original);
} }
static class RibbonRequest extends ClientRequest implements Cloneable { static class RibbonRequest extends ClientRequest implements Cloneable {
......
...@@ -52,7 +52,8 @@ import com.sun.jersey.api.client.Client; ...@@ -52,7 +52,8 @@ import com.sun.jersey.api.client.Client;
import com.sun.jersey.client.apache4.ApacheHttpClient4; import com.sun.jersey.client.apache4.ApacheHttpClient4;
import static com.netflix.client.config.CommonClientConfigKey.DeploymentContextBasedVipAddresses; import static com.netflix.client.config.CommonClientConfigKey.DeploymentContextBasedVipAddresses;
import static org.springframework.cloud.netflix.ribbon.RibbonProperyUtils.setRibbonProperty; import static org.springframework.cloud.netflix.ribbon.RibbonUtils.setRibbonProperty;
import static org.springframework.cloud.netflix.ribbon.RibbonUtils.updateToHttpsIfNeeded;
/** /**
* @author Dave Syer * @author Dave Syer
...@@ -187,23 +188,21 @@ public class RibbonClientConfiguration { ...@@ -187,23 +188,21 @@ public class RibbonClientConfiguration {
static class OverrideRestClient extends RestClient { static class OverrideRestClient extends RestClient {
private IClientConfig config;
private ServerIntrospector serverIntrospector; private ServerIntrospector serverIntrospector;
protected OverrideRestClient(IClientConfig ncc, protected OverrideRestClient(IClientConfig config,
ServerIntrospector serverIntrospector) { ServerIntrospector serverIntrospector) {
super(); super();
this.config = config;
this.serverIntrospector = serverIntrospector; this.serverIntrospector = serverIntrospector;
initWithNiwsConfig(ncc); initWithNiwsConfig(this.config);
} }
@Override @Override
public URI reconstructURIWithServer(Server server, URI original) { public URI reconstructURIWithServer(Server server, URI original) {
String scheme = original.getScheme(); URI uri = updateToHttpsIfNeeded(original, this.config, this.serverIntrospector, server);
if (!"https".equals(scheme) && this.serverIntrospector.isSecure(server)) { return super.reconstructURIWithServer(server, uri);
original = UriComponentsBuilder.fromUri(original).scheme("https").build(true)
.toUri();
}
return super.reconstructURIWithServer(server, original);
} }
@Override @Override
......
...@@ -29,7 +29,6 @@ import org.springframework.util.Assert; ...@@ -29,7 +29,6 @@ import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig; import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
...@@ -113,14 +112,8 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient { ...@@ -113,14 +112,8 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
private boolean isSecure(Server server, String serviceId) { private boolean isSecure(Server server, String serviceId) {
IClientConfig config = this.clientFactory.getClientConfig(serviceId); IClientConfig config = this.clientFactory.getClientConfig(serviceId);
if (config != null) { ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
Boolean isSecure = config.get(CommonClientConfigKey.IsSecure); return RibbonUtils.isSecure(config, serverIntrospector, server);
if (isSecure != null) {
return isSecure;
}
}
return serverIntrospector(serviceId).isSecure(server);
} }
protected Server getServer(String serviceId) { protected Server getServer(String serviceId) {
......
package org.springframework.cloud.netflix.ribbon; package org.springframework.cloud.netflix.ribbon;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
import com.netflix.client.config.IClientConfigKey;
import com.netflix.config.ConfigurationManager; import com.netflix.config.ConfigurationManager;
import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty; import com.netflix.config.DynamicStringProperty;
import com.netflix.loadbalancer.Server;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
*/ */
public class RibbonProperyUtils { public class RibbonUtils {
public static final String VALUE_NOT_SET = "__not__set__"; public static final String VALUE_NOT_SET = "__not__set__";
...@@ -30,4 +37,43 @@ public class RibbonProperyUtils { ...@@ -30,4 +37,43 @@ public class RibbonProperyUtils {
return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET); return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET);
} }
/**
* Determine if client is secure. If the supplied {@link IClientConfig} has the {@link CommonClientConfigKey#IsSecure}
* set, return that value. Otherwise, query the supplied {@link ServerIntrospector}.
* @param config the supplied client configuration.
* @param serverIntrospector
* @param server
* @return true if the client is secure
*/
public static boolean isSecure(IClientConfig config, ServerIntrospector serverIntrospector, Server server) {
if (config != null) {
Boolean isSecure = config.get(CommonClientConfigKey.IsSecure);
if (isSecure != null) {
return isSecure;
}
}
return serverIntrospector.isSecure(server);
}
/**
* Replace the scheme to https if needed. If the uri doesn't start with https and
* {@link #isSecure(IClientConfig, ServerIntrospector, Server)} is true, update the scheme.
* This assumes the uri is already encoded to avoid double encoding.
*
* @param uri
* @param config
* @param serverIntrospector
* @param server
* @return
*/
public static URI updateToHttpsIfNeeded(URI uri, IClientConfig config, ServerIntrospector serverIntrospector, Server server) {
String scheme = uri.getScheme();
if (!"https".equals(scheme) && isSecure(config, serverIntrospector, server)) {
return UriComponentsBuilder.fromUri(uri).scheme("https").build(true)
.toUri();
}
return uri;
}
} }
...@@ -19,6 +19,7 @@ import java.net.URI; ...@@ -19,6 +19,7 @@ import java.net.URI;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -104,6 +105,28 @@ public class FeignLoadBalancerTests { ...@@ -104,6 +105,28 @@ public class FeignLoadBalancerTests {
@Test @Test
@SneakyThrows @SneakyThrows
public void testInsecureUriFromInsecureClientConfigToSecureServerIntrospector() {
when(this.config.get(IsSecure)).thenReturn(false);
this.feignLoadBalancer = new FeignLoadBalancer(this.lb, this.config,
new ServerIntrospector() {
@Override
public boolean isSecure(Server server) {
return true;
}
@Override
public Map<String, String> getMetadata(Server server) {
return null;
}
});
Server server = new Server("foo", 7777);
URI uri = this.feignLoadBalancer.reconstructURIWithServer(server,
new URI("http://foo/"));
assertThat(uri, is(new URI("http://foo:7777/")));
}
@Test
@SneakyThrows
public void testSecureUriFromClientConfigOverride() { public void testSecureUriFromClientConfigOverride() {
this.feignLoadBalancer = new FeignLoadBalancer(this.lb, this.config, this.feignLoadBalancer = new FeignLoadBalancer(this.lb, this.config,
this.inspector); this.inspector);
......
/*
* Copyright 2013-2016 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.netflix.ribbon;
import com.netflix.client.config.CommonClientConfigKey;
import org.junit.Assert;
import org.junit.Test;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.loadbalancer.Server;
import java.util.Map;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.netflix.ribbon.RibbonUtils.isSecure;
/**
* @author Spencer Gibb
*/
public class RibbonUtilsTests {
private static final ServerIntrospector NON_SECURE_INTROSPECTOR = new StaticServerIntrospector(false);
private static final ServerIntrospector SECURE_INTROSPECTOR = new StaticServerIntrospector(true);
private static final Server SERVER = new Server("localhost", 8080);
private static final DefaultClientConfigImpl SECURE_CONFIG = getConfig(true);
private static final DefaultClientConfigImpl NON_SECURE_CONFIG = getConfig(false);
private static final DefaultClientConfigImpl NO_IS_SECURE_CONFIG = new DefaultClientConfigImpl();
@Test
public void noRibbonPropSecureIntrospector() {
boolean secure = isSecure(NO_IS_SECURE_CONFIG, SECURE_INTROSPECTOR, SERVER);
Assert.assertThat("isSecure was wrong", secure, is(true));
}
@Test
public void noRibbonPropNonSecureIntrospector() {
boolean secure = isSecure(NO_IS_SECURE_CONFIG, NON_SECURE_INTROSPECTOR, SERVER);
Assert.assertThat("isSecure was wrong", secure, is(false));
}
@Test
public void isSecureRibbonPropSecureIntrospector() {
boolean secure = isSecure(SECURE_CONFIG, SECURE_INTROSPECTOR, SERVER);
Assert.assertThat("isSecure was wrong", secure, is(true));
}
@Test
public void nonSecureRibbonPropNonSecureIntrospector() {
boolean secure = isSecure(NON_SECURE_CONFIG, NON_SECURE_INTROSPECTOR, SERVER);
Assert.assertThat("isSecure was wrong", secure, is(false));
}
@Test
public void isSecureRibbonPropNonSecureIntrospector() {
boolean secure = isSecure(SECURE_CONFIG, NON_SECURE_INTROSPECTOR, SERVER);
Assert.assertThat("isSecure was wrong", secure, is(true));
}
@Test
public void nonSecureRibbonPropSecureIntrospector() {
boolean secure = isSecure(NON_SECURE_CONFIG, SECURE_INTROSPECTOR, SERVER);
Assert.assertThat("isSecure was wrong", secure, is(false));
}
static DefaultClientConfigImpl getConfig(boolean value) {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.setProperty(CommonClientConfigKey.IsSecure, value);
return config;
}
static class StaticServerIntrospector implements ServerIntrospector {
final boolean secure;
public StaticServerIntrospector(boolean secure) {
this.secure = secure;
}
@Override
public boolean isSecure(Server server) {
return this.secure;
}
@Override
public Map<String, String> getMetadata(Server server) {
return null;
}
}
}
...@@ -41,7 +41,7 @@ import com.netflix.niws.loadbalancer.NIWSDiscoveryPing; ...@@ -41,7 +41,7 @@ import com.netflix.niws.loadbalancer.NIWSDiscoveryPing;
import static com.netflix.client.config.CommonClientConfigKey.DeploymentContextBasedVipAddresses; import static com.netflix.client.config.CommonClientConfigKey.DeploymentContextBasedVipAddresses;
import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity; import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity;
import static org.springframework.cloud.netflix.ribbon.RibbonProperyUtils.setRibbonProperty; import static org.springframework.cloud.netflix.ribbon.RibbonUtils.setRibbonProperty;
import lombok.extern.apachecommons.CommonsLog; import lombok.extern.apachecommons.CommonsLog;
......
...@@ -36,10 +36,10 @@ import com.netflix.niws.loadbalancer.DiscoveryEnabledServer; ...@@ -36,10 +36,10 @@ import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.springframework.cloud.netflix.ribbon.RibbonProperyUtils.VALUE_NOT_SET; import static org.springframework.cloud.netflix.ribbon.RibbonUtils.VALUE_NOT_SET;
import static org.springframework.cloud.netflix.ribbon.RibbonProperyUtils.getProperty; import static org.springframework.cloud.netflix.ribbon.RibbonUtils.getProperty;
import static org.springframework.cloud.netflix.ribbon.RibbonProperyUtils.getRibbonKey; import static org.springframework.cloud.netflix.ribbon.RibbonUtils.getRibbonKey;
import static org.springframework.cloud.netflix.ribbon.RibbonProperyUtils.setRibbonProperty; import static org.springframework.cloud.netflix.ribbon.RibbonUtils.setRibbonProperty;
/** /**
* @author Dave Syer * @author Dave Syer
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment