Try to guess whether a ribbon client is looking for HTTPS
There are usually some hints available, especially if the Server came from Eureka. Unfortunately Server on it's own doesn't contain enough information (why?), but as a fallback we can guess that anyone using port 443 is secure. Fixes gh-459
This commit is contained in:
@@ -108,6 +108,16 @@ information will have a secure health check URL. Because of the way
|
||||
Eureka works internally, it will still publish a non-secure URL for
|
||||
status and home page unless you also override those explicitly.
|
||||
|
||||
NOTE: If your app is running behind a proxy, and the SSL termination
|
||||
is in the proxy (e.g. if you run in Cloud Foundry or other platforms
|
||||
as a service) then you will need to ensure that the proxy "forwarded"
|
||||
headers are intercepted and handled by the application. An embedded
|
||||
Tomcat container in a Spring Boot app does this automatically for most
|
||||
proxies (since 1.3.0), but other containers might need explicit
|
||||
configuration for the 'X-Forwarded-\*` headers. A sign that you got
|
||||
this wrong will be that the links rendered by your app to itslef will be
|
||||
wrong (the wrong host, port or protocol).
|
||||
|
||||
=== Eureka's Health Checks
|
||||
|
||||
By default, Eureka uses the client heartbeat to determine if a client is up.
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.netflix.ribbon;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.http.client.params.ClientPNames;
|
||||
import org.apache.http.client.params.CookiePolicy;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -24,7 +26,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo.PortType;
|
||||
import com.netflix.client.config.DefaultClientConfigImpl;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ConfigurationBasedServerList;
|
||||
@@ -39,6 +44,7 @@ import com.netflix.loadbalancer.ServerListFilter;
|
||||
import com.netflix.loadbalancer.ZoneAvoidanceRule;
|
||||
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
|
||||
import com.netflix.niws.client.http.RestClient;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
||||
import com.netflix.servo.monitor.Monitors;
|
||||
import com.sun.jersey.api.client.Client;
|
||||
import com.sun.jersey.client.apache4.ApacheHttpClient4;
|
||||
@@ -90,9 +96,9 @@ public class RibbonClientConfiguration {
|
||||
|
||||
/**
|
||||
* Create a Netflix {@link RestClient} integrated with Ribbon if none already exists in the
|
||||
* application context. It is not required for Ribbon to work properly and is therefore
|
||||
* application context. It is not required for Ribbon to work properly and is therefore
|
||||
* created lazily if ever another component requires it.
|
||||
*
|
||||
*
|
||||
* @param config the configuration to use by the underlying Ribbon instance
|
||||
* @param loadBalancer the load balancer to use by the underlying Ribbon instance
|
||||
* @return a {@link RestClient} instances backed by Ribbon
|
||||
@@ -141,6 +147,27 @@ public class RibbonClientConfiguration {
|
||||
initWithNiwsConfig(ncc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI reconstructURIWithServer(Server server, URI original) {
|
||||
String scheme = original.getScheme();
|
||||
if (!"https".equals(scheme) && isSecure(server)) {
|
||||
original = UriComponentsBuilder.fromUri(original).scheme("https").build().toUri();
|
||||
}
|
||||
return super.reconstructURIWithServer(server, original);
|
||||
}
|
||||
|
||||
private boolean isSecure(Server server) {
|
||||
if (ClassUtils.isPresent("com.netflix.niws.loadbalancer.DiscoveryEnabledServer",
|
||||
null)) {
|
||||
if (server instanceof DiscoveryEnabledServer) {
|
||||
DiscoveryEnabledServer enabled = (DiscoveryEnabledServer) server;
|
||||
return enabled.getInstanceInfo().isPortEnabled(PortType.SECURE);
|
||||
}
|
||||
}
|
||||
// Can we do better?
|
||||
return (""+server.getPort()).endsWith("443");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Client apacheHttpClientSpecificInitialization() {
|
||||
ApacheHttpClient4 apache = (ApacheHttpClient4) super
|
||||
|
||||
@@ -24,14 +24,17 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo.PortType;
|
||||
import com.netflix.client.config.CommonClientConfigKey;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerStats;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
||||
import com.netflix.servo.monitor.Stopwatch;
|
||||
|
||||
/**
|
||||
@@ -53,9 +56,9 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
RibbonLoadBalancerContext context = this.clientFactory
|
||||
.getLoadBalancerContext(serviceId);
|
||||
Server server = new Server(instance.getHost(), instance.getPort());
|
||||
boolean secure = isSecure(this.clientFactory, serviceId);
|
||||
boolean secure = isSecure(this.clientFactory, server, serviceId);
|
||||
URI uri = original;
|
||||
if(secure) {
|
||||
if (secure) {
|
||||
uri = UriComponentsBuilder.fromUri(uri).scheme("https").build().toUri();
|
||||
}
|
||||
return context.reconstructURIWithServer(server, uri);
|
||||
@@ -67,7 +70,8 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
if (server == null) {
|
||||
return null;
|
||||
}
|
||||
return new RibbonServer(serviceId, server, isSecure(this.clientFactory, serviceId));
|
||||
return new RibbonServer(serviceId, server,
|
||||
isSecure(this.clientFactory, server, serviceId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,7 +80,8 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
RibbonLoadBalancerContext context = this.clientFactory
|
||||
.getLoadBalancerContext(serviceId);
|
||||
Server server = getServer(loadBalancer);
|
||||
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(clientFactory, serviceId));
|
||||
RibbonServer ribbonServer = new RibbonServer(serviceId, server,
|
||||
isSecure(this.clientFactory, server, serviceId));
|
||||
|
||||
ServerStats serverStats = context.getServerStats(server);
|
||||
context.noteOpenConnection(serverStats);
|
||||
@@ -93,20 +98,30 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isSecure(SpringClientFactory clientFactory, String serviceId) {
|
||||
|
||||
private boolean isSecure(SpringClientFactory clientFactory, Server server,
|
||||
String serviceId) {
|
||||
IClientConfig config = clientFactory.getClientConfig(serviceId);
|
||||
if(config != null) {
|
||||
if (config != null) {
|
||||
return config.get(CommonClientConfigKey.IsSecure, false);
|
||||
}
|
||||
return false;
|
||||
if (ClassUtils.isPresent("com.netflix.niws.loadbalancer.DiscoveryEnabledServer",
|
||||
null)) {
|
||||
if (server instanceof DiscoveryEnabledServer) {
|
||||
DiscoveryEnabledServer enabled = (DiscoveryEnabledServer) server;
|
||||
return enabled.getInstanceInfo().isPortEnabled(PortType.SECURE);
|
||||
}
|
||||
}
|
||||
// Can we do better?
|
||||
return ("" + server.getPort()).endsWith("443");
|
||||
}
|
||||
|
||||
private void recordStats(RibbonLoadBalancerContext context, Stopwatch tracer,
|
||||
ServerStats serverStats, Object entity, Throwable exception) {
|
||||
tracer.stop();
|
||||
long duration = tracer.getDuration(TimeUnit.MILLISECONDS);
|
||||
context.noteRequestCompletion(serverStats, entity, exception, duration, null/* errorHandler */);
|
||||
context.noteRequestCompletion(serverStats, entity, exception, duration,
|
||||
null/* errorHandler */);
|
||||
}
|
||||
|
||||
protected Server getServer(String serviceId) {
|
||||
@@ -117,7 +132,7 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
if (loadBalancer == null) {
|
||||
return null;
|
||||
}
|
||||
return loadBalancer.chooseServer("default"); //TODO: better handling of key
|
||||
return loadBalancer.chooseServer("default"); // TODO: better handling of key
|
||||
}
|
||||
|
||||
protected ILoadBalancer getLoadBalancer(String serviceId) {
|
||||
@@ -128,7 +143,7 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
|
||||
private String serviceId;
|
||||
private Server server;
|
||||
private boolean secure;
|
||||
|
||||
|
||||
protected RibbonServer(String serviceId, Server server) {
|
||||
this(serviceId, server, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user