From c31e92a2b569afad583cf25214a4d6f3fd5bd65a Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 27 Jan 2017 20:34:50 -0700 Subject: [PATCH] Adds RemoteAddrRoutePredicate RemoteAddr=127.0.0.1/24 --- pom.xml | 5 ++ .../config/GatewayAutoConfiguration.java | 7 ++ .../predicate/RemoteAddrRoutePredicate.java | 66 +++++++++++++++++++ .../gateway/test/GatewayIntegrationTests.java | 6 +- .../gateway/test/GatewayTestApplication.java | 1 + src/test/resources/application.yml | 1 + 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/springframework/cloud/gateway/handler/predicate/RemoteAddrRoutePredicate.java diff --git a/pom.xml b/pom.xml index ae929191..3315ac3b 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,11 @@ org.springframework.boot spring-boot-devtools + + commons-net + commons-net + 3.5 + org.springframework.cloud spring-cloud-starter-eureka diff --git a/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index a5d51583..f5d012f4 100644 --- a/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -40,6 +40,7 @@ import org.springframework.cloud.gateway.handler.predicate.HeaderRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.HostRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicate; +import org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicate; import org.springframework.cloud.gateway.handler.predicate.RoutePredicate; import org.springframework.cloud.gateway.handler.predicate.UrlRoutePredicate; import org.springframework.context.annotation.Bean; @@ -163,6 +164,12 @@ public class GatewayAutoConfiguration { return new QueryRoutePredicate(); } + @Bean(name = "RemoteAddrRoutePredicate") + public RemoteAddrRoutePredicate remoteAddrRoutePredicate() { + return new RemoteAddrRoutePredicate(); + } + + @Bean(name = "UrlRoutePredicate") public UrlRoutePredicate urlRoutePredicate() { return new UrlRoutePredicate(); diff --git a/src/main/java/org/springframework/cloud/gateway/handler/predicate/RemoteAddrRoutePredicate.java b/src/main/java/org/springframework/cloud/gateway/handler/predicate/RemoteAddrRoutePredicate.java new file mode 100644 index 00000000..1219c1f8 --- /dev/null +++ b/src/main/java/org/springframework/cloud/gateway/handler/predicate/RemoteAddrRoutePredicate.java @@ -0,0 +1,66 @@ +package org.springframework.cloud.gateway.handler.predicate; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.net.util.SubnetUtils; +import org.springframework.http.server.reactive.ReactorServerHttpRequest; +import org.springframework.web.server.ServerWebExchange; + +/** + * @author Spencer Gibb + */ +public class RemoteAddrRoutePredicate implements RoutePredicate { + + private static final Log log = LogFactory.getLog(RemoteAddrRoutePredicate.class); + + @Override + public Predicate apply(String source, String[] args) { + List sources = new ArrayList<>(); + addSource(sources, source); + + if (args != null) { + for (String arg : args) { + addSource(sources, arg); + } + } + + return exchange -> { + ReactorServerHttpRequest request = (ReactorServerHttpRequest) exchange.getRequest(); + InetSocketAddress remoteAddress = request.getReactorRequest().remoteAddress(); + String hostAddress = remoteAddress.getAddress().getHostAddress(); + String host = exchange.getRequest().getURI().getHost(); + + if (!hostAddress.equals(host)) { + log.warn("Remote addresses didn't match " + hostAddress + " != " + host); + } + + for (SubnetUtils subnet : sources) { + if (subnet.getInfo().isInRange(hostAddress)) { + return true; + } + } + + return false; + }; + } + + private void addSource(List sources, String source) { + boolean inclusiveHostCount = false; + if (!source.contains("/")) { // no netmask, add default + source = source + "/32"; + } + if (source.endsWith("/32")) { + //http://stackoverflow.com/questions/2942299/converting-cidr-address-to-subnet-mask-and-network-address#answer-6858429 + inclusiveHostCount = true; + } + //TODO: howto support ipv6 as well? + SubnetUtils subnetUtils = new SubnetUtils(source); + subnetUtils.setInclusiveHostCount(inclusiveHostCount); + sources.add(subnetUtils); + } +} diff --git a/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java b/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java index 5645289a..089c067e 100644 --- a/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java +++ b/src/test/java/org/springframework/cloud/gateway/test/GatewayIntegrationTests.java @@ -43,7 +43,11 @@ public class GatewayIntegrationTests { private static final String HANDLER_MAPPER_HEADER = "X-Gateway-Handler-Mapper-Class"; private static final String ROUTE_ID_HEADER = "X-Gateway-Route-Id"; - public static final Duration DURATION = Duration.ofSeconds(5); + private static final Duration DURATION = Duration.ofSeconds(5); + + static { + System.setProperty("java.net.preferIPv4Stack", "true"); + } @LocalServerPort private int port; diff --git a/src/test/java/org/springframework/cloud/gateway/test/GatewayTestApplication.java b/src/test/java/org/springframework/cloud/gateway/test/GatewayTestApplication.java index 012d919a..88997176 100644 --- a/src/test/java/org/springframework/cloud/gateway/test/GatewayTestApplication.java +++ b/src/test/java/org/springframework/cloud/gateway/test/GatewayTestApplication.java @@ -53,6 +53,7 @@ public class GatewayTestApplication { } public static void main(String[] args) { + System.setProperty("java.net.preferIPv4Stack", "true"); //Remove when configurable SpringApplication.run(GatewayTestApplication.class, args); } } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 8f05ad0e..22db75bc 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -140,6 +140,7 @@ spring: uri: http://httpbin.org:80 predicates: - Host=**.baz.org + - RemoteAddr=127.0.0.1/24 filters: # $\ is being used as an escape - RewritePath=/foo/(?.*), /$\{segment}