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