Skip to content

Commit 8920f88

Browse files
committed
refactor: encryption parameters in schedules
1 parent 663b6c9 commit 8920f88

11 files changed

Lines changed: 125 additions & 20 deletions

src/main/java/fr/insee/genesis/controller/dto/KraftwerkExecutionScheduleInput.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public class KraftwerkExecutionScheduleInput {
2626
private DestinationType destinationType;
2727
private boolean addStates;
2828
private String destinationFolder;
29+
private boolean useAsymmetricEncryption;
30+
private boolean useSymmetricEncryption;
2931
private TrustParameters trustParameters;
3032
private Integer batchSize;
3133
}

src/main/java/fr/insee/genesis/controller/dto/ScheduleRequestDto.java

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

33
import com.fasterxml.jackson.annotation.JsonFormat;
44
import fr.insee.genesis.controller.utils.ExportType;
5+
import fr.insee.genesis.controller.validation.schedule.ValidScheduleRequest;
56
import fr.insee.genesis.domain.model.context.schedule.DestinationType;
67
import fr.insee.genesis.domain.model.surveyunit.Mode;
78
import io.swagger.v3.oas.annotations.media.Schema;
@@ -17,6 +18,7 @@
1718
@NoArgsConstructor
1819
@AllArgsConstructor
1920
@Schema(description = "Request used to schedule a Kraftwerk export workflow")
21+
@ValidScheduleRequest
2022
public class ScheduleRequestDto {
2123

2224
@NotBlank
@@ -47,7 +49,10 @@ public class ScheduleRequestDto {
4749
private DestinationType destinationType = DestinationType.APPLISHARE;
4850

4951
@Schema(defaultValue = "false")
50-
private boolean useEncryption = false;
52+
private boolean useSymmetricEncryption = false;
53+
54+
@Schema(defaultValue = "false")
55+
private boolean useAsymmetricEncryption = false;
5156

5257
@Schema(description = "Encryption vault path")
5358
private String encryptionVaultPath = "";

src/main/java/fr/insee/genesis/controller/dto/rawdata/ScheduleV2Dto.java renamed to src/main/java/fr/insee/genesis/controller/dto/rawdata/ScheduleResponseDto.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
@Builder
1616
@NoArgsConstructor
1717
@AllArgsConstructor
18-
public class ScheduleV2Dto {
18+
public class ScheduleResponseDto {
1919

2020
private String scheduleUuid;
2121
private String collectionInstrumentId;
@@ -32,7 +32,8 @@ public class ScheduleV2Dto {
3232

3333
private Mode mode;
3434
private DestinationType destinationType;
35-
private boolean useEncryption;
35+
private boolean useAsymmetricEncryption;
36+
private boolean useSymmetricEncryption;
3637
private String encryptionVaultPath;
3738
private boolean useSignature;
3839
private boolean addStates;

src/main/java/fr/insee/genesis/controller/rest/ControllerExceptionHandler.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import org.springframework.dao.DuplicateKeyException;
44
import org.springframework.http.HttpStatus;
55
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.MethodArgumentNotValidException;
67
import org.springframework.web.bind.annotation.ExceptionHandler;
78
import org.springframework.web.bind.annotation.RestControllerAdvice;
89

10+
import java.util.HashMap;
11+
import java.util.Map;
12+
913
@RestControllerAdvice
1014
public class ControllerExceptionHandler {
1115

@@ -15,4 +19,25 @@ public ResponseEntity<String> handleDuplicate(DuplicateKeyException ex) {
1519
.status(HttpStatus.CONFLICT)
1620
.body(ex.getMessage());
1721
}
22+
23+
@ExceptionHandler(MethodArgumentNotValidException.class)
24+
public ResponseEntity<?> handleValidationExceptions(MethodArgumentNotValidException ex) {
25+
26+
Map<String, String> errors = new HashMap<>();
27+
28+
ex.getBindingResult().getFieldErrors().forEach(error -> {
29+
errors.put(error.getField(), error.getDefaultMessage());
30+
});
31+
32+
ex.getBindingResult().getGlobalErrors().forEach(error -> {
33+
errors.put(error.getObjectName(), error.getDefaultMessage());
34+
});
35+
36+
Map<String, Object> body = new HashMap<>();
37+
body.put("status", 400);
38+
body.put("message", "Validation failed");
39+
body.put("errors", errors);
40+
41+
return ResponseEntity.badRequest().body(body);
42+
}
1843
}

src/main/java/fr/insee/genesis/controller/rest/DataProcessingContextController.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import fr.insee.genesis.controller.dto.KraftwerkExecutionScheduleInput;
55
import fr.insee.genesis.controller.dto.ScheduleDto;
66
import fr.insee.genesis.controller.dto.ScheduleRequestDto;
7-
import fr.insee.genesis.controller.dto.rawdata.ScheduleV2Dto;
7+
import fr.insee.genesis.controller.dto.rawdata.ScheduleResponseDto;
88
import fr.insee.genesis.domain.model.context.schedule.ServiceToCall;
99
import fr.insee.genesis.domain.model.context.schedule.TrustParameters;
1010
import fr.insee.genesis.domain.ports.api.DataProcessingContextApiPort;
@@ -109,7 +109,7 @@ public ResponseEntity<Object> createScheduleV2(
109109
) {
110110
try {
111111
TrustParameters trustParameters = null;
112-
if (request.isUseEncryption()) {
112+
if (request.isUseAsymmetricEncryption()) {
113113
trustParameters = new TrustParameters(
114114
fileUtils.getKraftwerkOutFolder(request.getCollectionInstrumentId()),
115115
"",
@@ -243,7 +243,7 @@ public ResponseEntity<Object> updateScheduleV2(
243243
) {
244244
try {
245245
TrustParameters trustParameters = null;
246-
if (request.isUseEncryption()) {
246+
if (request.isUseAsymmetricEncryption()) {
247247
trustParameters = new TrustParameters(
248248
fileUtils.getKraftwerkOutFolder(collectionInstrumentId),
249249
"",
@@ -263,6 +263,8 @@ public ResponseEntity<Object> updateScheduleV2(
263263
.destinationType(request.getDestinationType())
264264
.addStates(request.isAddStates())
265265
.destinationFolder(request.getDestinationFolder())
266+
.useAsymmetricEncryption(request.isUseAsymmetricEncryption())
267+
.useSymmetricEncryption(request.isUseSymmetricEncryption())
266268
.trustParameters(trustParameters)
267269
.batchSize(request.getBatchSize())
268270
.build();
@@ -308,7 +310,7 @@ public ResponseEntity<Object> getAllSchedulesV2() {
308310
public ResponseEntity<Object> getAllSchedulesV3() {
309311
log.debug("Got GET all schedules V2 request");
310312

311-
List<ScheduleV2Dto> schedules = dataProcessingContextApiPort.getAllSchedulesV2();
313+
List<ScheduleResponseDto> schedules = dataProcessingContextApiPort.getAllSchedulesV2();
312314

313315
log.info("Returning {} V2 schedule documents...", schedules.size());
314316
return ResponseEntity.ok(schedules);
@@ -320,7 +322,7 @@ public ResponseEntity<Object> getAllSchedulesV3() {
320322
public ResponseEntity<Object> getSchedulesV2ByCollectionInstrumentId(
321323
@PathVariable("collectionInstrumentId") String collectionInstrumentId
322324
) {
323-
List<ScheduleV2Dto> schedules =
325+
List<ScheduleResponseDto> schedules =
324326
dataProcessingContextApiPort.getSchedulesV2ByCollectionInstrumentId(collectionInstrumentId);
325327

326328
return ResponseEntity.ok(schedules);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package fr.insee.genesis.controller.validation.schedule;
2+
3+
import fr.insee.genesis.controller.dto.ScheduleRequestDto;
4+
import jakarta.validation.ConstraintValidator;
5+
import jakarta.validation.ConstraintValidatorContext;
6+
7+
public class ScheduleRequestValidator implements ConstraintValidator<ValidScheduleRequest, ScheduleRequestDto> {
8+
9+
@Override
10+
public boolean isValid(ScheduleRequestDto value, ConstraintValidatorContext context) {
11+
12+
if (value == null) {
13+
return true;
14+
}
15+
16+
boolean valid = true;
17+
18+
// Encryption rule
19+
if (value.isUseAsymmetricEncryption()) {
20+
if (value.getEncryptionVaultPath() == null || value.getEncryptionVaultPath().isBlank()) {
21+
addViolation(context, "encryptionVaultPath", "encryptionVaultPath is mandatory if useAsymetricEncryption=true");
22+
valid = false;
23+
}
24+
}
25+
26+
// Date rule
27+
if (value.getScheduleBeginDate() != null &&
28+
value.getScheduleEndDate() != null &&
29+
value.getScheduleBeginDate().isAfter(value.getScheduleEndDate())) {
30+
31+
addViolation(context, "scheduleEndDate",
32+
"scheduleEndDate should be after scheduleBeginDate");
33+
valid = false;
34+
}
35+
36+
return valid;
37+
}
38+
39+
private void addViolation(ConstraintValidatorContext context, String field, String message) {
40+
context.disableDefaultConstraintViolation();
41+
42+
context.buildConstraintViolationWithTemplate(message)
43+
.addPropertyNode(field)
44+
.addConstraintViolation();
45+
}
46+
47+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package fr.insee.genesis.controller.validation.schedule;
2+
3+
import jakarta.validation.Constraint;
4+
import jakarta.validation.Payload;
5+
6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
10+
11+
@Target(ElementType.TYPE)
12+
@Retention(RetentionPolicy.RUNTIME)
13+
@Constraint(validatedBy = ScheduleRequestValidator.class)
14+
public @interface ValidScheduleRequest {
15+
String message() default "Invalid schedule request";
16+
Class<?>[] groups() default {};
17+
Class<? extends Payload>[] payload() default {};
18+
}

src/main/java/fr/insee/genesis/domain/model/context/DataProcessingContextModel.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package fr.insee.genesis.domain.model.context;
22

33
import fr.insee.genesis.controller.dto.ScheduleDto;
4-
import fr.insee.genesis.controller.dto.rawdata.ScheduleV2Dto;
4+
import fr.insee.genesis.controller.dto.rawdata.ScheduleResponseDto;
55
import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule;
66
import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2;
77
import lombok.AllArgsConstructor;
@@ -44,14 +44,14 @@ public ScheduleDto toScheduleDto() {
4444
.build();
4545
}
4646

47-
public List<ScheduleV2Dto> toScheduleV2Dtos() {
47+
public List<ScheduleResponseDto> toScheduleResponseDtos() {
4848
if (kraftwerkExecutionScheduleV2List == null || kraftwerkExecutionScheduleV2List.isEmpty()) {
4949
return List.of();
5050
}
5151

5252
return kraftwerkExecutionScheduleV2List.stream()
5353
.filter(schedule -> schedule != null && schedule.getScheduleUuid() != null)
54-
.map(schedule -> ScheduleV2Dto.builder()
54+
.map(schedule -> ScheduleResponseDto.builder()
5555
.scheduleUuid(schedule.getScheduleUuid())
5656
.collectionInstrumentId(getResolvedCollectionInstrumentId())
5757
.lastExecution(lastExecution)
@@ -60,7 +60,8 @@ public List<ScheduleV2Dto> toScheduleV2Dtos() {
6060
.scheduleBeginDate(schedule.getScheduleBeginDate())
6161
.scheduleEndDate(schedule.getScheduleEndDate())
6262
.mode(schedule.getMode())
63-
.useEncryption(schedule.getTrustParameters() != null)
63+
.useSymmetricEncryption(schedule.isUseSymmetricEncryption())
64+
.useAsymmetricEncryption(schedule.getTrustParameters() != null)
6465
.encryptionVaultPath(
6566
schedule.getTrustParameters() != null
6667
? schedule.getTrustParameters().getVaultPath()

src/main/java/fr/insee/genesis/domain/model/context/schedule/KraftwerkExecutionScheduleV2.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class KraftwerkExecutionScheduleV2 {
2828
private DestinationType destinationType;
2929
private boolean addStates;
3030
private String destinationFolder;
31+
private boolean useSymmetricEncryption;
3132
private TrustParameters trustParameters;
3233
private Integer batchSize;
3334
}

src/main/java/fr/insee/genesis/domain/ports/api/DataProcessingContextApiPort.java

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

33
import fr.insee.genesis.controller.dto.KraftwerkExecutionScheduleInput;
44
import fr.insee.genesis.controller.dto.ScheduleDto;
5-
import fr.insee.genesis.controller.dto.rawdata.ScheduleV2Dto;
5+
import fr.insee.genesis.controller.dto.rawdata.ScheduleResponseDto;
66
import fr.insee.genesis.domain.model.context.DataProcessingContextModel;
77
import fr.insee.genesis.domain.model.context.schedule.ServiceToCall;
88
import fr.insee.genesis.domain.model.context.schedule.TrustParameters;
@@ -45,11 +45,11 @@ void saveKraftwerkExecutionScheduleByCollectionInstrumentId(String collectionIns
4545

4646
void deleteSchedulesV2ByCollectionInstrumentId(String collectionInstrumentId) throws GenesisException;
4747

48-
List<ScheduleV2Dto> getSchedulesV2ByCollectionInstrumentId(String collectionInstrumentId);
48+
List<ScheduleResponseDto> getSchedulesV2ByCollectionInstrumentId(String collectionInstrumentId);
4949

5050
List<ScheduleDto> getAllSchedules();
5151

52-
List<ScheduleV2Dto> getAllSchedulesV2();
52+
List<ScheduleResponseDto> getAllSchedulesV2();
5353

5454
void deleteExpiredSchedules(String logFolder) throws GenesisException;
5555

0 commit comments

Comments
 (0)