Skip to content

Commit

Permalink
GRPC getClientIP - Strip and keep only ip-address (#85)
Browse files Browse the repository at this point in the history
Fix GRPC getClientIP Issue

---------

Co-authored-by: Kinshuk Bairagi <[email protected]>
Co-authored-by: Kinshuk Bairagi <[email protected]>
  • Loading branch information
3 people authored Aug 10, 2024
1 parent 98abf95 commit f0b42e5
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 6 deletions.
2 changes: 0 additions & 2 deletions core/src/main/java/com/flipkart/gjex/core/filter/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package com.flipkart.gjex.core.filter;

import com.flipkart.gjex.core.logging.Logging;

/**
* A Filter interface for processing Request, Request-Headers, Response and Response-Headers
* around gRPC and HTTP method invocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;
import java.util.Map;
import java.util.Optional;

Expand Down Expand Up @@ -90,7 +91,9 @@ public void doProcessResponse(ServletResponse response) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (isSuccess(httpServletResponse.getStatus())) {
// 2xx response
int contentLength = Optional.ofNullable(httpServletResponse.getHeader(HttpHeaderNames.CONTENT_LENGTH.toString()))
// TODO: check case where GET response is successful by content-length is -1.
int contentLength =
Optional.ofNullable(httpServletResponse.getHeader(HttpHeaders.CONTENT_LENGTH))
.map(Integer::parseInt).orElse(0);
accessLogContextBuilder.contentLength(contentLength);
} else {
Expand Down
31 changes: 31 additions & 0 deletions core/src/main/java/com/flipkart/gjex/core/util/NetworkUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.flipkart.gjex.core.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NetworkUtils {

private static final Pattern[] ipAddressPattern = {
Pattern.compile( "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})"),
Pattern.compile("((([0-9a-fA-F]){1,4})\\:){7}([0-9a-fA-F]){1,4}")
};


/**
* Extracts the IP address from a given string.
*
* @param str The input string from which the IP address is to be extracted.
* @return The IP address extracted from the input string.
*/
public static String extractIPAddress(String str) {
if (str != null) {
for (Pattern pattern : ipAddressPattern) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
return matcher.group();
}
}
}
return "0.0.0.0";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.flipkart.gjex.core.util;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class NetworkUtilsTest {


@Test
public void extractIPAddressReturnsIPv4Address() {
String input = "User IP is 192.168.1.1 and should be extracted";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("192.168.1.1", result);
}

@Test
public void extractIPAddressReturnsIPv6Address() {
String input = "User IP is 2001:0db8:85a3:0000:0000:8a2e:0370:7334 and should be extracted";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", result);
}

@Test
public void extractIPAddressReturnsFirstIPv4AddressWhenMultiplePresent() {
String input = "User IPs are 192.168.1.1 and 10.0.0.1, first one should be extracted";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("192.168.1.1", result);
}

@Test
public void extractIPAddressReturnsWithPrefix() {
String input = "/192.168.1.1:1234";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("192.168.1.1", result);
}

@Test
public void extractIPAddressReturnsFirstIPv6AddressWhenMultiplePresent() {
String input = "User IPs are 2001:0db8:85a3:0000:0000:8a2e:0370:7334 and fe80::1ff:fe23:4567:890a, first one should be extracted";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", result);
}

@Test
public void extractIPFromStringReturnsDefaultWhenNoIPPresent() {
String input = "No IP address in this string";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("0.0.0.0", result);
}

@Test
public void extractIPAddress() {
String input = "";
String result = NetworkUtils.extractIPAddress(input);
assertEquals("0.0.0.0", result);
}

@Test
public void extractIPAddressHandlesNullInput() {
String result = NetworkUtils.extractIPAddress(null);
assertEquals("0.0.0.0", result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,9 @@ protected void configure() {
bind(BindableService.class).annotatedWith(Names.named("GreeterService")).to(GreeterService.class);
bind(GrpcFilter.class).annotatedWith(Names.named("LoggingFilter")).to(LoggingFilter.class);
bind(GrpcFilter.class).annotatedWith(Names.named("AuthFilter")).to(AuthFilter.class);
// bind(AccessLogGrpcFilter.class).to(AccessLogTestFilter.class);
bind(TracingSampler.class).to(AllWhitelistTracingSampler.class);
bind(ResourceConfig.class).annotatedWith(Names.named("HelloWorldResourceConfig")).to(HelloWorldResourceConfig.class);
bind(JavaxFilterParams.class).annotatedWith(Names.named("ExampleJavaxFilter")).toInstance(JavaxFilterParams.builder().filter(new ExampleJavaxFilter()).pathSpec("/*").build());
bind(HttpFilterParams.class).annotatedWith(Names.named("CustomHeaderHttpFilter")).toInstance(HttpFilterParams.builder().filter(new CustomHeaderHttpFilter()).pathSpec("/*").build());

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.flipkart.gjex.core.filter.grpc.GrpcFilterConfig;
import com.flipkart.gjex.core.filter.grpc.MethodFilters;
import com.flipkart.gjex.core.logging.Logging;
import com.flipkart.gjex.core.util.NetworkUtils;
import com.flipkart.gjex.core.util.Pair;
import com.flipkart.gjex.grpc.utils.AnnotationUtils;
import io.grpc.*;
Expand All @@ -34,6 +35,8 @@
import javax.inject.Singleton;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -130,7 +133,7 @@ public void sendHeaders(final Metadata responseHeaders) {
}, headers);

RequestParams requestParams = RequestParams.builder()
.clientIp(call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR).toString())
.clientIp(getClientIp(call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR)))
.resourcePath(call.getMethodDescriptor().getFullMethodName().toLowerCase())
.metadata(headers)
.build();
Expand Down Expand Up @@ -215,4 +218,19 @@ private void configureAccessLog(GrpcFilterConfig grpcFilterConfig,
filtersForMethod.add(accessLogGrpcFilter);
}
}

protected static String getClientIp(SocketAddress socketAddress) {
if (socketAddress != null) {
if (socketAddress instanceof InetSocketAddress) {
return ((InetSocketAddress)socketAddress).getHostName();
} else {
// handle other scenarios use regex
String socketAddressString = socketAddress.toString();
return NetworkUtils.extractIPAddress(socketAddressString);
}
}
return "0.0.0.0";
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.flipkart.gjex.grpc.interceptor;

import org.junit.Test;

import java.net.InetSocketAddress;
import java.net.SocketAddress;

import static org.junit.Assert.assertEquals;

public class FilterInterceptorTest {

@Test
public void getClientIpReturnsHostNameForInetSocketAddress() {
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 1234);
String result = FilterInterceptor.getClientIp(inetSocketAddress);
assertEquals("localhost", result);
}

@Test
public void getClientIpReturnsExtractedIpForNonInetSocketAddress() {
SocketAddress socketAddress = new SocketAddress() {
@Override
public String toString() {
return "192.168.1.1:1234";
}
};
String result = FilterInterceptor.getClientIp(socketAddress);
assertEquals("192.168.1.1", result);
}

@Test
public void getClientIpReturnsDefaultIpForNullSocketAddress() {
String result = FilterInterceptor.getClientIp(null);
assertEquals("0.0.0.0", result);
}

@Test
public void getClientIpReturnsExtractedIpForGRPCSocketAddress() {
SocketAddress socketAddress = new SocketAddress() {
@Override
public String toString() {
return "/192.168.1.1:1234";
}
};
String result = FilterInterceptor.getClientIp(socketAddress);
assertEquals("192.168.1.1", result);
}

@Test
public void getClientIpReturnsExtractedFirstIpForGRPCSocketAddress() {
SocketAddress socketAddress = new SocketAddress() {
@Override
public String toString() {
return "192.168.1.1/192.168.1.2:1234";
}
};
String result = FilterInterceptor.getClientIp(socketAddress);
assertEquals("192.168.1.1", result);
}


}

0 comments on commit f0b42e5

Please sign in to comment.