Skip to content

Commit b075194

Browse files
fix: Correct null assertions when deserializing (#211)
previously this would throw null pointer exception if `"assertions": null` was in the manifest, this should stop that error and assign assertions and empty arraylist if it is null on deserialization
1 parent 1ee1367 commit b075194

File tree

4 files changed

+101
-4
lines changed

4 files changed

+101
-4
lines changed

sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public class Manifest {
4141
private static final String kAssertionHash = "assertionHash";
4242
private static final String kAssertionSignature = "assertionSig";
4343

44-
private static final Gson gson = new Gson();
44+
private static final Gson gson = new GsonBuilder()
45+
.registerTypeAdapter(Manifest.class, new ManifestDeserializer())
46+
.create();
4547

4648
@Override
4749
public boolean equals(Object o) {
@@ -458,6 +460,19 @@ private JWSVerifier createVerifier(AssertionConfig.AssertionKey assertionKey) th
458460
public Payload payload;
459461
public List<Assertion> assertions = new ArrayList<>();
460462

463+
public static class ManifestDeserializer implements JsonDeserializer<Object> {
464+
@Override
465+
public Manifest deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
466+
// Let Gson handle the default deserialization of the object first
467+
Manifest manifest = new Gson().fromJson(json, typeOfT);
468+
// Now check if the `assertions` field is null and replace it with an empty list if necessary
469+
if (manifest.assertions == null) {
470+
manifest.assertions = new ArrayList<>(); // Replace null with empty list
471+
}
472+
return manifest;
473+
}
474+
}
475+
461476
private static Manifest readManifest(Reader reader) {
462477
return gson.fromJson(reader, Manifest.class);
463478
}

sdk/src/main/java/io/opentdf/platform/sdk/TDF.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package io.opentdf.platform.sdk;
22

33
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
45
import com.nimbusds.jose.*;
56

67
import io.opentdf.platform.policy.Value;
78
import io.opentdf.platform.policy.attributes.AttributesServiceGrpc.AttributesServiceFutureStub;
89
import io.opentdf.platform.sdk.Config.TDFConfig;
10+
import io.opentdf.platform.sdk.Manifest.ManifestDeserializer;
911
import io.opentdf.platform.sdk.Autoconfigure.AttributeValueFQN;
1012
import io.opentdf.platform.sdk.Config.KASInfo;
1113

@@ -75,7 +77,9 @@ public TDF() {
7577

7678
private static final SecureRandom sRandom = new SecureRandom();
7779

78-
private static final Gson gson = new Gson();
80+
private static final Gson gson = new GsonBuilder()
81+
.registerTypeAdapter(Manifest.class, new ManifestDeserializer())
82+
.create();
7983

8084
public class SplitKeyException extends IOException {
8185
public SplitKeyException(String errorMessage) {

sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java

+71-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
import com.google.gson.Gson;
55
import com.google.gson.GsonBuilder;
66

7+
import io.opentdf.platform.sdk.Manifest.ManifestDeserializer;
8+
79
import java.nio.charset.Charset;
810
import java.nio.charset.StandardCharsets;
911
import java.util.List;
1012
import java.util.Map;
1113

14+
import static org.junit.Assert.assertNotNull;
1215
import static org.junit.jupiter.api.Assertions.assertEquals;
1316

1417
public class ManifestTest {
@@ -62,7 +65,9 @@ void testManifestMarshalAndUnMarshal() {
6265
"}";
6366

6467
GsonBuilder gsonBuilder = new GsonBuilder();
65-
Gson gson = gsonBuilder.setPrettyPrinting().create();
68+
Gson gson = gsonBuilder.setPrettyPrinting()
69+
.registerTypeAdapter(Manifest.class, new ManifestDeserializer())
70+
.create();
6671
Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class);
6772

6873
// Test payload
@@ -90,4 +95,69 @@ void testManifestMarshalAndUnMarshal() {
9095

9196
assertEquals(manifest, deserializedAgain, "something changed when we deserialized -> serialized -> deserialized");
9297
}
98+
99+
@Test
100+
void testAssertionNull() {
101+
String kManifestJsonFromTDF = "{\n" +
102+
" \"encryptionInformation\": {\n" +
103+
" \"integrityInformation\": {\n" +
104+
" \"encryptedSegmentSizeDefault\": 1048604,\n" +
105+
" \"rootSignature\": {\n" +
106+
" \"alg\": \"HS256\",\n" +
107+
" \"sig\": \"N2Y1ZjJlYWE4N2EzNjc2Nzc3NzgxNGU2ZGE1NmI4NDNhZTI5ZWY5NDc2OGI1ZTMzYTIyMTU4MDBlZTY3NzQzNA==\"\n" +
108+
" },\n" +
109+
" \"segmentHashAlg\": \"GMAC\",\n" +
110+
" \"segmentSizeDefault\": 1048576,\n" +
111+
" \"segments\": [\n" +
112+
" {\n" +
113+
" \"encryptedSegmentSize\": 41,\n" +
114+
" \"hash\": \"ZWEyZTkwYjZiZThmYWZhNzg5ZmNjOWIyZTA2Njg5OTQ=\",\n" +
115+
" \"segmentSize\": 1048576\n" +
116+
" }\n" +
117+
" ]\n" +
118+
" },\n" +
119+
" \"keyAccess\": [\n" +
120+
" {\n" +
121+
" \"policyBinding\": {\n" +
122+
" \"alg\": \"HS256\",\n" +
123+
" \"hash\": \"YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA==\"\n" +
124+
" },\n" +
125+
" \"protocol\": \"kas\",\n" +
126+
" \"type\": \"wrapped\",\n" +
127+
" \"url\": \"http://localhost:65432/kas\",\n" +
128+
" \"wrappedKey\": \"dJ3PdscXWvLv/juSkL7EMhl4lgLSBfI9EeoG2ct6NeSwPkPm/ieMF6ryDQjGeqZttoLlx2qBCVpik/BooGd/FtpYMIF/7a5RFTJ3G+o4Lww/zG6zIgV2APEPO+Gp7ORlFyMNJfn6Tj8ChTweKBqfXEXLihTV6sTZFtsWjdV96Z4KXbLe8tGpkXBpUAsSlmjcDJ920vrqnp3dvt2GwfmAiRWYCMXxnqUECqN5kVXMJywcvHatv2ZJSA/ixjDOrix+MocDJ69K/yFA17DXgfjf5X4SLyS0XgaZcXsdACBb+ogBlPw6vAbBrAyqI0Vi1msMRYNDS+FTl1yWEXl1HpyyCw==\"\n" +
129+
" }\n" +
130+
" ],\n" +
131+
" \"method\": {\n" +
132+
" \"algorithm\": \"AES-256-GCM\",\n" +
133+
" \"isStreamable\": true,\n" +
134+
" \"iv\": \"tozen81HLtZktNOP\"\n" +
135+
" },\n" +
136+
" \"policy\": \"eyJib2R5Ijp7ImRhdGFBdHRyaWJ1dGVzIjpbXSwiZGlzc2VtIjpbXX0sInV1aWQiOiJiNTM3MDllMy03NmE3LTRmYzctOGEwZi1mZDBhNjcyNmVhM2YifQ==\",\n" +
137+
" \"type\": \"split\"\n" +
138+
" },\n" +
139+
" \"payload\": {\n" +
140+
" \"isEncrypted\": true,\n" +
141+
" \"mimeType\": \"application/octet-stream\",\n" +
142+
" \"protocol\": \"zip\",\n" +
143+
" \"type\": \"reference\",\n" +
144+
" \"url\": \"0.payload\"\n" +
145+
" },\n" +
146+
" \"assertions\": null\n"+
147+
"}";
148+
149+
GsonBuilder gsonBuilder = new GsonBuilder();
150+
Gson gson = gsonBuilder.setPrettyPrinting()
151+
.registerTypeAdapter(Manifest.class, new ManifestDeserializer())
152+
.create();
153+
Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class);
154+
155+
// Test payload for sanity check
156+
assertEquals(manifest.payload.url, "0.payload");
157+
assertEquals(manifest.payload.isEncrypted, true);
158+
// Test assertion deserialization
159+
assertNotNull(manifest.assertions);
160+
assertEquals(manifest.assertions.size(), 0);
161+
162+
}
93163
}

sdk/src/test/java/io/opentdf/platform/sdk/ZipReaderTest.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package io.opentdf.platform.sdk;
22
import com.google.gson.Gson;
3+
import com.google.gson.GsonBuilder;
4+
5+
import io.opentdf.platform.sdk.Manifest.ManifestDeserializer;
6+
37
import org.apache.commons.compress.archivers.zip.Zip64Mode;
48
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
59
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
@@ -36,7 +40,11 @@ public void testReadingExistingZip() throws Exception {
3640
if (entry.getName().endsWith(".json")) {
3741
entry.getData().transferTo(stream);
3842
var data = stream.toString(StandardCharsets.UTF_8);
39-
var map = new Gson().fromJson(data, Map.class);
43+
var gson = new GsonBuilder()
44+
.registerTypeAdapter(Manifest.class, new ManifestDeserializer())
45+
.create();
46+
var map = gson.fromJson(data, Map.class);
47+
4048
assertThat(map.get("encryptionInformation")).isNotNull();
4149
}
4250
}

0 commit comments

Comments
 (0)