Add rate limiting
This commit is contained in:
parent
a3545ce551
commit
c6eb306691
|
@ -29,6 +29,9 @@ public class RateLimitsConfiguration {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private RateLimitConfiguration voiceDestinationDaily = new RateLimitConfiguration(10, 10.0 / (24.0 * 60.0));
|
private RateLimitConfiguration voiceDestinationDaily = new RateLimitConfiguration(10, 10.0 / (24.0 * 60.0));
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private RateLimitConfiguration smsVoiceIp = new RateLimitConfiguration(1000, 1000);
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private RateLimitConfiguration verifyNumber = new RateLimitConfiguration(2, 2);
|
private RateLimitConfiguration verifyNumber = new RateLimitConfiguration(2, 2);
|
||||||
|
|
||||||
|
@ -95,6 +98,10 @@ public class RateLimitsConfiguration {
|
||||||
return voiceDestinationDaily;
|
return voiceDestinationDaily;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RateLimitConfiguration getSmsVoiceIp() {
|
||||||
|
return smsVoiceIp;
|
||||||
|
}
|
||||||
|
|
||||||
public RateLimitConfiguration getVerifyNumber() {
|
public RateLimitConfiguration getVerifyNumber() {
|
||||||
return verifyNumber;
|
return verifyNumber;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ public class AccountController {
|
||||||
@Path("/{transport}/code/{number}")
|
@Path("/{transport}/code/{number}")
|
||||||
public Response createAccount(@PathParam("transport") String transport,
|
public Response createAccount(@PathParam("transport") String transport,
|
||||||
@PathParam("number") String number,
|
@PathParam("number") String number,
|
||||||
|
@HeaderParam("X-Forwarded-For") String requester,
|
||||||
@QueryParam("client") Optional<String> client)
|
@QueryParam("client") Optional<String> client)
|
||||||
throws IOException, RateLimitExceededException
|
throws IOException, RateLimitExceededException
|
||||||
{
|
{
|
||||||
|
@ -120,6 +121,13 @@ public class AccountController {
|
||||||
throw new WebApplicationException(Response.status(400).build());
|
throw new WebApplicationException(Response.status(400).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rateLimiters.getSmsVoiceIpLimiter().validate(requester);
|
||||||
|
} catch (RateLimitExceededException e) {
|
||||||
|
logger.info("Rate limited exceeded: " + transport + ", " + number + ", " + requester);
|
||||||
|
return Response.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
switch (transport) {
|
switch (transport) {
|
||||||
case "sms":
|
case "sms":
|
||||||
rateLimiters.getSmsDestinationLimiter().validate(number);
|
rateLimiters.getSmsDestinationLimiter().validate(number);
|
||||||
|
|
|
@ -25,6 +25,7 @@ public class RateLimiters {
|
||||||
private final RateLimiter smsDestinationLimiter;
|
private final RateLimiter smsDestinationLimiter;
|
||||||
private final RateLimiter voiceDestinationLimiter;
|
private final RateLimiter voiceDestinationLimiter;
|
||||||
private final RateLimiter voiceDestinationDailyLimiter;
|
private final RateLimiter voiceDestinationDailyLimiter;
|
||||||
|
private final RateLimiter smsVoiceIpLimiter;
|
||||||
private final RateLimiter verifyLimiter;
|
private final RateLimiter verifyLimiter;
|
||||||
private final RateLimiter pinLimiter;
|
private final RateLimiter pinLimiter;
|
||||||
|
|
||||||
|
@ -53,6 +54,10 @@ public class RateLimiters {
|
||||||
config.getVoiceDestinationDaily().getBucketSize(),
|
config.getVoiceDestinationDaily().getBucketSize(),
|
||||||
config.getVoiceDestinationDaily().getLeakRatePerMinute());
|
config.getVoiceDestinationDaily().getLeakRatePerMinute());
|
||||||
|
|
||||||
|
this.smsVoiceIpLimiter = new RateLimiter(cacheClient, "smsVoiceIp",
|
||||||
|
config.getSmsVoiceIp().getBucketSize(),
|
||||||
|
config.getSmsVoiceIp().getLeakRatePerMinute());
|
||||||
|
|
||||||
this.verifyLimiter = new RateLimiter(cacheClient, "verify",
|
this.verifyLimiter = new RateLimiter(cacheClient, "verify",
|
||||||
config.getVerifyNumber().getBucketSize(),
|
config.getVerifyNumber().getBucketSize(),
|
||||||
config.getVerifyNumber().getLeakRatePerMinute());
|
config.getVerifyNumber().getLeakRatePerMinute());
|
||||||
|
@ -122,6 +127,10 @@ public class RateLimiters {
|
||||||
return smsDestinationLimiter;
|
return smsDestinationLimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RateLimiter getSmsVoiceIpLimiter() {
|
||||||
|
return smsVoiceIpLimiter;
|
||||||
|
}
|
||||||
|
|
||||||
public RateLimiter getVoiceDestinationLimiter() {
|
public RateLimiter getVoiceDestinationLimiter() {
|
||||||
return voiceDestinationLimiter;
|
return voiceDestinationLimiter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class AccountControllerTest {
|
||||||
private RateLimiters rateLimiters = mock(RateLimiters.class );
|
private RateLimiters rateLimiters = mock(RateLimiters.class );
|
||||||
private RateLimiter rateLimiter = mock(RateLimiter.class );
|
private RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||||
private RateLimiter pinLimiter = mock(RateLimiter.class );
|
private RateLimiter pinLimiter = mock(RateLimiter.class );
|
||||||
|
private RateLimiter smsVoiceIpLimiter = mock(RateLimiter.class );
|
||||||
private SmsSender smsSender = mock(SmsSender.class );
|
private SmsSender smsSender = mock(SmsSender.class );
|
||||||
private DirectoryQueue directoryQueue = mock(DirectoryQueue.class);
|
private DirectoryQueue directoryQueue = mock(DirectoryQueue.class);
|
||||||
private MessagesManager storedMessages = mock(MessagesManager.class );
|
private MessagesManager storedMessages = mock(MessagesManager.class );
|
||||||
|
@ -80,6 +81,7 @@ public class AccountControllerTest {
|
||||||
when(rateLimiters.getVoiceDestinationLimiter()).thenReturn(rateLimiter);
|
when(rateLimiters.getVoiceDestinationLimiter()).thenReturn(rateLimiter);
|
||||||
when(rateLimiters.getVerifyLimiter()).thenReturn(rateLimiter);
|
when(rateLimiters.getVerifyLimiter()).thenReturn(rateLimiter);
|
||||||
when(rateLimiters.getPinLimiter()).thenReturn(pinLimiter);
|
when(rateLimiters.getPinLimiter()).thenReturn(pinLimiter);
|
||||||
|
when(rateLimiters.getSmsVoiceIpLimiter()).thenReturn(smsVoiceIpLimiter);
|
||||||
|
|
||||||
when(timeProvider.getCurrentTimeMillis()).thenReturn(System.currentTimeMillis());
|
when(timeProvider.getCurrentTimeMillis()).thenReturn(System.currentTimeMillis());
|
||||||
|
|
||||||
|
@ -106,6 +108,7 @@ public class AccountControllerTest {
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
|
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
|
||||||
.request()
|
.request()
|
||||||
|
.header("X-Forwarded-For", "127.0.0.1")
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
@ -120,6 +123,7 @@ public class AccountControllerTest {
|
||||||
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
|
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
|
||||||
.queryParam("client", "ios")
|
.queryParam("client", "ios")
|
||||||
.request()
|
.request()
|
||||||
|
.header("X-Forwarded-For", "127.0.0.1")
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
|
Loading…
Reference in New Issue