Skip to content

Commit e3aa748

Browse files
Fix: don't allow retry signature with revoked VC (#187)
* update version and changelog * fix(CredentialSignerWorkflowImpl): add condition to check if credential procedure that is being re-signed has status PEND_SIGNATURE * add testing * create new CredentialProcedureInvalidStatusException to throw it in CredentialSignerWorkflowImpl.retrySignUnsignedCredential * create new CredentialProcedureNotFoundException to throw it in CredentialSignerWorkflowImpl.retrySignUnsignedCredential * enhance changelog entry * rename 'backofficePdp' > 'backofficePdpService'
1 parent 73b0f1b commit e3aa748

File tree

16 files changed

+228
-156
lines changed

16 files changed

+228
-156
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [v2.2.3](https://github.com/in2workspace/in2-issuer-api/releases/tag/v2.2.3)
8+
### Fixed
9+
- Prevent retrying the signature process when the credential procedure is not in PEND_SIGNATURE status.
10+
711
## [v2.2.2](https://github.com/in2workspace/in2-issuer-api/releases/tag/v2.2.2)
812
### Changed
913
- Add org ID validation for notification and async signature flows.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugins {
1212

1313
group = 'es.in2'
1414

15-
version = '2.2.2'
15+
version = '2.2.3'
1616

1717
java {
1818
sourceCompatibility = '17'

src/main/java/es/in2/issuer/backend/backoffice/application/workflow/impl/CredentialStatusWorkflowImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.fasterxml.jackson.databind.JsonNode;
66
import com.fasterxml.jackson.databind.ObjectMapper;
77
import es.in2.issuer.backend.backoffice.application.workflow.CredentialStatusWorkflow;
8-
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdp;
8+
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdpService;
99
import es.in2.issuer.backend.backoffice.domain.service.CredentialStatusAuthorizationService;
1010
import es.in2.issuer.backend.backoffice.domain.service.CredentialStatusService;
1111
import es.in2.issuer.backend.backoffice.domain.exception.InvalidStatusException;
@@ -31,7 +31,7 @@ public class CredentialStatusWorkflowImpl implements CredentialStatusWorkflow {
3131

3232
private final CredentialStatusService credentialStatusService;
3333
private final AccessTokenService accessTokenService;
34-
private final BackofficePdp backofficePdp;
34+
private final BackofficePdpService backofficePdpService;
3535
private final CredentialStatusAuthorizationService credentialStatusAuthorizationService;
3636
private final CredentialProcedureService credentialProcedureService;
3737
private final ObjectMapper objectMapper;
@@ -49,7 +49,7 @@ public Flux<String> getCredentialsByListId(String processId, int listId) {
4949
@Override
5050
public Mono<Void> revokeCredential(String processId, String bearerToken, String credentialProcedureId, int listId) {
5151
return accessTokenService.getCleanBearerToken(bearerToken)
52-
.flatMap(token -> backofficePdp.validateRevokeCredential(processId, token, credentialProcedureId)
52+
.flatMap(token -> backofficePdpService.validateRevokeCredential(processId, token, credentialProcedureId)
5353
.then(credentialProcedureService.getCredentialProcedureById(credentialProcedureId))
5454
)
5555
.flatMap(credential -> validateStatus(credential.getCredentialStatus())
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import reactor.core.publisher.Mono;
44

5-
public interface BackofficePdp {
5+
public interface BackofficePdpService {
66

77
Mono<Void> validateSignCredential(String processId, String token, String credentialProcedureId);
88

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.nimbusds.jose.Payload;
44
import com.nimbusds.jwt.SignedJWT;
5-
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdp;
5+
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdpService;
66
import es.in2.issuer.backend.shared.domain.exception.JWTParsingException;
77
import es.in2.issuer.backend.shared.domain.exception.UnauthorizedRoleException;
88
import es.in2.issuer.backend.shared.domain.service.JWTService;
@@ -24,7 +24,7 @@
2424
@Service
2525
@Slf4j
2626
@RequiredArgsConstructor
27-
public class BackofficePdpImpl implements BackofficePdp {
27+
public class BackofficePdpServiceImpl implements BackofficePdpService {
2828

2929
private final AppConfig appConfig;
3030
private final JWTService jwtService;

src/main/java/es/in2/issuer/backend/backoffice/domain/service/impl/NotificationServiceImpl.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
package es.in2.issuer.backend.backoffice.domain.service.impl;
22

3-
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdp;
3+
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdpService;
44
import es.in2.issuer.backend.backoffice.domain.service.NotificationService;
55
import es.in2.issuer.backend.shared.domain.exception.EmailCommunicationException;
66
import es.in2.issuer.backend.shared.domain.service.*;
77
import es.in2.issuer.backend.shared.infrastructure.config.AppConfig;
88
import lombok.RequiredArgsConstructor;
99
import lombok.extern.slf4j.Slf4j;
10-
import org.springframework.http.HttpStatus;
11-
import org.springframework.security.access.AccessDeniedException;
1210
import org.springframework.stereotype.Service;
13-
import org.springframework.web.server.ResponseStatusException;
1411
import reactor.core.publisher.Mono;
1512

1613
import static es.in2.issuer.backend.backoffice.domain.util.Constants.*;
@@ -22,7 +19,7 @@ public class NotificationServiceImpl implements NotificationService {
2219

2320
private final AppConfig appConfig;
2421
private final AccessTokenService accessTokenService;
25-
private final BackofficePdp backofficePdp;
22+
private final BackofficePdpService backofficePdpService;
2623
private final EmailService emailService;
2724
private final CredentialProcedureService credentialProcedureService;
2825
private final DeferredCredentialMetadataService deferredCredentialMetadataService;
@@ -33,7 +30,7 @@ public Mono<Void> sendNotification(String processId, String procedureId, String
3330
log.info("sendNotification processId={} organizationId={} token={}", processId, bearerToken, procedureId);
3431

3532
return accessTokenService.getCleanBearerToken(bearerToken)
36-
.flatMap(token -> backofficePdp.validateSendReminder(processId, token, procedureId)
33+
.flatMap(token -> backofficePdpService.validateSendReminder(processId, token, procedureId)
3734
.then(credentialProcedureService.getCredentialProcedureById(procedureId))
3835
)
3936
.zipWhen(credentialProcedure -> credentialProcedureService.getCredentialOfferEmailInfoByProcedureId(procedureId))

src/main/java/es/in2/issuer/backend/shared/application/workflow/impl/CredentialSignerWorkflowImpl.java

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
package es.in2.issuer.backend.shared.application.workflow.impl;
22

3-
import com.fasterxml.jackson.annotation.JsonProperty;
4-
import com.fasterxml.jackson.databind.JsonNode;
5-
import com.fasterxml.jackson.databind.ObjectMapper;
3+
64
import com.upokecenter.cbor.CBORObject;
7-
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdp;
5+
import es.in2.issuer.backend.backoffice.application.workflow.policies.BackofficePdpService;
86
import es.in2.issuer.backend.shared.application.workflow.CredentialSignerWorkflow;
97
import es.in2.issuer.backend.shared.application.workflow.DeferredCredentialWorkflow;
108
import es.in2.issuer.backend.shared.domain.exception.Base45Exception;
9+
import es.in2.issuer.backend.shared.domain.exception.CredentialProcedureInvalidStatusException;
10+
import es.in2.issuer.backend.shared.domain.exception.CredentialProcedureNotFoundException;
1111
import es.in2.issuer.backend.shared.domain.model.dto.*;
1212
import es.in2.issuer.backend.shared.domain.model.dto.credential.LabelCredential;
1313
import es.in2.issuer.backend.shared.domain.model.dto.credential.lear.employee.LEARCredentialEmployee;
1414
import es.in2.issuer.backend.shared.domain.model.dto.credential.lear.machine.LEARCredentialMachine;
15+
import es.in2.issuer.backend.shared.domain.model.enums.CredentialStatusEnum;
1516
import es.in2.issuer.backend.shared.domain.model.enums.SignatureType;
1617
import es.in2.issuer.backend.shared.domain.service.*;
1718
import es.in2.issuer.backend.shared.domain.util.factory.IssuerFactory;
@@ -28,11 +29,8 @@
2829
import org.springframework.stereotype.Service;
2930
import reactor.core.publisher.Mono;
3031
import reactor.core.scheduler.Schedulers;
31-
import reactor.util.function.Tuples;
3232

3333
import java.io.ByteArrayOutputStream;
34-
import java.sql.Timestamp;
35-
import java.time.Instant;
3634
import java.util.Base64;
3735
import java.util.Collections;
3836
import java.util.List;
@@ -48,7 +46,7 @@
4846
public class CredentialSignerWorkflowImpl implements CredentialSignerWorkflow {
4947

5048
private final AccessTokenService accessTokenService;
51-
private final BackofficePdp backofficePdp;
49+
private final BackofficePdpService backofficePdpService;
5250
private final AppConfig appConfig;
5351
private final DeferredCredentialWorkflow deferredCredentialWorkflow;
5452
private final RemoteSignatureService remoteSignatureService;
@@ -204,20 +202,28 @@ public Mono<Void> retrySignUnsignedCredential(String processId, String authoriza
204202

205203
return accessTokenService.getCleanBearerToken(authorizationHeader)
206204
.flatMap(token ->
207-
backofficePdp.validateSignCredential(processId, token, procedureId)
205+
backofficePdpService.validateSignCredential(processId, token, procedureId)
208206
.then(Mono.just(token))
209207
.zipWhen(t -> accessTokenService.getMandateeEmail(authorizationHeader))
210-
.zipWhen(
211-
tuple2 -> accessTokenService.getOrganizationId(authorizationHeader),
212-
(tuple2, orgId) -> Tuples.of(tuple2.getT1(), tuple2.getT2(), orgId)
213-
)
214208
)
215-
.flatMap(tuple3 -> {
216-
String token = tuple3.getT1();
217-
String email = tuple3.getT2();
209+
.flatMap(tupleTokenEmail -> {
210+
String token = tupleTokenEmail.getT1();
211+
String email = tupleTokenEmail.getT2();
218212

219213
return credentialProcedureRepository.findByProcedureId(UUID.fromString(procedureId))
220-
.switchIfEmpty(Mono.error(new RuntimeException("Procedure not found")))
214+
.switchIfEmpty(Mono.error(new CredentialProcedureNotFoundException(
215+
"Credential procedure with ID " + procedureId + " was not found"
216+
)))
217+
.doOnNext(credentialProcedure ->
218+
log.info("ProcessID: {} - Current credential status: {}",
219+
processId, credentialProcedure.getCredentialStatus())
220+
)
221+
.filter(credentialProcedure ->
222+
credentialProcedure.getCredentialStatus() == CredentialStatusEnum.PEND_SIGNATURE
223+
)
224+
.switchIfEmpty(Mono.error(new CredentialProcedureInvalidStatusException(
225+
"Credential procedure with ID " + procedureId + " is not in PEND_SIGNATURE status"
226+
)))
221227
.flatMap(credentialProcedure -> {
222228
Mono<Void> updateDecodedCredentialMono =
223229
switch (credentialProcedure.getCredentialType()) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package es.in2.issuer.backend.shared.domain.exception;
2+
3+
public class CredentialProcedureInvalidStatusException extends RuntimeException {
4+
public CredentialProcedureInvalidStatusException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package es.in2.issuer.backend.shared.domain.exception;
2+
3+
public class CredentialProcedureNotFoundException extends RuntimeException {
4+
public CredentialProcedureNotFoundException(String message) {
5+
super(message);
6+
}
7+
}

src/main/java/es/in2/issuer/backend/shared/domain/util/GlobalErrorTypes.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ public enum GlobalErrorTypes {
2626
JWT_VERIFICATION("jwt_verification_error"),
2727
UNAUTHORIZED_ROLE("unauthorized_role"),
2828
EMAIL_COMMUNICATION("email_communication_error"),
29-
CREDENTIAL_SERIALIZATION("credential_serialization");
29+
CREDENTIAL_SERIALIZATION("credential_serialization"),
30+
CREDENTIAL_PROCEDURE_INVALID_STATUS("credential_procedure_invalid_status"),
31+
CREDENTIAL_PROCEDURE_NOT_FOUND("credential_procedure_not_found");
3032

3133
private final String code;
3234

0 commit comments

Comments
 (0)