From f3595e2ce7e0c12ac35f751ca8c0c728f90c6206 Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Fri, 28 Aug 2020 11:35:00 +0200 Subject: [PATCH] Cleanups from feature/insert-manager This is the first PR to make the PR #213 somewhat smaller and more manageable. It takes only the cleanup parts of it. See #226 --- .../org/dpppt/backend/sdk/utils/README.md | 21 ++++++++ .../org/dpppt/backend/sdk/ws/config/README.md | 3 ++ .../sdk/ws/controller/DPPPTController.java | 23 +++++--- .../sdk/ws/controller/DebugController.java | 11 ++-- .../sdk/ws/controller/GaenController.java | 14 +++-- .../dpppt/backend/sdk/ws/controller/README.md | 3 ++ .../sdk/ws/security/JWTValidateRequest.java | 9 ++-- .../sdk/ws/security/NoValidateRequest.java | 4 +- .../dpppt/backend/sdk/ws/security/README.md | 1 + .../sdk/ws/security/ValidateRequest.java | 18 +++++-- .../ws/security/gaen/JWTValidateRequest.java | 20 ++++--- .../sdk/ws/security/signature/README.md | 1 + .../backend/sdk/ws/util/ValidationUtils.java | 52 +++++++++++++++++++ .../sdk/ws/controller/BaseControllerTest.java | 4 +- .../ws/controller/DPPPTControllerTest.java | 22 ++++---- .../sdk/ws/controller/GaenControllerTest.java | 47 ++++++++--------- .../sdk/ws/insertmanager/MockDataSource.java | 33 ++++++++++++ 17 files changed, 216 insertions(+), 70 deletions(-) create mode 100644 dpppt-backend-sdk/dpppt-backend-sdk-model/src/main/java/org/dpppt/backend/sdk/utils/README.md create mode 100644 dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/README.md create mode 100644 dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/README.md create mode 100644 dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/README.md create mode 100644 dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/signature/README.md create mode 100644 dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/insertmanager/MockDataSource.java diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-model/src/main/java/org/dpppt/backend/sdk/utils/README.md b/dpppt-backend-sdk/dpppt-backend-sdk-model/src/main/java/org/dpppt/backend/sdk/utils/README.md new file mode 100644 index 00000000..498d2557 --- /dev/null +++ b/dpppt-backend-sdk/dpppt-backend-sdk-model/src/main/java/org/dpppt/backend/sdk/utils/README.md @@ -0,0 +1,21 @@ +# UTC Instant + +## Why a new class? + +During the development of this project, various different time formats came into play. Mostly the 10 minute intervals used by GAEN and the default milliseconds used by the dp3t API. But time handling is hard. So `OffsetDateTimes` at UTC offsets were used, and sometimes `Dates` were needed, and some classes wanted different Objects and and and.... + +We ended up with a mess of 300 character lines, converting from one object into the other. For this reason we added this class, which gathers all usages and conversions we needed during development. It also should ensure that different people write the same code, by providing _one thing who times 'em all_. + +This also allowed us to the name the functions in a concise and natural way. The first example reads more natural than the second one. + +```java +if(UTCInstant.of(keyDate, GaenUnit.TenMinutes).isBeforeDateOf(UTCInstant.now().atStartOfDay().plusDays(2)) { + +} +``` + +```java +if(Instant.ofEpochMilli(Duration.of(10, GaenUnit.TenMinutes).toMillis()).isBefore(LocalDate.now().atStartOfDay().plusDays(2).toInstant(ZoneOffset.UTC))) { + +} +``` \ No newline at end of file diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/README.md b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/README.md new file mode 100644 index 00000000..1f95a99c --- /dev/null +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/README.md @@ -0,0 +1,3 @@ +# Configurations + +This package holds all possible configurations. For the Swiss-Covid App the cloud-configurations, together with the `MultipleJWTConfig` and the `ActuatorSecurity` are used. \ No newline at end of file diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DPPPTController.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DPPPTController.java index b7289c52..e26da265 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DPPPTController.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DPPPTController.java @@ -28,7 +28,9 @@ import org.dpppt.backend.sdk.model.proto.Exposed; import org.dpppt.backend.sdk.utils.UTCInstant; import org.dpppt.backend.sdk.ws.security.ValidateRequest; +import org.dpppt.backend.sdk.ws.security.ValidateRequest.ClaimIsBeforeOnsetException; import org.dpppt.backend.sdk.ws.security.ValidateRequest.InvalidDateException; +import org.dpppt.backend.sdk.ws.security.ValidateRequest.WrongScopeException; import org.dpppt.backend.sdk.ws.util.ValidationUtils; import org.dpppt.backend.sdk.ws.util.ValidationUtils.BadBatchReleaseTimeException; import org.springframework.http.CacheControl; @@ -114,19 +116,25 @@ public DPPPTController( + " + OS-Version", example = "ch.ubique.android.starsdk;1.0;iOS;13.3") String userAgent, - @AuthenticationPrincipal Object principal) - throws InvalidDateException { + @AuthenticationPrincipal Object principal) { var now = UTCInstant.now(); - if (!this.validateRequest.isValid(principal)) { - return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + long keyDate; + + try { + if (!this.validateRequest.isValid(principal)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + keyDate = this.validateRequest.validateKeyDate(now, principal, exposeeRequest); + } catch (WrongScopeException | ClaimIsBeforeOnsetException | InvalidDateException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); } + if (!validationUtils.isValidBase64Key(exposeeRequest.getKey())) { return new ResponseEntity<>("No valid base64 key", HttpStatus.BAD_REQUEST); } // TODO: should we give that information? Exposee exposee = new Exposee(); exposee.setKey(exposeeRequest.getKey()); - long keyDate = this.validateRequest.getKeyDate(now, principal, exposeeRequest); exposee.setKeyDate(keyDate); if (!this.validateRequest.isFakeRequest(principal, exposeeRequest)) { @@ -169,8 +177,9 @@ public DPPPTController( example = "ch.ubique.android.starsdk;1.0;iOS;13.3") String userAgent, @AuthenticationPrincipal Object principal) - throws InvalidDateException { + throws InvalidDateException, WrongScopeException, ClaimIsBeforeOnsetException { var now = UTCInstant.now(); + if (!this.validateRequest.isValid(principal)) { return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } @@ -183,7 +192,7 @@ public DPPPTController( Exposee exposee = new Exposee(); exposee.setKey(exposedKey.getKey()); - long keyDate = this.validateRequest.getKeyDate(now, principal, exposedKey); + long keyDate = this.validateRequest.validateKeyDate(now, principal, exposedKey); exposee.setKeyDate(keyDate); exposees.add(exposee); diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DebugController.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DebugController.java index a11480e6..6dd653aa 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DebugController.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/DebugController.java @@ -14,7 +14,9 @@ import org.dpppt.backend.sdk.model.gaen.GaenRequest; import org.dpppt.backend.sdk.utils.UTCInstant; import org.dpppt.backend.sdk.ws.security.ValidateRequest; +import org.dpppt.backend.sdk.ws.security.ValidateRequest.ClaimIsBeforeOnsetException; import org.dpppt.backend.sdk.ws.security.ValidateRequest.InvalidDateException; +import org.dpppt.backend.sdk.ws.security.ValidateRequest.WrongScopeException; import org.dpppt.backend.sdk.ws.security.signature.ProtoSignature; import org.dpppt.backend.sdk.ws.util.ValidationUtils; import org.dpppt.backend.sdk.ws.util.ValidationUtils.BadBatchReleaseTimeException; @@ -63,17 +65,16 @@ public DebugController( @RequestHeader(value = "User-Agent", required = true) String userAgent, @RequestHeader(value = "X-Device-Name", required = true) String deviceName, @AuthenticationPrincipal Object principal) - throws InvalidDateException { + throws InvalidDateException, ClaimIsBeforeOnsetException, WrongScopeException { var now = UTCInstant.now(); - if (!this.validateRequest.isValid(principal)) { - return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); - } + this.validateRequest.isValid(principal); + List nonFakeKeys = new ArrayList<>(); for (var key : gaenRequest.getGaenKeys()) { if (!validationUtils.isValidBase64Key(key.getKeyData())) { return new ResponseEntity<>("No valid base64 key", HttpStatus.BAD_REQUEST); } - this.validateRequest.getKeyDate(now, principal, key); + this.validateRequest.validateKeyDate(now, principal, key); if (this.validateRequest.isFakeRequest(principal, key)) { continue; } else { diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/GaenController.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/GaenController.java index 48e055d6..ab98a243 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/GaenController.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/GaenController.java @@ -139,7 +139,13 @@ public GaenController( @Documentation(description = "JWT token that can be verified by the backend server") Object principal) { var now = UTCInstant.now(); - if (!this.validateRequest.isValid(principal)) { + boolean valid = false; + try { + valid = this.validateRequest.isValid(principal); + } catch (ValidateRequest.WrongScopeException e) { + logger.error("Got invalid scope: " + e); + } + if (!valid) { return () -> ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } @@ -409,9 +415,9 @@ private boolean hasNegativeRollingPeriod(GaenKey key) { private boolean hasInvalidKeyDate(UTCInstant now, Object principal, GaenKey key) { try { - this.validateRequest.getKeyDate(now, principal, key); - } catch (InvalidDateException invalidDate) { - logger.error(invalidDate.getLocalizedMessage()); + this.validateRequest.validateKeyDate(now, principal, key); + } catch (InvalidDateException | ValidateRequest.ClaimIsBeforeOnsetException e) { + logger.error(e.getLocalizedMessage()); return true; } return false; diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/README.md b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/README.md new file mode 100644 index 00000000..14971f07 --- /dev/null +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/controller/README.md @@ -0,0 +1,3 @@ +# Controllers + +The `DPPPTController` is deprecated, and will eventually be removed in future versions. The `DebugController` can be used to test various Scenario, together with the callibration app. \ No newline at end of file diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/JWTValidateRequest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/JWTValidateRequest.java index 7ea8a283..8cdc74b1 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/JWTValidateRequest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/JWTValidateRequest.java @@ -33,17 +33,18 @@ public boolean isValid(Object authObject) { } @Override - public long getKeyDate(UTCInstant now, Object authObject, Object others) - throws InvalidDateException { + public long validateKeyDate(UTCInstant now, Object authObject, Object others) + throws InvalidDateException, ClaimIsBeforeOnsetException { if (authObject instanceof Jwt) { Jwt token = (Jwt) authObject; var jwtKeyDate = UTCInstant.parseDate(token.getClaim("onset")); if (others instanceof ExposeeRequest) { ExposeeRequest request = (ExposeeRequest) others; var requestKeyDate = UTCInstant.ofEpochMillis(request.getKeyDate()); - if (!validationUtils.isDateInRange(requestKeyDate, now) - || requestKeyDate.isBeforeEpochMillisOf(jwtKeyDate)) { + if (!validationUtils.isDateInRange(requestKeyDate, now)) { throw new InvalidDateException(); + } else if (requestKeyDate.isBeforeEpochMillisOf(jwtKeyDate)) { + throw new ClaimIsBeforeOnsetException(); } jwtKeyDate = UTCInstant.ofEpochMillis(request.getKeyDate()); } diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/NoValidateRequest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/NoValidateRequest.java index 5a1a0a45..fa86570f 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/NoValidateRequest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/NoValidateRequest.java @@ -29,8 +29,8 @@ public boolean isValid(Object authObject) { } @Override - public long getKeyDate(UTCInstant now, Object authObject, Object others) - throws InvalidDateException { + public long validateKeyDate(UTCInstant now, Object authObject, Object others) + throws ClaimIsBeforeOnsetException, InvalidDateException { if (others instanceof ExposeeRequest) { ExposeeRequest request = ((ExposeeRequest) others); var requestKeyDate = new UTCInstant(request.getKeyDate()); diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/README.md b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/README.md new file mode 100644 index 00000000..567ce831 --- /dev/null +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/README.md @@ -0,0 +1 @@ +# Validation and Cryptography \ No newline at end of file diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/ValidateRequest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/ValidateRequest.java index 825bbc15..60fdbf89 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/ValidateRequest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/ValidateRequest.java @@ -14,13 +14,13 @@ public interface ValidateRequest { - public boolean isValid(Object authObject); + public boolean isValid(Object authObject) throws WrongScopeException; // authObject is the Principal, given from Springboot // others can be any object (currently it is the ExposeeRequest, since we want // to allow no auth without the jwt profile) - public long getKeyDate(UTCInstant now, Object authObject, Object others) - throws InvalidDateException; + public long validateKeyDate(UTCInstant now, Object authObject, Object others) + throws ClaimIsBeforeOnsetException, InvalidDateException; public boolean isFakeRequest(Object authObject, Object others); @@ -28,4 +28,16 @@ public class InvalidDateException extends Exception { private static final long serialVersionUID = 5886601055826066148L; } + + public class ClaimDoesNotMatchKeyDateException extends Exception { + private static final long serialVersionUID = 5886601055826066149L; + } + + public class ClaimIsBeforeOnsetException extends Exception { + private static final long serialVersionUID = 5886601055826066150L; + } + + public class WrongScopeException extends Exception { + private static final long serialVersionUID = 5886601055826066151L; + } } diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/gaen/JWTValidateRequest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/gaen/JWTValidateRequest.java index a1fafbf0..68d68217 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/gaen/JWTValidateRequest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/gaen/JWTValidateRequest.java @@ -25,25 +25,30 @@ public JWTValidateRequest(ValidationUtils validationUtils) { } @Override - public boolean isValid(Object authObject) { + public boolean isValid(Object authObject) throws WrongScopeException { if (authObject instanceof Jwt) { Jwt token = (Jwt) authObject; - return token.containsClaim("scope") && token.getClaim("scope").equals("exposed"); + if (Boolean.TRUE.equals(token.containsClaim("scope")) + && token.getClaim("scope").equals("exposed")) { + return true; + } + throw new WrongScopeException(); } return false; } @Override - public long getKeyDate(UTCInstant now, Object authObject, Object others) - throws InvalidDateException { + public long validateKeyDate(UTCInstant now, Object authObject, Object others) + throws ClaimIsBeforeOnsetException, InvalidDateException { if (authObject instanceof Jwt) { Jwt token = (Jwt) authObject; var jwtKeyDate = UTCInstant.parseDate(token.getClaim("onset")); if (others instanceof GaenKey) { GaenKey request = (GaenKey) others; var keyDate = UTCInstant.of(request.getRollingStartNumber(), GaenUnit.TenMinutes); - if (!validationUtils.isDateInRange(keyDate, now) - || keyDate.isBeforeEpochMillisOf(jwtKeyDate)) { + if (keyDate.isBeforeEpochMillisOf(jwtKeyDate)) { + throw new ClaimIsBeforeOnsetException(); + } else if (!validationUtils.isDateInRange(keyDate, now)) { throw new InvalidDateException(); } jwtKeyDate = keyDate; @@ -59,7 +64,8 @@ public boolean isFakeRequest(Object authObject, Object others) { Jwt token = (Jwt) authObject; GaenKey request = (GaenKey) others; boolean fake = false; - if (token.containsClaim("fake") && token.getClaimAsString("fake").equals("1")) { + if (Boolean.TRUE.equals(token.containsClaim("fake")) + && token.getClaimAsString("fake").equals("1")) { fake = true; } if (request.getFake() == 1) { diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/signature/README.md b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/signature/README.md new file mode 100644 index 00000000..35637582 --- /dev/null +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/security/signature/README.md @@ -0,0 +1 @@ +# Exposure Notification (Protobuf and Signing) \ No newline at end of file diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/util/ValidationUtils.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/util/ValidationUtils.java index 8027b43f..8e849d25 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/util/ValidationUtils.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/util/ValidationUtils.java @@ -11,7 +11,9 @@ import java.time.Duration; import java.util.Base64; +import org.dpppt.backend.sdk.model.gaen.GaenKey; import org.dpppt.backend.sdk.utils.UTCInstant; +import org.springframework.security.oauth2.jwt.Jwt; /** Offers a set of methods to validate the incoming requests from the mobile devices. */ public class ValidationUtils { @@ -63,6 +65,15 @@ public boolean isDateInRange(UTCInstant timestamp, UTCInstant now) { // Because _now_ has a resolution of 1 millisecond, this precision is acceptable. return timestamp.isAfterEpochMillisOf(retention) && timestamp.isBeforeEpochMillisOf(now); } + /** + * Check if the given date is before now - retentionPeriod ... now + * + * @param timestamp to verify + * @return if the date is in the range + */ + public boolean isBeforeRetention(UTCInstant timestamp, UTCInstant now) { + return timestamp.isBeforeDateOf(now.minus(retentionPeriod)); + } /** * Check if the given timestamp is a valid key date: Must be midnight UTC. @@ -90,8 +101,49 @@ public boolean isValidBatchReleaseTime(UTCInstant batchReleaseTime, UTCInstant n return this.isDateInRange(batchReleaseTime, now); } + public void validateDelayedKeyDate(UTCInstant now, UTCInstant delayedKeyDate) + throws DelayedKeyDateIsInvalid { + if (delayedKeyDate.isBeforeDateOf(now.getLocalDate().minusDays(1)) + || delayedKeyDate.isAfterDateOf(now.getLocalDate().plusDays(1))) { + throw new DelayedKeyDateIsInvalid(); + } + } + + public void checkForDelayedKeyDateClaim(Object principal, GaenKey delayedKey) + throws DelayedKeyDateClaimIsWrong { + if (principal instanceof Jwt + && Boolean.FALSE.equals(((Jwt) principal).containsClaim("delayedKeyDate"))) { + throw new DelayedKeyDateClaimIsWrong(); + } + if (principal instanceof Jwt) { + var jwt = (Jwt) principal; + var claimKeyDate = Integer.parseInt(jwt.getClaimAsString("delayedKeyDate")); + if (!delayedKey.getRollingStartNumber().equals(claimKeyDate)) { + throw new DelayedKeyDateClaimIsWrong(); + } + } + } + + public boolean jwtIsFake(Object principal) { + return principal instanceof Jwt + && Boolean.TRUE.equals(((Jwt) principal).containsClaim("fake")) + && ((Jwt) principal).getClaim("fake").equals("1"); + } + public class BadBatchReleaseTimeException extends Exception { private static final long serialVersionUID = 618376703047108588L; } + + public class DelayedKeyDateIsInvalid extends Exception { + + /** */ + private static final long serialVersionUID = -2667236967819549686L; + } + + public class DelayedKeyDateClaimIsWrong extends Exception { + + /** */ + private static final long serialVersionUID = 4683923905451080793L; + } } diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/BaseControllerTest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/BaseControllerTest.java index 5e93c244..e466bfbf 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/BaseControllerTest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/BaseControllerTest.java @@ -25,7 +25,6 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.Base64; -import java.util.Date; import java.util.UUID; import javax.servlet.Filter; import javax.sql.DataSource; @@ -182,8 +181,7 @@ protected String createMaliciousToken(UTCInstant expiresAt) { .setSubject( "test-subject" + OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC).toString()) .setExpiration(expiresAt.getDate()) - .setIssuedAt( - Date.from(OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC).toInstant())) + .setIssuedAt(UTCInstant.now().getDate()) .compact(); } } diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/DPPPTControllerTest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/DPPPTControllerTest.java index 7244219c..d94cacc7 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/DPPPTControllerTest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/DPPPTControllerTest.java @@ -306,17 +306,17 @@ public void cannotUseKeyDateBeforeOnset() throws Exception { createToken( UTCInstant.now().plusMinutes(5), UTCInstant.now().getLocalDate().format(DateTimeFormatter.ISO_DATE)); - MockHttpServletResponse response = - mockMvc - .perform( - post("/v1/exposed") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + token) - .header("User-Agent", "MockMVC") - .content(json(exposeeRequest))) - .andExpect(status().is(400)) - .andReturn() - .getResponse(); + + mockMvc + .perform( + post("/v1/exposed") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + token) + .header("User-Agent", "MockMVC") + .content(json(exposeeRequest))) + .andExpect(status().is(400)) + .andReturn() + .getResponse(); } @Test diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/GaenControllerTest.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/GaenControllerTest.java index 570c2383..fd3f299e 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/GaenControllerTest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/controller/GaenControllerTest.java @@ -830,17 +830,17 @@ public void cannotUseKeyDateInFuture() throws Exception { String token = createToken(now.plusMinutes(5)); - MvcResult response = - mockMvc - .perform( - post("/v1/gaen/exposed") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + token) - .header("User-Agent", "MockMVC") - .content(json(exposeeRequest))) - .andExpect(request().asyncStarted()) - .andExpect(status().is(200)) - .andReturn(); + mockMvc + .perform( + post("/v1/gaen/exposed") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + token) + .header("User-Agent", "MockMVC") + .content(json(exposeeRequest))) + .andExpect(request().asyncStarted()) + .andExpect(status().is(200)) + .andReturn(); + var result = gaenDataService.getSortedExposedForKeyDate( midnight.plusDays(2).getTimestamp(), @@ -867,8 +867,7 @@ public void keyDateNotOlderThan21Days() throws Exception { keys.add(key); for (int i = 0; i < 13; i++) { var tmpKey = new GaenKey(); - tmpKey.setRollingStartNumber( - (int) Duration.ofMillis(Instant.now().toEpochMilli()).dividedBy(Duration.ofMinutes(10))); + tmpKey.setRollingStartNumber((int) now.get10MinutesSince1970()); tmpKey.setKeyData(Base64.getEncoder().encodeToString("testKey32Bytes--".getBytes("UTF-8"))); tmpKey.setRollingPeriod(144); tmpKey.setFake(1); @@ -879,17 +878,17 @@ public void keyDateNotOlderThan21Days() throws Exception { String token = createToken(now.plusMinutes(5), "2020-01-01"); - MvcResult response = - mockMvc - .perform( - post("/v1/gaen/exposed") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + token) - .header("User-Agent", "MockMVC") - .content(json(exposeeRequest))) - .andExpect(request().asyncStarted()) - .andExpect(status().is(200)) - .andReturn(); + mockMvc + .perform( + post("/v1/gaen/exposed") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + token) + .header("User-Agent", "MockMVC") + .content(json(exposeeRequest))) + .andExpect(request().asyncStarted()) + .andExpect(status().is(200)) + .andReturn(); + var result = gaenDataService.getSortedExposedForKeyDate( midnight.minusDays(22).getTimestamp(), diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/insertmanager/MockDataSource.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/insertmanager/MockDataSource.java new file mode 100644 index 00000000..a6b3773d --- /dev/null +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/test/java/org/dpppt/backend/sdk/ws/insertmanager/MockDataSource.java @@ -0,0 +1,33 @@ +package org.dpppt.backend.sdk.ws.insertmanager; + +import java.time.Duration; +import java.util.List; +import org.dpppt.backend.sdk.data.gaen.GAENDataService; +import org.dpppt.backend.sdk.model.gaen.GaenKey; +import org.dpppt.backend.sdk.utils.UTCInstant; + +public class MockDataSource implements GAENDataService { + + @Override + public void upsertExposees(List keys, UTCInstant now) { + throw new RuntimeException("UPSERT_EXPOSEES"); + } + + @Override + public void upsertExposeesDelayed( + List keys, UTCInstant delayedReceivedAt, UTCInstant now) {} + + @Override + public int getMaxExposedIdForKeyDate(Long keyDate, Long publishedAfter, Long publishedUntil) { + return 0; + } + + @Override + public List getSortedExposedForKeyDate( + Long keyDate, Long publishedAfter, Long publishedUntil) { + return null; + } + + @Override + public void cleanDB(Duration retentionPeriod) {} +}