Skip to content

Commit

Permalink
Update RemoteAddrRoutePredicateFactory to optionally respect the `X…
Browse files Browse the repository at this point in the history
…-Forwarded-For` header. Fixes gh-155.
  • Loading branch information
fitzoh committed Jan 14, 2018
1 parent b980609 commit bb1c346
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@

package org.springframework.cloud.gateway.handler.predicate;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.handler.support.RoutePredicateFactoryUtils;
import org.springframework.cloud.gateway.support.SubnetUtils;
import org.springframework.tuple.Tuple;
import org.springframework.util.Assert;
Expand All @@ -46,7 +47,7 @@ public Predicate<ServerWebExchange> apply(Tuple args) {
addSource(sources, (String) arg);
}
}
return apply(sources);
return apply(sources, false);
}

public Predicate<ServerWebExchange> apply(String... addrs) {
Expand All @@ -56,14 +57,22 @@ public Predicate<ServerWebExchange> apply(String... addrs) {
for (String addr : addrs) {
addSource(sources, addr);
}
return apply(sources);
return apply(sources, false);
}

public Predicate<ServerWebExchange> apply(List<SubnetUtils> sources) {
/**
* @param respectForwardedHeader whether to check the `X-Forwarded-For` header for the
* remote IP address.
*/
public Predicate<ServerWebExchange> apply(List<SubnetUtils> sources,
boolean respectForwardedHeader) {
Function<ServerWebExchange, String> remoteIpResolver = respectForwardedHeader
? RoutePredicateFactoryUtils::parseRemoteIpRespectingForwardedHeader
: RoutePredicateFactoryUtils::parseRemoteIpIgnoringForwardedHeader;

return exchange -> {
InetSocketAddress remoteAddress = exchange.getRequest().getRemoteAddress();
if (remoteAddress != null) {
String hostAddress = remoteAddress.getAddress().getHostAddress();
String hostAddress = remoteIpResolver.apply(exchange);
if (hostAddress != null) {
String host = exchange.getRequest().getURI().getHost();

if (!hostAddress.equals(host)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@

package org.springframework.cloud.gateway.handler.support;

import java.net.InetSocketAddress;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.web.server.ServerWebExchange;

/**
* @author Spencer Gibb
* @author Andrew Fitzgerald
*/
public class RoutePredicateFactoryUtils {

public static final String X_FORWARDED_FOR = "X-Forwarded-For";

private static final Log logger = LogFactory.getLog(RoutePredicateFactory.class);

public static void traceMatch(String prefix, Object desired, Object actual, boolean match) {
Expand All @@ -34,4 +42,22 @@ public static void traceMatch(String prefix, Object desired, Object actual, bool
logger.trace(message);
}
}


public static String parseRemoteIpRespectingForwardedHeader(ServerWebExchange exchange) {
List<String> xForwardedValues = exchange.getRequest().getHeaders().get(X_FORWARDED_FOR);
if (xForwardedValues != null && xForwardedValues.size() != 0) {
return xForwardedValues.get(0).split(", ")[0];
}
return parseRemoteIpIgnoringForwardedHeader(exchange);
}

public static String parseRemoteIpIgnoringForwardedHeader(ServerWebExchange exchange) {
InetSocketAddress remoteAddress = exchange.getRequest().getRemoteAddress();
if (remoteAddress != null) {
return remoteAddress.getAddress().getHostAddress();
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.springframework.cloud.gateway.handler.support;

import static org.assertj.core.api.Assertions.assertThat;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import org.junit.Test;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;

public class RoutePredicateFactoryUtilsTest {

private InetSocketAddress getRemote0000Address() {
try {
return new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 1234);
}
catch (UnknownHostException e) {
throw new IllegalStateException();
}
}

@Test
public void parseRemoteIpPrioritizesFirstForwardedIp() {
MockServerHttpRequest request = MockServerHttpRequest.get("someUrl")
.remoteAddress(getRemote0000Address())
.header("X-Forwarded-For", "0.0.0.1, 0.0.0.2, 0.0.0.3").build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
String actualIp = RoutePredicateFactoryUtils
.parseRemoteIpRespectingForwardedHeader(exchange);

assertThat(actualIp).isEqualTo("0.0.0.1");
}

@Test
public void parseRemoteIpFallsBackToRemoteIp() {
MockServerHttpRequest request = MockServerHttpRequest.get("someUrl")
.remoteAddress(getRemote0000Address()).build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
String actualIp = RoutePredicateFactoryUtils
.parseRemoteIpRespectingForwardedHeader(exchange);

assertThat(actualIp).isEqualTo("0.0.0.0");
}

@Test
public void parseRemoteIpReturnsNullIfNoForwardedOrRemoteIp() {
MockServerHttpRequest request = MockServerHttpRequest.get("someUrl").build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
String actualIp = RoutePredicateFactoryUtils
.parseRemoteIpRespectingForwardedHeader(exchange);

assertThat(actualIp).isEqualTo(null);
}
}

0 comments on commit bb1c346

Please sign in to comment.