Skip to content

Commit

Permalink
[#11729] RFC 7239 Forwarded Header based RealIpHeaderResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
beyond-seunghyun authored and jaehong-kim committed Nov 19, 2024
1 parent e5970b0 commit cbb9f5f
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@
import com.navercorp.pinpoint.common.util.StringUtils;

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


/**
* @author Woonduk Kang(emeroad)
*/
public class RealIpHeaderResolver<T> implements RemoteAddressResolver<T> {

private static final String FORWARDED_HEADER_NAME = "Forwarded";
private static final Pattern FORWARDED_FOR_PATTERN = Pattern.compile("(?i:for)=\"?([^;,\"]+)\"?");

private final String realIpHeaderName;
private final String realIpHeaderEmptyValue;

Expand All @@ -38,21 +43,41 @@ public RealIpHeaderResolver(final String realIpHeaderName, final String realIpHe

@Override
public String resolve(RequestAdaptor<T> requestAdaptor, T request) {
final String realIp = requestAdaptor.getHeader(request, realIpHeaderName);
if (StringUtils.isEmpty(realIp)) {
final String realIpHeaderValue = requestAdaptor.getHeader(request, realIpHeaderName);
if (StringUtils.isEmpty(realIpHeaderValue)) {
return null;
}

if (realIpHeaderEmptyValue != null && realIpHeaderEmptyValue.equalsIgnoreCase(realIp)) {
if (realIpHeaderEmptyValue != null && realIpHeaderEmptyValue.equalsIgnoreCase(realIpHeaderValue)) {
return null;
}

String firstRealIpHeaderValue = getFirstRealIpHeaderValue(realIpHeaderValue);

if ("Forwarded".equalsIgnoreCase(realIpHeaderName)) {
Matcher matcher = FORWARDED_FOR_PATTERN.matcher(firstRealIpHeaderValue);
if (matcher.find()) {
String ip = matcher.group(1).trim();
int portSeparatorIdx = ip.lastIndexOf(':');
int squareBracketIdx = ip.lastIndexOf(']');
if (portSeparatorIdx > squareBracketIdx) {
return ip.substring(0, portSeparatorIdx);
}

return ip;
}
}

return firstRealIpHeaderValue;
}

private static String getFirstRealIpHeaderValue(String realIp) {
final int firstIndex = realIp.indexOf(',');

if (firstIndex == -1) {
return realIp;
} else {
return realIp.substring(0, firstIndex);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@
* @author Woonduk Kang(emeroad)
*/
public class RemoteAddressResolverFactoryTest {
public static final String FORWARDED = "forwarded";
public static final String X_FORWARDED_FOR = "x-forwarded-for";
public static final String UNKNOWN = "unknown";

@Test
public void getRemoteAddress0() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, "x-forwarded-for", "unknown");
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, X_FORWARDED_FOR, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
when(httpServletRequest.getHeader(X_FORWARDED_FOR)).thenReturn("127.0.0.1");

Expand All @@ -49,7 +50,7 @@ public void getRemoteAddress0() throws Exception {
@Test
public void getRemoteAddress1() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, "x-forwarded-for", "unknown");
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, X_FORWARDED_FOR, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
when(httpServletRequest.getHeader(X_FORWARDED_FOR)).thenReturn("127.0.0.1, proxy1, proxy2");

Expand All @@ -61,11 +62,76 @@ public void getRemoteAddress1() throws Exception {
@Test
public void getRemoteAddress2() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, "x-forwarded-for", "unknown");
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, X_FORWARDED_FOR, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);

when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2");

assertEquals("127.0.0.2", requestAdaptor.getRemoteAddress(httpServletRequest));
}
}

@Test
public void getRemoteAddress3() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, FORWARDED, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);

when(httpServletRequest.getHeader(FORWARDED)).thenReturn("for=\"_gazonk\"");

when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2");

assertEquals("_gazonk", requestAdaptor.getRemoteAddress(httpServletRequest));
}

@Test
public void getRemoteAddress4() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, FORWARDED, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);

when(httpServletRequest.getHeader(FORWARDED)).thenReturn("For=\"[2001:db8:cafe::17]:4711\"");

when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2");

assertEquals("[2001:db8:cafe::17]", requestAdaptor.getRemoteAddress(httpServletRequest));
}

@Test
public void getRemoteAddress5() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, FORWARDED, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);

when(httpServletRequest.getHeader(FORWARDED)).thenReturn("for=192.0.2.60;proto=http;by=203.0.113.43");

when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2");

assertEquals("192.0.2.60", requestAdaptor.getRemoteAddress(httpServletRequest));
}

@Test
public void getRemoteAddress6() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, FORWARDED, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);

when(httpServletRequest.getHeader(FORWARDED)).thenReturn("for=192.0.2.43, for=198.51.100.17");

when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2");

assertEquals("192.0.2.43", requestAdaptor.getRemoteAddress(httpServletRequest));
}

@Test
public void getRemoteAddress7() throws Exception {
RequestAdaptor<HttpServletRequest> requestAdaptor = new HttpServletRequestAdaptor();
requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, FORWARDED, UNKNOWN);
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);

when(httpServletRequest.getHeader(FORWARDED)).thenReturn("for=192.0.2.43,for=198.51.100.17");

when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2");

assertEquals("192.0.2.43", requestAdaptor.getRemoteAddress(httpServletRequest));
}
}

0 comments on commit cbb9f5f

Please sign in to comment.