From 8d1545db817f48dcd6bfd5db7594fb71a878e0db Mon Sep 17 00:00:00 2001 From: Philipp Bumann Date: Tue, 1 Oct 2024 13:08:01 +0200 Subject: [PATCH 1/3] Added error handling if resumption token is not a valid base64 string --- .../services/impl/SimpleResumptionTokenFormat.java | 10 +++++++--- .../impl/SimpleResumptionTokenFormatTest.java | 13 +++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/xoai-common/src/main/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormat.java b/xoai-common/src/main/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormat.java index a7b3ae23..4129e602 100644 --- a/xoai-common/src/main/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormat.java +++ b/xoai-common/src/main/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormat.java @@ -124,12 +124,16 @@ public String format(ResumptionToken.Value resumptionToken) { * @param value The Base64 encoded string * @return A decoded String (may be empty) */ - static String base64Decode(String value) { + static String base64Decode(String value) throws BadResumptionTokenException { if (value == null) { return null; } - byte[] decodedValue = Base64.getDecoder().decode(value); - return new String(decodedValue, StandardCharsets.UTF_8); + try { + byte[] decodedValue = Base64.getDecoder().decode(value); + return new String(decodedValue, StandardCharsets.UTF_8); + } catch (IllegalArgumentException e) { + throw new BadResumptionTokenException("Token has no valid base64 encoding", e); + } } static String base64Encode(String value) { diff --git a/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java b/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java index a0cb6ab7..e5f9e244 100644 --- a/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java +++ b/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java @@ -9,6 +9,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -73,4 +74,16 @@ void validParse(String token) { String encoded = SimpleResumptionTokenFormat.base64Encode(token); assertDoesNotThrow(() -> format.parse(encoded)); } + + @Test + void validBase64Decoding() { + assertDoesNotThrow(() -> SimpleResumptionTokenFormat.base64Decode("b2Zmc2V0OjoxMDA=")); + } + + @Test + void invalidBase64Decoding() { + assertThrows( + BadResumptionTokenException.class, + () -> SimpleResumptionTokenFormat.base64Decode("b2Zmc2V0OjoMDA=")); + } } From e9ef7119c71c34d4bb2377e42d68b4f8ef9dafd0 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Fri, 18 Oct 2024 10:21:00 +0200 Subject: [PATCH 2/3] test(common): restructure tests for invalid Base64 encoded strings - Use a parameterized test with format.parse(), not the lower level API call, making it more aligned to the pre-existing tests. - Add a parsing test with a string that contains UTF-8 chars to ensure encoding and decoding those works and don't provoke failures. --- .../impl/SimpleResumptionTokenFormatTest.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java b/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java index e5f9e244..4e7544fb 100644 --- a/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java +++ b/xoai-common/src/test/java/io/gdcc/xoai/services/impl/SimpleResumptionTokenFormatTest.java @@ -1,6 +1,8 @@ package io.gdcc.xoai.services.impl; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import io.gdcc.xoai.exceptions.BadResumptionTokenException; import io.gdcc.xoai.model.oaipmh.Granularity; @@ -9,7 +11,6 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.stream.Stream; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -69,21 +70,22 @@ void failingParse(String token) { @ParameterizedTest @NullAndEmptySource - @ValueSource(strings = {" ", "\t\t\t", "offset::1|", "until::2022-05-13T10:00:00Z"}) + @ValueSource( + strings = { + " ", + "\t\t\t", + "offset::1|", + "until::2022-05-13T10:00:00Z", + "offset::1|set::Ätherische Öle" + }) void validParse(String token) { String encoded = SimpleResumptionTokenFormat.base64Encode(token); assertDoesNotThrow(() -> format.parse(encoded)); } - @Test - void validBase64Decoding() { - assertDoesNotThrow(() -> SimpleResumptionTokenFormat.base64Decode("b2Zmc2V0OjoxMDA=")); - } - - @Test - void invalidBase64Decoding() { - assertThrows( - BadResumptionTokenException.class, - () -> SimpleResumptionTokenFormat.base64Decode("b2Zmc2V0OjoMDA=")); + @ParameterizedTest + @ValueSource(strings = {"b2Zmc2V0OjoMDA=", "VG========"}) + void invalidBase64Parse(String sut) { + assertThrows(BadResumptionTokenException.class, () -> format.parse(sut)); } } From a54ef694891c12019e2ef45489c6fe3741c1b259 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Fri, 18 Oct 2024 10:24:03 +0200 Subject: [PATCH 3/3] doc: add release note for v5.2.2 to README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 40585db2..b318afbb 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,17 @@ mvn spotless:check ## Release notes +### v5.2.2 + +#### 🌟 FEATURES +- (none) + +#### 💔 BREAKING CHANGES +- (none) + +#### 🏹 BUG FIXES +- Catch invalid Base64 encodings for resumption tokens (#272) - a community contribution by @bumann-sbb 💫 + ### v5.2.1 #### 🌟 FEATURES