Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRPC getClientIP - Strip and keep only ip-address #85

Merged
merged 19 commits into from
Aug 10, 2024
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);
}


}