Skip to content

Commit

Permalink
Fix #1795: Validate user ID for operation approve and reject before u…
Browse files Browse the repository at this point in the history
…pdating operation (#1796)
  • Loading branch information
romanstrobl authored Dec 3, 2024
1 parent ee6c266 commit 6ffadee
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,12 @@ public OperationUserActionResponse attemptApproveOperation(OperationApproveReque

final String expectedUserId = operationEntity.getUserId();
if (expectedUserId == null) {
logger.warn("Operation ID: {} cannot be approved, because user ID is not set.", operationId);
logger.warn("Operation with operationId: {} cannot be approved, because user ID is not set.", operationId);
throw localizationProvider.buildExceptionForCode(ServiceError.OPERATION_APPROVE_FAILURE);
}

if (!expectedUserId.equals(userId)) {
logger.warn("Operation with operationId: {} cannot be approved, because user ID from the request '{}' does not match user ID from the operation '{}'.", operationId, userId, expectedUserId);
throw localizationProvider.buildExceptionForCode(ServiceError.OPERATION_APPROVE_FAILURE);
}

Expand All @@ -380,8 +385,7 @@ public OperationUserActionResponse attemptApproveOperation(OperationApproveReque
final ProximityCheckResult proximityCheckResult = fetchProximityCheckResult(operationEntity, request, currentInstant);
final boolean activationIdMatches = activationIdMatches(request, operationEntity.getActivationId());
final boolean operationShouldFail = operationApprovalCustomizer.operationShouldFail(operationEntity, request);
if (expectedUserId.equals(userId) // correct user approved the operation
&& operationEntity.getApplications().contains(application.get()) // operation is approved by the expected application
if (operationEntity.getApplications().contains(application.get()) // operation is approved by the expected application
&& isDataEqual(operationEntity, data) // operation data matched the expected value
&& factorsAcceptable(operationEntity, factorEnum) // auth factors are acceptable
&& operationEntity.getMaxFailureCount() > operationEntity.getFailureCount() // operation has sufficient attempts left (redundant check)
Expand Down Expand Up @@ -539,12 +543,16 @@ public OperationUserActionResponse rejectOperation(OperationRejectRequest reques

final String expectedUserId = operationEntity.getUserId();
if (expectedUserId == null) {
logger.warn("Operation ID: {} cannot be rejected, because user ID is not set.", operationId);
throw localizationProvider.buildExceptionForCode(ServiceError.OPERATION_APPROVE_FAILURE);
logger.warn("Operation with operationId: {} cannot be rejected, because user ID is not set.", operationId);
throw localizationProvider.buildExceptionForCode(ServiceError.OPERATION_REJECT_FAILURE);
}

if (!expectedUserId.equals(userId)) {
logger.warn("Operation with operationId: {} cannot be rejected, because user ID from the request '{}' does not match user ID from the operation '{}'.", operationId, userId, expectedUserId);
throw localizationProvider.buildExceptionForCode(ServiceError.OPERATION_REJECT_FAILURE);
}

if ((expectedUserId.equals(userId)) // correct user rejects the operation
&& operationEntity.getApplications().contains(application.get())) { // operation is rejected by the expected application
if (operationEntity.getApplications().contains(application.get())) { // operation is rejected by the expected application

// Reject the operation
operationEntity.setStatus(OperationStatusDo.REJECTED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,8 +747,8 @@ void testOperationApprovalFailDifferentUserId() throws GenericServiceException {
approveRequest.setData("A2");
approveRequest.setApplicationId("PA_Tests");
approveRequest.setSignatureType(SignatureType.POSSESSION_KNOWLEDGE);
final OperationUserActionResponse response = operationService.attemptApproveOperation(approveRequest);
assertEquals(UserActionResult.APPROVAL_FAILED, response.getResult());
final Exception exception = assertThrows(GenericServiceException.class, () -> operationService.attemptApproveOperation(approveRequest));
assertEquals("Operation cannot be approved.", exception.getMessage());
}

@Test
Expand All @@ -762,7 +762,7 @@ void testAnonymousOperationRejectError() throws GenericServiceException {
rejectRequest.setUserId("test_user");
rejectRequest.setApplicationId("PA_Tests");
final Exception exception = assertThrows(GenericServiceException.class, () -> operationService.rejectOperation(rejectRequest));
assertEquals("Operation cannot be approved.", exception.getMessage());
assertEquals("Operation cannot be rejected.", exception.getMessage());
}

@Test
Expand All @@ -776,8 +776,8 @@ void testOperationRejectFailedDifferentUserId() throws GenericServiceException {
rejectRequest.setOperationId(operation.getId());
rejectRequest.setUserId("test_user_2");
rejectRequest.setApplicationId("PA_Tests");
final OperationUserActionResponse response = operationService.rejectOperation(rejectRequest);
assertEquals(UserActionResult.REJECT_FAILED, response.getResult());
final Exception exception = assertThrows(GenericServiceException.class, () -> operationService.rejectOperation(rejectRequest));
assertEquals("Operation cannot be rejected.", exception.getMessage());
}

private void createApplication() throws GenericServiceException {
Expand Down

0 comments on commit 6ffadee

Please sign in to comment.