From 7d9d851046a736854db36e38c8f242772408a2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Sun, 20 Dec 2015 22:41:17 +0100 Subject: [PATCH] Make DTOs and Challenges serializable --- .../java/org/shredzone/acme4j/Account.java | 4 ++- .../org/shredzone/acme4j/Authorization.java | 8 ++++- .../org/shredzone/acme4j/Registration.java | 4 ++- .../shredzone/acme4j/challenge/Challenge.java | 3 +- .../acme4j/challenge/DnsChallenge.java | 1 + .../acme4j/challenge/GenericChallenge.java | 27 +++++++++++++- .../acme4j/challenge/HttpChallenge.java | 1 + .../challenge/ProofOfPossessionChallenge.java | 1 + .../acme4j/challenge/TlsSniChallenge.java | 1 + .../challenge/GenericChallengeTest.java | 36 +++++++++++++++++++ 10 files changed, 81 insertions(+), 5 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java index 24de24d4..13e3f093 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j; +import java.io.Serializable; import java.security.KeyPair; /** @@ -22,7 +23,8 @@ import java.security.KeyPair; * * @author Richard "Shred" Körber */ -public class Account { +public class Account implements Serializable { + private static final long serialVersionUID = 1064105289226118702L; private final KeyPair keyPair; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java index 510f51dc..0ef50388 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -25,7 +26,8 @@ import org.shredzone.acme4j.challenge.Challenge; * * @author Richard "Shred" Körber */ -public class Authorization { +public class Authorization implements Serializable { + private static final long serialVersionUID = -3116928998379417741L; private String domain; private String status; @@ -138,6 +140,10 @@ public class Authorization { * validation. */ public Collection findCombination(String... types) { + if (combinations == null) { + return null; + } + Collection available = Arrays.asList(types); Collection combinationTypes = new ArrayList<>(); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java index a0fbd4ff..87a2b222 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j; +import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -23,7 +24,8 @@ import java.util.List; * * @author Richard "Shred" Körber */ -public class Registration { +public class Registration implements Serializable { + private static final long serialVersionUID = -8177333806740391140L; private List contacts = new ArrayList<>(); private URI agreement; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java index 15151bc2..73f66035 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j.challenge; +import java.io.Serializable; import java.net.URI; import java.util.Map; @@ -24,7 +25,7 @@ import org.shredzone.acme4j.util.ClaimBuilder; * * @author Richard "Shred" Körber */ -public interface Challenge { +public interface Challenge extends Serializable { /** * Challenge status enumeration. diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/DnsChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/DnsChallenge.java index b3db9601..347504ec 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/DnsChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/DnsChallenge.java @@ -27,6 +27,7 @@ import org.shredzone.acme4j.util.ClaimBuilder; * @author Richard "Shred" Körber */ public class DnsChallenge extends GenericChallenge { + private static final long serialVersionUID = 6964687027713533075L; /** * Challenge type name: {@value} diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/GenericChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/GenericChallenge.java index 78aaf9f7..cee4bca1 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/GenericChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/GenericChallenge.java @@ -13,6 +13,9 @@ */ package org.shredzone.acme4j.challenge; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; @@ -22,6 +25,7 @@ import java.security.PublicKey; import java.util.HashMap; import java.util.Map; +import org.jose4j.json.JsonUtil; import org.jose4j.jwk.JsonWebKey; import org.jose4j.jwk.JsonWebKey.OutputControlLevel; import org.jose4j.lang.JoseException; @@ -36,6 +40,7 @@ import org.shredzone.acme4j.util.ClaimBuilder; * @author Richard "Shred" Körber */ public class GenericChallenge implements Challenge { + private static final long serialVersionUID = 2338794776848388099L; protected static final String KEY_TYPE = "type"; protected static final String KEY_STATUS = "status"; @@ -44,7 +49,7 @@ public class GenericChallenge implements Challenge { protected static final String KEY_TOKEN = "token"; protected static final String KEY_KEY_AUTHORIZSATION = "keyAuthorization"; - private final Map data = new HashMap<>(); + private transient Map data = new HashMap<>(); @Override public String getType() { @@ -165,4 +170,24 @@ public class GenericChallenge implements Challenge { } } + /** + * Serialize the data map in JSON. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeUTF(JsonUtil.toJson(data)); + out.defaultWriteObject(); + } + + /** + * Deserialize the JSON representation of the data map. + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + try { + data = new HashMap<>(JsonUtil.parseJson(in.readUTF())); + in.defaultReadObject(); + } catch (JoseException ex) { + throw new IOException("Cannot deserialize", ex); + } + } + } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/HttpChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/HttpChallenge.java index 33201acf..e5150b02 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/HttpChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/HttpChallenge.java @@ -23,6 +23,7 @@ import org.shredzone.acme4j.util.ClaimBuilder; * @author Richard "Shred" Körber */ public class HttpChallenge extends GenericChallenge { + private static final long serialVersionUID = 3322211185872544605L; /** * Challenge type name: {@value} diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallenge.java index a3e9da20..0e7fd152 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallenge.java @@ -26,6 +26,7 @@ import org.shredzone.acme4j.util.ClaimBuilder; * @author Richard "Shred" Körber */ public class ProofOfPossessionChallenge extends GenericChallenge { + private static final long serialVersionUID = 6212440828380185335L; /** * Challenge type name: {@value} diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSniChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSniChallenge.java index a6acc9a2..a550d664 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSniChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSniChallenge.java @@ -21,6 +21,7 @@ package org.shredzone.acme4j.challenge; * @author Richard "Shred" Körber */ public class TlsSniChallenge extends GenericChallenge { + private static final long serialVersionUID = 7370329525205430573L; /** * Challenge type name: {@value} diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/GenericChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/GenericChallengeTest.java index ab21fd58..53153726 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/GenericChallengeTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/GenericChallengeTest.java @@ -17,7 +17,11 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.net.URI; import java.net.URISyntaxException; import java.security.KeyPair; @@ -132,4 +136,36 @@ public class GenericChallengeTest { assertThat(thumbprint, is(Base64Url.decode(TestUtils.THUMBPRINT))); } + /** + * Test that challenge serialization works correctly. + */ + @Test + public void testSerialization() throws IOException, ClassNotFoundException { + HttpChallenge originalChallenge = new HttpChallenge(); + originalChallenge.unmarshall(TestUtils.getJsonAsMap("httpChallenge")); + + // Serialize + byte[] data; + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + try (ObjectOutputStream oos = new ObjectOutputStream(out)) { + oos.writeObject(originalChallenge); + } + data = out.toByteArray(); + } + + // Deserialize + Challenge testChallenge; + try (ByteArrayInputStream in = new ByteArrayInputStream(data)) { + try (ObjectInputStream ois = new ObjectInputStream(in)) { + testChallenge = (Challenge) ois.readObject(); + } + } + + assertThat(testChallenge, not(sameInstance((Challenge) originalChallenge))); + assertThat(testChallenge, is(instanceOf(HttpChallenge.class))); + assertThat(testChallenge.getType(), is(HttpChallenge.TYPE)); + assertThat(testChallenge.getStatus(), is(Challenge.Status.PENDING)); + assertThat(((HttpChallenge )testChallenge).getToken(), is("rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ")); + } + }