Commit a38ba340 by Dave Syer

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
parent b10bf9c3
......@@ -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;
......@@ -142,6 +148,27 @@ public class RibbonClientConfiguration {
}
@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
.apacheHttpClientSpecificInitialization();
......
......@@ -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);
......@@ -94,19 +99,29 @@ 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) {
......
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