Conditionally use request.remoteAddr instead of X-Forwarded-For

This commit is contained in:
Chris Eager
2023-11-22 17:05:50 -06:00
committed by Chris Eager
parent b1fd025ea6
commit a027c4ce1f
8 changed files with 48 additions and 16 deletions

View File

@@ -12,9 +12,12 @@ import com.google.common.net.HttpHeaders;
import java.io.IOException;
import java.time.Duration;
import java.util.Optional;
import javax.inject.Provider;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import org.glassfish.jersey.server.ExtendedUriInfo;
@@ -28,6 +31,9 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(RateLimitByIpFilter.class);
@Context
private Provider<HttpServletRequest> httpServletRequestProvider;
@VisibleForTesting
static final RateLimitExceededException INVALID_HEADER_EXCEPTION = new RateLimitExceededException(Duration.ofHours(1),
true);
@@ -35,10 +41,12 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
private static final ExceptionMapper<RateLimitExceededException> EXCEPTION_MAPPER = new RateLimitExceededExceptionMapper();
private final RateLimiters rateLimiters;
private final boolean useRemoteAddress;
public RateLimitByIpFilter(final RateLimiters rateLimiters) {
public RateLimitByIpFilter(final RateLimiters rateLimiters, final boolean useRemoteAddress) {
this.rateLimiters = requireNonNull(rateLimiters);
this.useRemoteAddress = useRemoteAddress;
}
@Override
@@ -62,12 +70,14 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
try {
final String xffHeader = requestContext.getHeaders().getFirst(HttpHeaders.X_FORWARDED_FOR);
final Optional<String> maybeMostRecentProxy = Optional.ofNullable(xffHeader)
.flatMap(HeaderUtils::getMostRecentProxy);
final Optional<String> remoteAddress = useRemoteAddress
? Optional.of(httpServletRequestProvider.get().getRemoteAddr())
: Optional.ofNullable(xffHeader)
.flatMap(HeaderUtils::getMostRecentProxy);
// checking if we failed to extract the most recent IP from the X-Forwarded-For header
// for any reason
if (maybeMostRecentProxy.isEmpty()) {
if (remoteAddress.isEmpty()) {
// checking if annotation is configured to fail when the most recent IP is not resolved
if (annotation.failOnUnresolvedIp()) {
logger.error("Missing/bad X-Forwarded-For: {}", xffHeader);
@@ -78,7 +88,7 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
}
final RateLimiter rateLimiter = rateLimiters.forDescriptor(handle);
rateLimiter.validate(maybeMostRecentProxy.get());
rateLimiter.validate(remoteAddress.get());
} catch (RateLimitExceededException e) {
final Response response = EXCEPTION_MAPPER.toResponse(e);
throw new ClientErrorException(response);