From 33b814bebcc6f36592d96ef18305b15066c834a5 Mon Sep 17 00:00:00 2001 From: alig Date: Fri, 19 Jun 2020 05:55:32 +0200 Subject: [PATCH 1/3] PP-552: truncate received at to current day midnight --- .../dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java b/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java index fdeb2469..f09a59db 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java @@ -11,7 +11,9 @@ package org.dpppt.backend.sdk.data; import java.time.Duration; +import java.time.LocalDate; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; import java.util.Date; @@ -46,12 +48,14 @@ public boolean checkAndInsertPublishUUID(String uuid) { if (count > 0) { return false; } else { - params.addValue("received_at", new Date()); + // set the received_at to the current day, with no time information + long startOfDay = LocalDate.now().atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli(); + params.addValue("received_at", new Date(startOfDay)); reedemUUIDInsert.execute(params); return true; } } - + @Override @Transactional(readOnly = false) public void cleanDB(Duration retentionPeriod) { From 7f1934550ce7ad8d957ebdb9f3515274d4225645 Mon Sep 17 00:00:00 2001 From: Patrick Amrein Date: Fri, 19 Jun 2020 09:21:33 +0200 Subject: [PATCH 2/3] round received_at up not down add clock parameter to allow testing different timescenarios add tests --- .../sdk/data/JDBCRedeemDataServiceImpl.java | 11 ++++-- .../gaen/PostgresGaenDataServiceTest.java | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java b/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java index f09a59db..4450b6a8 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-data/src/main/java/org/dpppt/backend/sdk/data/JDBCRedeemDataServiceImpl.java @@ -10,10 +10,10 @@ package org.dpppt.backend.sdk.data; +import java.time.Clock; import java.time.Duration; import java.time.LocalDate; import java.time.OffsetDateTime; -import java.time.ZoneId; import java.time.ZoneOffset; import java.util.Date; @@ -32,6 +32,7 @@ public class JDBCRedeemDataServiceImpl implements RedeemDataService { private final NamedParameterJdbcTemplate jt; private final SimpleJdbcInsert reedemUUIDInsert; + private Clock currentClock = Clock.systemUTC(); public JDBCRedeemDataServiceImpl(DataSource dataSource) { this.jt = new NamedParameterJdbcTemplate(dataSource); @@ -48,8 +49,10 @@ public boolean checkAndInsertPublishUUID(String uuid) { if (count > 0) { return false; } else { - // set the received_at to the current day, with no time information - long startOfDay = LocalDate.now().atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli(); + // set the received_at to the next day, with no time information + // it will stay longer in the DB but we mitigate the risk that the JWT + // can be used twice (c.f. testTokensArentDeletedBeforeExpire). + long startOfDay = LocalDate.now(currentClock).atStartOfDay(ZoneOffset.UTC).plusDays(1).toInstant().toEpochMilli(); params.addValue("received_at", new Date(startOfDay)); reedemUUIDInsert.execute(params); return true; @@ -59,7 +62,7 @@ public boolean checkAndInsertPublishUUID(String uuid) { @Override @Transactional(readOnly = false) public void cleanDB(Duration retentionPeriod) { - OffsetDateTime retentionTime = OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC).minus(retentionPeriod); + OffsetDateTime retentionTime = OffsetDateTime.now(currentClock).minus(retentionPeriod); logger.info("Cleanup DB entries before: " + retentionTime); MapSqlParameterSource params = new MapSqlParameterSource("retention_time", Date.from(retentionTime.toInstant())); String sqlRedeem = "delete from t_redeem_uuid where received_at < :retention_time"; diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-data/src/test/java/org/dpppt/backend/sdk/data/gaen/PostgresGaenDataServiceTest.java b/dpppt-backend-sdk/dpppt-backend-sdk-data/src/test/java/org/dpppt/backend/sdk/data/gaen/PostgresGaenDataServiceTest.java index cfb0a888..b8f26223 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-data/src/test/java/org/dpppt/backend/sdk/data/gaen/PostgresGaenDataServiceTest.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-data/src/test/java/org/dpppt/backend/sdk/data/gaen/PostgresGaenDataServiceTest.java @@ -14,11 +14,13 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; +import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.time.LocalDate; @@ -32,6 +34,7 @@ import javax.sql.DataSource; +import org.dpppt.backend.sdk.data.JDBCRedeemDataServiceImpl; import org.dpppt.backend.sdk.data.RedeemDataService; import org.dpppt.backend.sdk.data.config.DPPPTDataServiceConfig; import org.dpppt.backend.sdk.data.config.FlyWayConfig; @@ -114,6 +117,41 @@ public void testRedeemUUID() { assertTrue(actual); } + private Field getFieldToClock() throws Exception{ + Field field = JDBCRedeemDataServiceImpl.class.getDeclaredField("currentClock"); + field.setAccessible(true); + return field; + } + + @Test + public void testTokensArentDeletedBeforeExpire() throws Exception { + var field = getFieldToClock(); + var localDateNow = LocalDate.now(ZoneOffset.UTC); + Clock twoMinutesToMidnight = Clock.fixed(localDateNow.atStartOfDay(ZoneOffset.UTC).plusDays(1).minusMinutes(2).toInstant(), ZoneOffset.UTC); + Clock twoMinutesAfterMidnight = Clock.fixed(localDateNow.atStartOfDay(ZoneOffset.UTC).plusDays(1).plusMinutes(2).toInstant(), ZoneOffset.UTC); + Clock nextDay = Clock.fixed(localDateNow.atStartOfDay(ZoneOffset.UTC).plusDays(2).plusMinutes(2).toInstant(), ZoneOffset.UTC); + + field.set(redeemDataService, twoMinutesToMidnight); + + boolean actual = redeemDataService.checkAndInsertPublishUUID("bc77d983-2359-48e8-835a-de673fe53ccb"); + assertTrue(actual); + + //token is still valid for 1 minute + field.set(redeemDataService, twoMinutesAfterMidnight); + + redeemDataService.cleanDB(Duration.ofDays(1)); + + actual = redeemDataService.checkAndInsertPublishUUID("bc77d983-2359-48e8-835a-de673fe53ccb"); + assertFalse(actual); + + field.set(redeemDataService, nextDay); + + redeemDataService.cleanDB(Duration.ofDays(1)); + + actual = redeemDataService.checkAndInsertPublishUUID("bc77d983-2359-48e8-835a-de673fe53ccb"); + assertTrue(actual); + } + @Test public void cleanup() throws SQLException { OffsetDateTime now = OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC); From d7644373ae8695550237ed346aa1e0fb4a952e2c Mon Sep 17 00:00:00 2001 From: Patrick Amrein Date: Fri, 19 Jun 2020 10:15:31 +0200 Subject: [PATCH 3/3] set retention day to 2 --- .../main/java/org/dpppt/backend/sdk/ws/config/WSBaseConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/WSBaseConfig.java b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/WSBaseConfig.java index 53ee82f4..795a6ca0 100644 --- a/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/WSBaseConfig.java +++ b/dpppt-backend-sdk/dpppt-backend-sdk-ws/src/main/java/org/dpppt/backend/sdk/ws/config/WSBaseConfig.java @@ -283,7 +283,7 @@ public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { logger.info("Start DB cleanup"); dppptSDKDataService().cleanDB(Duration.ofDays(retentionDays)); gaenDataService().cleanDB(Duration.ofDays(retentionDays)); - redeemDataService().cleanDB(Duration.ofDays(1)); + redeemDataService().cleanDB(Duration.ofDays(2)); logger.info("DB cleanup up"); }, 60 * 60 * 1000L));