0
0
mirror of https://github.com/signalapp/Signal-Server.git synced 2024-09-19 19:42:18 +02:00

install RateLimitByIpFilter in soft-enforcement mode

This commit is contained in:
Jonathan Klabunde Tomer 2024-09-18 18:38:21 -04:00 committed by GitHub
parent 8cb9c60a3c
commit aa60fae3b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 4 deletions

View File

@ -167,6 +167,7 @@ import org.whispersystems.textsecuregcm.keytransparency.KeyTransparencyServiceCl
import org.whispersystems.textsecuregcm.limits.CardinalityEstimator;
import org.whispersystems.textsecuregcm.limits.MessageDeliveryLoopMonitor;
import org.whispersystems.textsecuregcm.limits.PushChallengeManager;
import org.whispersystems.textsecuregcm.limits.RateLimitByIpFilter;
import org.whispersystems.textsecuregcm.limits.RateLimitChallengeManager;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.mappers.CompletionExceptionMapper;
@ -1003,6 +1004,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
environment.jersey().register(new BufferingInterceptor());
environment.jersey().register(new VirtualExecutorServiceProvider("managed-async-virtual-thread-"));
environment.jersey().register(new RateLimitByIpFilter(rateLimiters, true));
environment.jersey().register(new RequestStatisticsFilter(TrafficSource.HTTP));
environment.jersey().register(MultiRecipientMessageProvider.class);
environment.jersey().register(new AuthDynamicFeature(accountAuthFilter));
@ -1021,11 +1023,13 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
clientReleaseManager, messageDeliveryLoopMonitor));
webSocketEnvironment.jersey()
.register(new WebsocketRefreshApplicationEventListener(accountsManager, clientPresenceManager));
webSocketEnvironment.jersey().register(new RateLimitByIpFilter(rateLimiters, true));
webSocketEnvironment.jersey().register(new RequestStatisticsFilter(TrafficSource.WEBSOCKET));
webSocketEnvironment.jersey().register(MultiRecipientMessageProvider.class);
webSocketEnvironment.jersey().register(new MetricsApplicationEventListener(TrafficSource.WEBSOCKET, clientReleaseManager));
webSocketEnvironment.jersey().register(new KeepAliveController(clientPresenceManager));
final List<SpamFilter> spamFilters = ServiceLoader.load(SpamFilter.class)
.stream()
.map(ServiceLoader.Provider::get)

View File

@ -22,6 +22,11 @@ import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.filters.RemoteAddressFilter;
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
public class RateLimitByIpFilter implements ContainerRequestFilter {
@ -33,11 +38,18 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
private static final ExceptionMapper<RateLimitExceededException> EXCEPTION_MAPPER = new RateLimitExceededExceptionMapper();
private final RateLimiters rateLimiters;
private static final String NO_IP_COUNTER_NAME = MetricsUtil.name(RateLimitByIpFilter.class, "noIpAddress");
private final RateLimiters rateLimiters;
private final boolean softEnforcement;
public RateLimitByIpFilter(final RateLimiters rateLimiters, final boolean softEnforcement) {
this.rateLimiters = requireNonNull(rateLimiters);
this.softEnforcement = softEnforcement;
}
public RateLimitByIpFilter(final RateLimiters rateLimiters) {
this.rateLimiters = requireNonNull(rateLimiters);
this(rateLimiters, false);
}
@Override
@ -65,10 +77,19 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
// checking if we failed to extract the most recent IP for any reason
if (remoteAddress.isEmpty()) {
Metrics.counter(
NO_IP_COUNTER_NAME,
Tags.of(
Tag.of("limiter", handle.id()),
Tag.of("fail", String.valueOf(annotation.failOnUnresolvedIp()))))
.increment();
// checking if annotation is configured to fail when the most recent IP is not resolved
if (annotation.failOnUnresolvedIp()) {
logger.error("Remote address was null");
throw INVALID_HEADER_EXCEPTION;
if (!softEnforcement) {
throw INVALID_HEADER_EXCEPTION;
}
}
// otherwise, allow request
return;
@ -78,7 +99,9 @@ public class RateLimitByIpFilter implements ContainerRequestFilter {
rateLimiter.validate(remoteAddress.get());
} catch (RateLimitExceededException e) {
final Response response = EXCEPTION_MAPPER.toResponse(e);
throw new ClientErrorException(response);
if (!softEnforcement) {
throw new ClientErrorException(response);
}
}
}
}