From b3173f5016b36cbf9a4b41b0e2fece1981d80693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20=C4=8Cern=C3=BD?= Date: Fri, 13 Dec 2024 14:11:08 +0100 Subject: [PATCH 1/2] Fix #1803: Ensure the getOperation doesn't change operation status --- .../tasks/OperationServiceBehavior.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) 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 2e9c5083c..32279e724 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 @@ -763,11 +763,10 @@ public OperationDetailResponse operationDetail(OperationDetailRequest request) t }); final String userId = request.getUserId(); - final OperationEntity operationEntity = expireOperation( - claimOperation(operation, userId, currentTimestamp), - currentTimestamp - ); + final OperationEntity operationEntity = + claimOperation(operation, userId, currentTimestamp); final OperationDetailResponse operationDetailResponse = convertFromEntityAndFillOtp(operationEntity); + expireOperation(operationDetailResponse,currentTimestamp); extendAndSetOperationDetailData(operationDetailResponse); return operationDetailResponse; } catch (GenericServiceException ex) { @@ -1013,6 +1012,17 @@ private OperationEntity expireOperation(OperationEntity operationEntity, Date cu return operationEntity; } + private void expireOperation(OperationDetailResponse operation, Date currentTimestamp) throws GenericServiceException { + // Operation is still pending and timestamp is after the expiration. + if (OperationStatus.PENDING.equals(operation.getStatus()) + && operation.getTimestampExpires().before(currentTimestamp)) { + // Operation status is persisted only using background service to avoid database deadlocks, + // because two concurrent UPDATE queries can be executed at the same time. + // The status in the database may be updated few seconds later for this reason. + operation.setStatus(OperationStatus.EXPIRED); + } + } + private boolean factorsAcceptable(@NotNull OperationEntity operation, PowerAuthSignatureTypes usedFactor) { final String operationId = operation.getId(); final PowerAuthSignatureTypes[] allowedFactors = operation.getSignatureType(); From 8e7fbc9529204e3a6c8c9bcacb1721965d393ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20=C4=8Cern=C3=BD?= Date: Fri, 13 Dec 2024 14:27:35 +0100 Subject: [PATCH 2/2] renaming method for clarity --- .../service/behavior/tasks/OperationServiceBehavior.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 32279e724..d367f0e88 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 @@ -766,7 +766,7 @@ public OperationDetailResponse operationDetail(OperationDetailRequest request) t final OperationEntity operationEntity = claimOperation(operation, userId, currentTimestamp); final OperationDetailResponse operationDetailResponse = convertFromEntityAndFillOtp(operationEntity); - expireOperation(operationDetailResponse,currentTimestamp); + markOperationExpired(operationDetailResponse, currentTimestamp); extendAndSetOperationDetailData(operationDetailResponse); return operationDetailResponse; } catch (GenericServiceException ex) { @@ -1012,7 +1012,7 @@ private OperationEntity expireOperation(OperationEntity operationEntity, Date cu return operationEntity; } - private void expireOperation(OperationDetailResponse operation, Date currentTimestamp) throws GenericServiceException { + private void markOperationExpired(OperationDetailResponse operation, Date currentTimestamp) throws GenericServiceException { // Operation is still pending and timestamp is after the expiration. if (OperationStatus.PENDING.equals(operation.getStatus()) && operation.getTimestampExpires().before(currentTimestamp)) {