Skip to content

Commit

Permalink
Fix #922: EvaluateClientRequest should contain extracted data (#979)
Browse files Browse the repository at this point in the history
  • Loading branch information
jnpsk authored Jan 16, 2024
1 parent 7b3bbff commit b783099
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/onboarding/Configuration-Properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ The Onboarding Server uses the following public configuration properties:
| `enrollment-server-onboarding.identity-verification.otp.enabled` | `true` | Whether OTP verification is enabled during identity verification. |
| `enrollment-server-onboarding.identity-verification.max-failed-attempts` | `5` | Maximum failed attempts for identity verification. |
| `enrollment-server-onboarding.identity-verification.max-failed-attempts-document-upload` | `5` | Maximum failed attempts for document upload. |
| `enrollment-server-onboarding.client-evaluation.max-failed-attempts` | `5` | Maximum failed attempts for client evaluation. |

## Digital Onboarding Adapter Configuration

Expand All @@ -69,6 +68,7 @@ The Onboarding Server uses the following public configuration properties:
| Property | Default | Note |
|---|---|---|
| `enrollment-server-onboarding.client-evaluation.max-failed-attempts` | 5 | Number of maximum failed attempts for client evaluation. |
| `enrollment-server-onboarding.client-evaluation.include-extracted-data` | `false` | Include extracted data to the evaluate client request. The format of extracted data is defined by the provider of document verification. |

## Document Verification Provider Configuration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ public class IdentityVerificationConfig {
@Value("${enrollment-server-onboarding.client-evaluation.max-failed-attempts:5}")
private int clientEvaluationMaxFailedAttempts;

@Value("${enrollment-server-onboarding.client-evaluation.include-extracted-data:false}")
private boolean sendingExtractedDataEnabled;

@PostConstruct
void validate() {
// Once in the future, we may replace OTP in SCA by NFC document reading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import com.wultra.app.enrollmentserver.model.enumeration.ErrorOrigin;
import com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationPhase;
import com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationStatus;
import com.wultra.app.enrollmentserver.model.integration.DocumentSubmitResult;
import com.wultra.app.enrollmentserver.model.integration.OwnerId;
import com.wultra.app.onboardingserver.common.database.entity.DocumentResultEntity;
import com.wultra.app.onboardingserver.common.database.entity.DocumentVerificationEntity;
import com.wultra.app.onboardingserver.common.database.entity.IdentityVerificationEntity;
import com.wultra.app.onboardingserver.common.service.AuditService;
Expand All @@ -33,6 +35,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;

import static com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationStatus.ACCEPTED;
Expand Down Expand Up @@ -86,20 +89,27 @@ public ClientEvaluationService(
public void processClientEvaluation(final IdentityVerificationEntity identityVerification, final OwnerId ownerId) {
logger.debug("Client evaluation started for {}", identityVerification);

final Set<DocumentVerificationEntity> acceptedDocuments = selectAcceptedDocuments(identityVerification);

final String verificationId;
try {
verificationId = getVerificationId(identityVerification);
verificationId = fetchVerificationId(identityVerification, acceptedDocuments);
} catch (Exception e) {
processVerificationIdError(identityVerification, ownerId, e);
return;
}

final EvaluateClientRequest request = EvaluateClientRequest.builder()
final EvaluateClientRequest.EvaluateClientRequestBuilder requestBuilder = EvaluateClientRequest.builder()
.processId(identityVerification.getProcessId())
.userId(identityVerification.getUserId())
.identityVerificationId(identityVerification.getId())
.verificationId(verificationId)
.build();
.provider(config.getDocumentVerificationProvider());

if (config.isSendingExtractedDataEnabled()) {
requestBuilder.extractedData(fetchDocumentsExtractedData(acceptedDocuments, identityVerification));
}
final EvaluateClientRequest request = requestBuilder.build();

final int maxFailedAttempts = config.getClientEvaluationMaxFailedAttempts();
for (int i = 0; i < maxFailedAttempts; i++) {
Expand All @@ -117,10 +127,29 @@ public void processClientEvaluation(final IdentityVerificationEntity identityVer
processTooManyEvaluationError(identityVerification, ownerId);
}

private static String getVerificationId(final IdentityVerificationEntity identityVerification) {
final Set<String> verificationIds = identityVerification.getDocumentVerifications().stream()
private static Set<DocumentVerificationEntity> selectAcceptedDocuments(final IdentityVerificationEntity identityVerification) {
return identityVerification.getDocumentVerifications().stream()
.filter(DocumentVerificationEntity::isUsedForVerification)
.filter(it -> it.getStatus() == DocumentStatus.ACCEPTED)
.collect(toSet());
}

private static List<String> fetchDocumentsExtractedData(final Set<DocumentVerificationEntity> documents, final IdentityVerificationEntity identityVerification) {
return documents.stream()
.map(doc -> selectLatestDocumentResult(doc, identityVerification))
.map(DocumentResultEntity::getExtractedData)
.filter(data -> !DocumentSubmitResult.NO_DATA_EXTRACTED.equals(data))
.toList();
}

private static DocumentResultEntity selectLatestDocumentResult(final DocumentVerificationEntity documentVerificationEntity, final IdentityVerificationEntity identityVerification) {
return documentVerificationEntity.getResults().stream()
.findFirst()
.orElseThrow(() -> new IllegalStateException("Missing document result for %s of %s".formatted(documentVerificationEntity, identityVerification)));
}

private static String fetchVerificationId(final IdentityVerificationEntity identityVerification, final Set<DocumentVerificationEntity> documents) {
final Set<String> verificationIds = documents.stream()
.map(DocumentVerificationEntity::getVerificationId)
.collect(toSet());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.wultra.core.annotations.PublicApi;
import lombok.*;

import java.util.List;

/**
* Request object for {@link OnboardingProvider#evaluateClient(EvaluateClientRequest)}.
*
Expand All @@ -45,4 +47,11 @@ public final class EvaluateClientRequest {

@NonNull
private String verificationId;

private String provider;

/**
* Data extracted from each document/page. Format is defined by the document verification provider used.
*/
private List<String> extractedData;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import lombok.Data;

import java.util.List;

/**
* Request object for client evaluation.
*
Expand All @@ -39,4 +41,9 @@ class ClientEvaluateRequestDto {
private String verificationId;

private String provider;

/**
* Data extracted from each document/page. Format is defined by the document verification provider used.
*/
private List<String> extractedData;
}
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ private static ClientEvaluateRequestDto convert(final EvaluateClientRequest sour
target.setIdentityVerificationId(source.getIdentityVerificationId());
target.setUserId(source.getUserId());
target.setVerificationId(source.getVerificationId());
target.setProvider(source.getProvider());
target.setExtractedData(source.getExtractedData());
return target;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ enrollment-server-onboarding.onboarding-process.max-error-score=15

# Client Evaluation Configuration
enrollment-server-onboarding.client-evaluation.max-failed-attempts=5
enrollment-server-onboarding.client-evaluation.include-extracted-data=false

# Identity Verification Configuration
enrollment-server-onboarding.identity-verification.enabled=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

import com.wultra.app.enrollmentserver.model.enumeration.DocumentStatus;
import com.wultra.app.enrollmentserver.model.enumeration.ErrorOrigin;
import com.wultra.app.enrollmentserver.model.integration.DocumentSubmitResult;
import com.wultra.app.enrollmentserver.model.integration.OwnerId;
import com.wultra.app.onboardingserver.common.database.entity.DocumentResultEntity;
import com.wultra.app.onboardingserver.common.database.entity.DocumentVerificationEntity;
import com.wultra.app.onboardingserver.common.database.entity.IdentityVerificationEntity;
import com.wultra.app.onboardingserver.common.service.AuditService;
Expand All @@ -34,6 +36,7 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;
import java.util.Set;
import java.util.UUID;

Expand Down Expand Up @@ -71,12 +74,15 @@ class ClientEvaluationServiceTest {
void testProcessClientEvaluation_successful() throws Exception {
when(identityVerificationConfig.getClientEvaluationMaxFailedAttempts())
.thenReturn(1);
when(identityVerificationConfig.isSendingExtractedDataEnabled())
.thenReturn(true);

final EvaluateClientRequest evaluateClientRequest = EvaluateClientRequest.builder()
.processId("p1")
.userId("u1")
.identityVerificationId("i1")
.verificationId("v1")
.extractedData(List.of("d1_data"))
.build();
final EvaluateClientResponse evaluateClientResponse = EvaluateClientResponse.builder()
.accepted(true)
Expand All @@ -90,8 +96,8 @@ void testProcessClientEvaluation_successful() throws Exception {
identityVerification.setUserId("u1");
identityVerification.setPhase(CLIENT_EVALUATION);
identityVerification.setDocumentVerifications(Set.of(
createDocumentVerification("d1", DocumentStatus.ACCEPTED, "v1"),
createDocumentVerification("d2", DocumentStatus.ACCEPTED, "v1"),
createDocumentVerificationWithResults("d1", DocumentStatus.ACCEPTED, "v1", "d1_data"),
createDocumentVerificationWithResults("d2", DocumentStatus.ACCEPTED, "v1", DocumentSubmitResult.NO_DATA_EXTRACTED),
createDocumentVerification("d3", DocumentStatus.DISPOSED, "v2")));

final OwnerId ownerId = new OwnerId();
Expand Down Expand Up @@ -166,4 +172,13 @@ private static DocumentVerificationEntity createDocumentVerification(final Strin
documentVerification.setUsedForVerification(true);
return documentVerification;
}

private static DocumentVerificationEntity createDocumentVerificationWithResults(final String id, final DocumentStatus status, final String verificationId, final String extractedData) {
final DocumentResultEntity documentResult = new DocumentResultEntity();
documentResult.setExtractedData(extractedData);

final DocumentVerificationEntity documentVerification = createDocumentVerification(id, status, verificationId);
documentVerification.setResults(Set.of(documentResult));
return documentVerification;
}
}

0 comments on commit b783099

Please sign in to comment.