Skip to content

Commit

Permalink
Merge pull request #97 from /issues/96-max-attempts-otp-sca
Browse files Browse the repository at this point in the history
Fix #96: Test for maximum attempts for OTP verification during SCA step
  • Loading branch information
romanstrobl authored Sep 6, 2022
2 parents 357c1a5 + 8862d6f commit 6e97097
Showing 1 changed file with 63 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ void testScaFailedPresenceCheck() throws Exception {
initPresenceCheck(processId);
if (!config.isSkipResultVerification()) {
verifyStatusBeforeOtp();
verifyOtpCheckFailed(processId);
verifyOtpCheckFailed(processId, IdentityVerificationPhase.PRESENCE_CHECK);
assertIdentityVerificationStateWithRetries(
new IdentityVerificationState(IdentityVerificationPhase.PRESENCE_CHECK, IdentityVerificationStatus.NOT_INITIALIZED));
verifyProcessNotFinished(processId);
Expand All @@ -236,9 +236,9 @@ void testScaFailedOtpCheck() throws Exception {
initPresenceCheck(processId);
if (!config.isSkipResultVerification()) {
verifyStatusBeforeOtp();
verifyOtpCheckFailedInvalidCode(processId);
verifyOtpCheckFailedInvalidCode(processId, IdentityVerificationPhase.OTP_VERIFICATION);
assertIdentityVerificationStateWithRetries(
new IdentityVerificationState(IdentityVerificationPhase.PRESENCE_CHECK, IdentityVerificationStatus.NOT_INITIALIZED));
new IdentityVerificationState(IdentityVerificationPhase.OTP_VERIFICATION, IdentityVerificationStatus.OTP_VERIFICATION_PENDING));
verifyProcessNotFinished(processId);
}

Expand Down Expand Up @@ -638,6 +638,28 @@ void initDocumentVerificationSdkTest() throws Exception {
assertNotNull(responseOK.getMac());
}

@Test
void testFailedScaOtpMaxFailedAttemptsIdentityRestart() throws Exception {
final TestContext context = prepareActivation();
final String activationId = context.activationId;
final String processId = context.processId;

processDocuments(context);

initPresenceCheck(processId);
if (!config.isSkipResultVerification()) {
for (int i = 0; i < 4; i++) {
verifyStatusBeforeOtp();
verifyOtpCheckFailedInvalidCode(processId, IdentityVerificationPhase.OTP_VERIFICATION);
}
// Verify restart of identity verification
verifyStatusBeforeOtp();
verifyOtpCheckFailedInvalidCode(processId, null);
}

powerAuthClient.removeActivation(activationId, "test");
}

private TestContext prepareActivation() throws Exception {
return prepareActivation("");
}
Expand Down Expand Up @@ -1085,68 +1107,60 @@ private OnboardingStatus checkProcessStatus(String processId) throws Exception {
return status;
}

private void verifyOtpCheckFailed(String processId) throws Exception {
private void verifyOtpCheckFailed(String processId, IdentityVerificationPhase allowedPhase) throws Exception {
final String otpCode = getOtpCode(processId, OtpType.USER_VERIFICATION);
verifyOtpCheck(processId, false, otpCode);
verifyOtpCheck(processId, false, otpCode, allowedPhase);
}

private void verifyOtpCheckFailedInvalidCode(String processId) throws Exception {
private void verifyOtpCheckFailedInvalidCode(String processId, IdentityVerificationPhase allowedPhase) throws Exception {
final String otpCode = "invalid";
verifyOtpCheck(processId, false, otpCode);
verifyOtpCheck(processId, false, otpCode, allowedPhase);
}

private void verifyOtpCheckSuccessful(String processId) throws Exception {
final String otpCode = getOtpCode(processId, OtpType.USER_VERIFICATION);
verifyOtpCheck(processId, true, otpCode);
verifyOtpCheck(processId, true, otpCode, IdentityVerificationPhase.COMPLETED);
}

private void verifyOtpCheck(final String processId, final boolean expectedResult, final String otpCode) throws Exception {
private void verifyOtpCheck(final String processId, final boolean expectedResult, final String otpCode, IdentityVerificationPhase allowedPhase) throws Exception {
if (config.isSkipOtpVerification()) {
return;
}
boolean otpVerified = false;
boolean verificationComplete = false;
for (int i = 0; i < 10; i++) {
IdentityVerificationState idState = checkIdentityVerificationState();
if (idState.getStatus() == IdentityVerificationStatus.OTP_VERIFICATION_PENDING) {
IdentityVerificationOtpVerifyRequest otpVerifyRequest = new IdentityVerificationOtpVerifyRequest();
otpVerifyRequest.setProcessId(processId);
otpVerifyRequest.setOtpCode(otpCode);
stepLogger = new ObjectStepLogger(System.out);
encryptModel.setData(objectMapper.writeValueAsBytes(new ObjectRequest<>(otpVerifyRequest)));
encryptModel.setUriString(config.getEnrollmentOnboardingServiceUrl() + "/api/identity/otp/verify");
encryptModel.setScope("activation");
new EncryptStep().execute(stepLogger, encryptModel.toMap());
assertTrue(stepLogger.getResult().isSuccess());
assertEquals(200, stepLogger.getResponse().getStatusCode());

otpVerified = stepLogger.getItems().stream()
.filter(isStepItemDecryptedResponse())
.map(StepItem::getObject)
.map(Object::toString)
.map(it -> safeReadValue(it, new TypeReference<ObjectResponse<OtpVerifyResponse>>() {}))
.filter(Objects::nonNull)
.map(ObjectResponse::getResponseObject)
.map(OtpVerifyResponse::isVerified)
.findFirst()
.orElse(false);

if (otpVerified) {
// Force status refresh
continue;
}
}
if (idState.getStatus() == IdentityVerificationStatus.ACCEPTED) {
verificationComplete = true;
break;
} else if (idState.getPhase() == IdentityVerificationPhase.PRESENCE_CHECK) {
verificationComplete = true;
break;
} else {
Thread.sleep(1000);
}
IdentityVerificationState idState = checkIdentityVerificationState();
if (idState.getStatus() == IdentityVerificationStatus.OTP_VERIFICATION_PENDING) {
IdentityVerificationOtpVerifyRequest otpVerifyRequest = new IdentityVerificationOtpVerifyRequest();
otpVerifyRequest.setProcessId(processId);
otpVerifyRequest.setOtpCode(otpCode);
stepLogger = new ObjectStepLogger(System.out);
encryptModel.setData(objectMapper.writeValueAsBytes(new ObjectRequest<>(otpVerifyRequest)));
encryptModel.setUriString(config.getEnrollmentOnboardingServiceUrl() + "/api/identity/otp/verify");
encryptModel.setScope("activation");
new EncryptStep().execute(stepLogger, encryptModel.toMap());
assertTrue(stepLogger.getResult().isSuccess());
assertEquals(200, stepLogger.getResponse().getStatusCode());

otpVerified = stepLogger.getItems().stream()
.filter(isStepItemDecryptedResponse())
.map(StepItem::getObject)
.map(Object::toString)
.map(it -> safeReadValue(it, new TypeReference<ObjectResponse<OtpVerifyResponse>>() {}))
.filter(Objects::nonNull)
.map(ObjectResponse::getResponseObject)
.map(OtpVerifyResponse::isVerified)
.findFirst()
.orElse(false);

// Force status refresh
idState = checkIdentityVerificationState();
}
if (idState.getStatus() == IdentityVerificationStatus.ACCEPTED) {
verificationComplete = true;
} else if (idState.getPhase() == allowedPhase) {
verificationComplete = true;
}
assertTrue(verificationComplete, "Verification should complete, either valid OTP or returning to PRESENCE_CHECK phase");
assertTrue(verificationComplete, "Verification should complete, either valid OTP or phase set to " + allowedPhase);
assertEquals(expectedResult, otpVerified);
}

Expand Down

0 comments on commit 6e97097

Please sign in to comment.