diff --git a/pom.xml b/pom.xml index 48e9111ca..a66d16099 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3 pom diff --git a/powerauth-admin/pom.xml b/powerauth-admin/pom.xml index 9e8692bc5..4a7bda118 100644 --- a/powerauth-admin/pom.xml +++ b/powerauth-admin/pom.xml @@ -11,7 +11,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3 diff --git a/powerauth-client-model/pom.xml b/powerauth-client-model/pom.xml index 18b0d35af..1e2df1809 100644 --- a/powerauth-client-model/pom.xml +++ b/powerauth-client-model/pom.xml @@ -28,7 +28,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3 diff --git a/powerauth-fido2-model/pom.xml b/powerauth-fido2-model/pom.xml index 5420724eb..34c0fa4b3 100644 --- a/powerauth-fido2-model/pom.xml +++ b/powerauth-fido2-model/pom.xml @@ -7,7 +7,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3 powerauth-fido2-model diff --git a/powerauth-fido2/pom.xml b/powerauth-fido2/pom.xml index 40d6a7247..1dd69b45b 100644 --- a/powerauth-fido2/pom.xml +++ b/powerauth-fido2/pom.xml @@ -27,7 +27,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3 diff --git a/powerauth-java-server/pom.xml b/powerauth-java-server/pom.xml index 2b04df909..73107a3a0 100644 --- a/powerauth-java-server/pom.xml +++ b/powerauth-java-server/pom.xml @@ -29,7 +29,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3 diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java index 577cbef17..2e9c5083c 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java @@ -374,7 +374,7 @@ public OperationUserActionResponse attemptApproveOperation(OperationApproveReque final String expectedUserId = operationEntity.getUserId(); final boolean activationIdMatches = activationIdMatches(request, operationEntity.getActivationId()); final boolean operationShouldFail = operationApprovalCustomizer.operationShouldFail(operationEntity, request); - if (expectedUserId == null || expectedUserId.equals(userId) // correct user approved the operation + if ((expectedUserId == null || expectedUserId.equals(userId)) // correct user approved the operation && 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 @@ -419,7 +419,6 @@ && proximityCheckPassed(proximityCheckResult) final Long maxFailureCount = operationEntity.getMaxFailureCount(); if (failureCount < maxFailureCount) { - operationEntity.setUserId(userId); operationEntity.setFailureCount(failureCount); operationEntity.setAdditionalData(mapMerge(operationEntity.getAdditionalData(), additionalData)); @@ -450,7 +449,6 @@ && proximityCheckPassed(proximityCheckResult) response.setOperation(operationDetailResponse); return response; } else { - operationEntity.setUserId(userId); operationEntity.setStatus(OperationStatusDo.FAILED); operationEntity.setTimestampFinalized(currentTimestamp); operationEntity.setFailureCount(maxFailureCount); // just in case, set the failure count to max value @@ -535,7 +533,7 @@ public OperationUserActionResponse rejectOperation(OperationRejectRequest reques } final String expectedUserId = operationEntity.getUserId(); - if (expectedUserId == null || expectedUserId.equals(userId) // correct user rejects the operation + if ((expectedUserId == null || expectedUserId.equals(userId)) // correct user rejects the operation && operationEntity.getApplications().contains(application.get())) { // operation is rejected by the expected application // Reject the operation diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java index 17b04ad7d..439c3d6ae 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java @@ -146,7 +146,10 @@ public AssertionChallenge approveAssertion(String challengeValue, AuthenticatorD @SuppressWarnings("unchecked") final List allowCredentials = (List) operationEntity.getAdditionalData().get(ATTR_ALLOW_CREDENTIALS); final String credentialId = (String) request.getAdditionalData().get(ATTR_CREDENTIAL_ID); - return allowCredentials == null || allowCredentials.isEmpty() || allowCredentials.contains(credentialId); + final boolean allowCredentialsMatches = allowCredentials == null // no allow credentials at all are expected (null) + || allowCredentials.isEmpty() // no allow credentials at all are expected (empty collection) + || allowCredentials.contains(credentialId); // used credential matches one of expected values + return !allowCredentialsMatches; }); final UserActionResult result = approveOperation.getResult(); final OperationDetailResponse operation = approveOperation.getOperation(); diff --git a/powerauth-java-server/src/test/java/com/wultra/powerauth/fido2/Fido2AuthenticatorTest.java b/powerauth-java-server/src/test/java/com/wultra/powerauth/fido2/Fido2AuthenticatorTest.java index 54fb71047..1082bdb3a 100644 --- a/powerauth-java-server/src/test/java/com/wultra/powerauth/fido2/Fido2AuthenticatorTest.java +++ b/powerauth-java-server/src/test/java/com/wultra/powerauth/fido2/Fido2AuthenticatorTest.java @@ -544,7 +544,7 @@ private void createOperationTemplate() throws Exception { templateCreateRequest.setDataTemplate("A2"); templateCreateRequest.setMaxFailureCount(5L); templateCreateRequest.setExpiration(300L); - templateCreateRequest.getSignatureType().add(SignatureType.POSSESSION_KNOWLEDGE); + templateCreateRequest.getSignatureType().add(SignatureType.POSSESSION); operationTemplateService.createOperationTemplate(templateCreateRequest); } diff --git a/powerauth-java-server/src/test/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehaviorTest.java b/powerauth-java-server/src/test/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehaviorTest.java index 40ed1d602..98425b76d 100644 --- a/powerauth-java-server/src/test/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehaviorTest.java +++ b/powerauth-java-server/src/test/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehaviorTest.java @@ -699,6 +699,108 @@ void testParsingDeviceOperationCancelDetail() throws Exception { assertEquals(expectedDevice, detailResponse.getAdditionalData().get("device")); } + @Test + void testAnonymousOperationApprovedUserChanged() throws GenericServiceException { + final OperationCreateRequest operationCreateRequest = new OperationCreateRequest(); + operationCreateRequest.setApplications(List.of("PA_Tests")); + operationCreateRequest.setTemplateName("test-template"); + final OperationDetailResponse operation = operationService.createOperation(operationCreateRequest); + final OperationApproveRequest approveRequest = new OperationApproveRequest(); + approveRequest.setOperationId(operation.getId()); + approveRequest.setUserId("test_user"); + approveRequest.setData("A2"); + approveRequest.setApplicationId("PA_Tests"); + approveRequest.setSignatureType(SignatureType.POSSESSION_KNOWLEDGE); + final OperationUserActionResponse response = operationService.attemptApproveOperation(approveRequest); + assertEquals(UserActionResult.APPROVED, response.getResult()); + final OperationDetailRequest detailRequest = new OperationDetailRequest(); + detailRequest.setOperationId(operation.getId()); + final OperationDetailResponse operationDetail = operationService.operationDetail(detailRequest); + assertEquals("test_user", operationDetail.getUserId()); + } + + @Test + void testAnonymousOperationFailedApproveUserNotChanged() throws GenericServiceException { + final OperationCreateRequest operationCreateRequest = new OperationCreateRequest(); + operationCreateRequest.setApplications(List.of("PA_Tests")); + operationCreateRequest.setTemplateName("test-template"); + final OperationDetailResponse operation = operationService.createOperation(operationCreateRequest); + final OperationApproveRequest approveRequest = new OperationApproveRequest(); + approveRequest.setOperationId(operation.getId()); + approveRequest.setUserId("invalid_user"); + approveRequest.setData("invalid_data"); + approveRequest.setApplicationId("PA_Tests"); + approveRequest.setSignatureType(SignatureType.POSSESSION_KNOWLEDGE); + final OperationUserActionResponse response = operationService.attemptApproveOperation(approveRequest); + assertEquals(UserActionResult.APPROVAL_FAILED, response.getResult()); + final OperationDetailRequest detailRequest = new OperationDetailRequest(); + detailRequest.setOperationId(operation.getId()); + final OperationDetailResponse operationDetail = operationService.operationDetail(detailRequest); + assertNull(operationDetail.getUserId()); + } + + @Test + void testAnonymousOperationFailedOperationUserNotChanged() throws GenericServiceException { + final OperationCreateRequest operationCreateRequest = new OperationCreateRequest(); + operationCreateRequest.setApplications(List.of("PA_Tests")); + operationCreateRequest.setTemplateName("test-template"); + final OperationDetailResponse operation = operationService.createOperation(operationCreateRequest); + for (int i = 0; i < 5; i++) { + final OperationApproveRequest approveRequest = new OperationApproveRequest(); + approveRequest.setOperationId(operation.getId()); + approveRequest.setUserId("invalid_user"); + approveRequest.setData("invalid_data"); + approveRequest.setApplicationId("PA_Tests"); + approveRequest.setSignatureType(SignatureType.POSSESSION_KNOWLEDGE); + final OperationUserActionResponse response = operationService.attemptApproveOperation(approveRequest); + if (i == 4) { + assertEquals(UserActionResult.OPERATION_FAILED, response.getResult()); + } else { + assertEquals(UserActionResult.APPROVAL_FAILED, response.getResult()); + } + } + final OperationDetailRequest detailRequest = new OperationDetailRequest(); + detailRequest.setOperationId(operation.getId()); + final OperationDetailResponse operationDetail = operationService.operationDetail(detailRequest); + assertNull(operationDetail.getUserId()); + } + + @Test + void testAnonymousOperationRejectUserChanged() throws GenericServiceException { + final OperationCreateRequest operationCreateRequest = new OperationCreateRequest(); + operationCreateRequest.setApplications(List.of("PA_Tests")); + operationCreateRequest.setTemplateName("test-template"); + final OperationDetailResponse operation = operationService.createOperation(operationCreateRequest); + final OperationRejectRequest rejectRequest = new OperationRejectRequest(); + rejectRequest.setOperationId(operation.getId()); + rejectRequest.setUserId("test_user"); + rejectRequest.setApplicationId("PA_Tests"); + final OperationUserActionResponse response = operationService.rejectOperation(rejectRequest); + assertEquals(UserActionResult.REJECTED, response.getResult()); + final OperationDetailRequest detailRequest = new OperationDetailRequest(); + detailRequest.setOperationId(operation.getId()); + final OperationDetailResponse operationDetail = operationService.operationDetail(detailRequest); + assertEquals("test_user", operationDetail.getUserId()); + } + + @Test + void testAnonymousOperationRejectFailedUserNotChanged() throws GenericServiceException { + final OperationCreateRequest operationCreateRequest = new OperationCreateRequest(); + operationCreateRequest.setApplications(List.of("PA_Tests")); + operationCreateRequest.setTemplateName("test-template"); + final OperationDetailResponse operation = operationService.createOperation(operationCreateRequest); + final OperationRejectRequest rejectRequest = new OperationRejectRequest(); + rejectRequest.setOperationId(operation.getId()); + rejectRequest.setUserId("test_user"); + rejectRequest.setApplicationId(APP_ID); + final OperationUserActionResponse response = operationService.rejectOperation(rejectRequest); + assertEquals(UserActionResult.REJECT_FAILED, response.getResult()); + final OperationDetailRequest detailRequest = new OperationDetailRequest(); + detailRequest.setOperationId(operation.getId()); + final OperationDetailResponse operationDetail = operationService.operationDetail(detailRequest); + assertNull(operationDetail.getUserId()); + } + private void createApplication() throws GenericServiceException { boolean appExists = applicationService.getApplicationList().getApplications().stream() .anyMatch(app -> app.getApplicationId().equals(APP_ID)); diff --git a/powerauth-rest-client-spring/pom.xml b/powerauth-rest-client-spring/pom.xml index 2fe385c1e..fdef654fa 100644 --- a/powerauth-rest-client-spring/pom.xml +++ b/powerauth-rest-client-spring/pom.xml @@ -28,7 +28,7 @@ io.getlime.security powerauth-server-parent - 1.8.2 + 1.8.3