change v1/challenge response for invalid captcha
This commit is contained in:
parent
05b43a878b
commit
890293e429
|
@ -20,8 +20,9 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.Optional;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import javax.ws.rs.BadRequestException;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.HeaderParam;
|
import javax.ws.rs.HeaderParam;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
|
@ -85,19 +86,20 @@ public class ChallengeController {
|
||||||
tags = tags.and(CHALLENGE_TYPE_TAG, "push");
|
tags = tags.and(CHALLENGE_TYPE_TAG, "push");
|
||||||
|
|
||||||
rateLimitChallengeManager.answerPushChallenge(auth.getAccount(), pushChallengeRequest.getChallenge());
|
rateLimitChallengeManager.answerPushChallenge(auth.getAccount(), pushChallengeRequest.getChallenge());
|
||||||
} else if (answerRequest instanceof AnswerRecaptchaChallengeRequest) {
|
} else if (answerRequest instanceof AnswerRecaptchaChallengeRequest recaptchaChallengeRequest) {
|
||||||
tags = tags.and(CHALLENGE_TYPE_TAG, "recaptcha");
|
tags = tags.and(CHALLENGE_TYPE_TAG, "recaptcha");
|
||||||
|
|
||||||
try {
|
final String mostRecentProxy = HeaderUtils.getMostRecentProxy(forwardedFor).orElseThrow(() -> new BadRequestException());
|
||||||
final AnswerRecaptchaChallengeRequest recaptchaChallengeRequest = (AnswerRecaptchaChallengeRequest) answerRequest;
|
boolean success = rateLimitChallengeManager.answerRecaptchaChallenge(
|
||||||
final String mostRecentProxy = HeaderUtils.getMostRecentProxy(forwardedFor).orElseThrow();
|
auth.getAccount(),
|
||||||
|
recaptchaChallengeRequest.getCaptcha(),
|
||||||
|
mostRecentProxy,
|
||||||
|
userAgent);
|
||||||
|
|
||||||
rateLimitChallengeManager.answerRecaptchaChallenge(auth.getAccount(), recaptchaChallengeRequest.getCaptcha(),
|
if (!success) {
|
||||||
mostRecentProxy, userAgent);
|
return Response.status(428).build();
|
||||||
|
|
||||||
} catch (final NoSuchElementException e) {
|
|
||||||
return Response.status(400).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
tags = tags.and(CHALLENGE_TYPE_TAG, "unrecognized");
|
tags = tags.and(CHALLENGE_TYPE_TAG, "unrecognized");
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class RateLimitChallengeManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void answerRecaptchaChallenge(final Account account, final String captcha, final String mostRecentProxyIp, final String userAgent)
|
public boolean answerRecaptchaChallenge(final Account account, final String captcha, final String mostRecentProxyIp, final String userAgent)
|
||||||
throws RateLimitExceededException, IOException {
|
throws RateLimitExceededException, IOException {
|
||||||
|
|
||||||
rateLimiters.getRecaptchaChallengeAttemptLimiter().validate(account.getUuid());
|
rateLimiters.getRecaptchaChallengeAttemptLimiter().validate(account.getUuid());
|
||||||
|
@ -82,6 +82,7 @@ public class RateLimitChallengeManager {
|
||||||
rateLimiters.getRecaptchaChallengeSuccessLimiter().validate(account.getUuid());
|
rateLimiters.getRecaptchaChallengeSuccessLimiter().validate(account.getUuid());
|
||||||
resetRateLimits(account);
|
resetRateLimits(account);
|
||||||
}
|
}
|
||||||
|
return challengeSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetRateLimits(final Account account) throws RateLimitExceededException {
|
private void resetRateLimits(final Account account) throws RateLimitExceededException {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.common.net.HttpHeaders;
|
import com.google.common.net.HttpHeaders;
|
||||||
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
|
@ -108,6 +109,9 @@ class ChallengeControllerTest {
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
when(rateLimitChallengeManager.answerRecaptchaChallenge(any(), any(), any(), any()))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
final Response response = EXTENSION.target("/v1/challenge")
|
final Response response = EXTENSION.target("/v1/challenge")
|
||||||
.request()
|
.request()
|
||||||
.header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1")
|
.header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1")
|
||||||
|
@ -115,9 +119,32 @@ class ChallengeControllerTest {
|
||||||
.put(Entity.json(recaptchaChallengeJson));
|
.put(Entity.json(recaptchaChallengeJson));
|
||||||
|
|
||||||
assertEquals(200, response.getStatus());
|
assertEquals(200, response.getStatus());
|
||||||
|
|
||||||
verify(rateLimitChallengeManager).answerRecaptchaChallenge(eq(AuthHelper.VALID_ACCOUNT), eq("The value of the solved captcha token"), eq("10.0.0.1"), anyString());
|
verify(rateLimitChallengeManager).answerRecaptchaChallenge(eq(AuthHelper.VALID_ACCOUNT), eq("The value of the solved captcha token"), eq("10.0.0.1"), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHandleInvalidCaptcha() throws RateLimitExceededException, IOException {
|
||||||
|
final String recaptchaChallengeJson = """
|
||||||
|
{
|
||||||
|
"type": "recaptcha",
|
||||||
|
"token": "A server-generated token",
|
||||||
|
"captcha": "The value of the solved captcha token"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
when(rateLimitChallengeManager.answerRecaptchaChallenge(eq(AuthHelper.VALID_ACCOUNT), eq("The value of the solved captcha token"), eq("10.0.0.1"), anyString()))
|
||||||
|
.thenReturn(false);
|
||||||
|
|
||||||
|
final Response response = EXTENSION.target("/v1/challenge")
|
||||||
|
.request()
|
||||||
|
.header(HttpHeaders.X_FORWARDED_FOR, "10.0.0.1")
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
|
.put(Entity.json(recaptchaChallengeJson));
|
||||||
|
|
||||||
|
assertEquals(428, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testHandleRecaptchaRateLimited() throws RateLimitExceededException, IOException {
|
void testHandleRecaptchaRateLimited() throws RateLimitExceededException, IOException {
|
||||||
final String recaptchaChallengeJson = """
|
final String recaptchaChallengeJson = """
|
||||||
|
|
Loading…
Reference in New Issue