Replace all JSON maps with a JSON type

pull/30/head
Richard Körber 2016-12-21 23:24:49 +01:00
parent 0ee546da8b
commit 101801260f
33 changed files with 917 additions and 460 deletions

View File

@ -22,13 +22,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.shredzone.acme4j.challenge.Challenge;
import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -180,7 +180,7 @@ public class Authorization extends AcmeResource {
conn.sendRequest(getLocation(), getSession());
int rc = conn.accept(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED);
Map<String, Object> result = conn.readJsonResponse();
JSON result = conn.readJsonResponse();
unmarshalAuthorization(result);
if (rc == HttpURLConnection.HTTP_ACCEPTED) {
@ -231,43 +231,42 @@ public class Authorization extends AcmeResource {
* @param json
* JSON data
*/
@SuppressWarnings("unchecked")
protected void unmarshalAuthorization(Map<String, Object> json) {
this.status = Status.parse((String) json.get("status"), Status.PENDING);
protected void unmarshalAuthorization(JSON json) {
this.status = Status.parse(json.get("status").asString(), Status.PENDING);
String jsonExpires = (String) json.get("expires");
String jsonExpires = json.get("expires").asString();
if (jsonExpires != null) {
expires = parseTimestamp(jsonExpires);
}
Map<String, Object> jsonIdentifier = (Map<String, Object>) json.get("identifier");
JSON jsonIdentifier = json.get("identifier").asObject();
if (jsonIdentifier != null) {
String type = (String) jsonIdentifier.get("type");
String type = jsonIdentifier.get("type").asString();
if (type != null && !"dns".equals(type)) {
throw new AcmeProtocolException("Unknown authorization type: " + type);
}
domain = (String) jsonIdentifier.get("value");
domain = jsonIdentifier.get("value").asString();
}
Collection<Map<String, Object>> jsonChallenges =
(Collection<Map<String, Object>>) json.get("challenges");
JSON.Array jsonChallenges = json.get("challenges").asArray();
List<Challenge> cr = new ArrayList<>();
for (Map<String, Object> c : jsonChallenges) {
Challenge ch = getSession().createChallenge(c);
for (JSON.Value c : jsonChallenges) {
Challenge ch = getSession().createChallenge(c.asObject());
if (ch != null) {
cr.add(ch);
}
}
challenges = cr;
Collection<List<Number>> jsonCombinations =
(Collection<List<Number>>) json.get("combinations");
JSON.Array jsonCombinations = json.get("combinations").asArray();
if (jsonCombinations != null) {
List<List<Challenge>> cmb = new ArrayList<>(jsonCombinations.size());
for (List<Number> c : jsonCombinations) {
for (int ix = 0; ix < jsonCombinations.size(); ix++) {
JSON.Array c = jsonCombinations.get(ix).asArray();
List<Challenge> clist = new ArrayList<>(c.size());
for (Number n : c) {
clist.add(cr.get(n.intValue()));
for (JSON.Value n : c) {
clist.add(cr.get(n.asInt()));
}
cmb.add(clist);
}

View File

@ -14,26 +14,20 @@
package org.shredzone.acme4j;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSON.Array;
import org.shredzone.acme4j.util.JSON.Value;
/**
* Contains metadata related to the provider.
*/
public class Metadata {
private final Map<String, Object> meta;
/**
* Creates an empty new {@link Metadata} instance.
*/
public Metadata() {
this(new HashMap<String, Object>());
}
private final JSON meta;
/**
* Creates a new {@link Metadata} instance.
@ -41,7 +35,7 @@ public class Metadata {
* @param meta
* JSON map of metadata
*/
public Metadata(Map<String, Object> meta) {
public Metadata(JSON meta) {
this.meta = meta;
}
@ -50,7 +44,7 @@ public class Metadata {
* available.
*/
public URI getTermsOfService() {
return getUri("terms-of-service");
return meta.get("terms-of-service").asURI();
}
/**
@ -58,73 +52,31 @@ public class Metadata {
* server. {@code null} if not available.
*/
public URI getWebsite() {
return getUri("website");
return meta.get("website").asURI();
}
/**
* Returns an array of hostnames, which the ACME server recognises as referring to
* Returns a collection of hostnames, which the ACME server recognises as referring to
* itself for the purposes of CAA record validation. {@code null} if not available.
*/
public String[] getCaaIdentities() {
return getStringArray("caa-identities");
}
/**
* Gets a custom metadata value, as {@link String}.
*
* @param key
* Key of the meta value
* @return Value as {@link String}, or {@code null} if there is no such key in the
* directory metadata.
*/
public String get(String key) {
Object value = meta.get(key);
return value != null ? value.toString() : null;
}
/**
* Gets a custom metadata value, as {@link URI}.
*
* @param key
* Key of the meta value
* @return Value as {@link URI}, or {@code null} if there is no such key in the
* directory metadata.
* @throws AcmeProtocolException
* if the value is not an {@link URI}
*/
public URI getUri(String key) {
Object uri = meta.get(key);
try {
return uri != null ? new URI(uri.toString()) : null;
} catch (URISyntaxException ex) {
throw new AcmeProtocolException("Bad URI: " + uri, ex);
public Collection<String> getCaaIdentities() {
Array array = meta.get("caa-identities").asArray();
if (array == null) {
return null;
}
}
/**
* Gets a custom metadata value, as array of {@link String}.
*
* @param key
* Key of the meta value
* @return {@link String} array, or {@code null} if there is no such key in the
* directory metadata.
*/
@SuppressWarnings("unchecked")
public String[] getStringArray(String key) {
Object value = meta.get(key);
if (value != null && value instanceof Collection) {
Collection<String> data = (Collection<String>) value;
return data.toArray(new String[data.size()]);
List<String> result = new ArrayList<>(array.size());
for (Value v : array) {
result.add(v.asString());
}
return null;
return result;
}
/**
* Returns the metadata as raw JSON map.
* <p>
* Do not modify the map or its contents. Changes will have a session-wide effect.
* Returns the JSON representation of the metadata. This is useful for reading
* proprietary metadata properties.
*/
public Map<String, Object> getJsonData() {
public JSON getJSON() {
return meta;
}

View File

@ -17,17 +17,14 @@ import static org.shredzone.acme4j.util.AcmeUtils.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.jose4j.jwk.PublicJsonWebKey;
@ -39,6 +36,7 @@ import org.shredzone.acme4j.connector.ResourceIterator;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -162,7 +160,7 @@ public class Registration extends AcmeResource {
conn.sendSignedRequest(getLocation(), claims, getSession());
conn.accept(HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_ACCEPTED);
Map<String, Object> json = conn.readJsonResponse();
JSON json = conn.readJsonResponse();
unmarshal(json, conn);
}
}
@ -193,7 +191,7 @@ public class Registration extends AcmeResource {
conn.sendSignedRequest(getSession().resourceUri(Resource.NEW_AUTHZ), claims, getSession());
conn.accept(HttpURLConnection.HTTP_CREATED);
Map<String, Object> json = conn.readJsonResponse();
JSON json = conn.readJsonResponse();
Authorization auth = new Authorization(getSession(), conn.getLocation());
auth.unmarshalAuthorization(json);
@ -350,49 +348,23 @@ public class Registration extends AcmeResource {
* @param conn
* {@link Connection} with headers to be evaluated
*/
@SuppressWarnings("unchecked")
private void unmarshal(Map<String, Object> json, Connection conn) {
if (json.containsKey("agreement")) {
try {
this.agreement = new URI((String) json.get("agreement"));
} catch (ClassCastException | URISyntaxException ex) {
throw new AcmeProtocolException("Illegal agreement URI", ex);
}
private void unmarshal(JSON json, Connection conn) {
if (json.contains("agreement")) {
this.agreement = json.get("agreement").asURI();
}
if (json.containsKey("contact")) {
if (json.contains("contact")) {
contacts.clear();
for (Object c : (Collection<Object>) json.get("contact")) {
try {
contacts.add(new URI((String) c));
} catch (ClassCastException | URISyntaxException ex) {
throw new AcmeProtocolException("Illegal contact URI", ex);
}
for (JSON.Value v : json.get("contact").asArray()) {
contacts.add(v.asURI());
}
}
if (json.containsKey("authorizations")) {
try {
this.authorizations = new URI((String) json.get("authorizations"));
} catch (ClassCastException | URISyntaxException ex) {
throw new AcmeProtocolException("Illegal authorizations URI", ex);
}
} else {
this.authorizations = null;
}
this.authorizations = json.get("authorizations").asURI();
this.certificates = json.get("certificates").asURI();
if (json.containsKey("certificates")) {
try {
this.certificates = new URI((String) json.get("certificates"));
} catch (ClassCastException | URISyntaxException ex) {
throw new AcmeProtocolException("Illegal certificates URI", ex);
}
} else {
this.certificates = null;
}
if (json.containsKey("status")) {
this.status = Status.parse((String) json.get("status"));
if (json.contains("status")) {
this.status = Status.parse(json.get("status").asString());
}
URI location = conn.getLocation();
@ -490,7 +462,7 @@ public class Registration extends AcmeResource {
conn.sendSignedRequest(getLocation(), claims, getSession());
conn.accept(HttpURLConnection.HTTP_ACCEPTED);
Map<String, Object> json = conn.readJsonResponse();
JSON json = conn.readJsonResponse();
unmarshal(json, conn);
}
}

View File

@ -14,7 +14,6 @@
package org.shredzone.acme4j;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Date;
@ -29,8 +28,8 @@ import org.shredzone.acme4j.challenge.Challenge;
import org.shredzone.acme4j.challenge.TokenChallenge;
import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.provider.AcmeProvider;
import org.shredzone.acme4j.util.JSON;
/**
* A session stores the ACME server URI and the account's key pair. It also tracks
@ -46,7 +45,7 @@ public class Session {
private KeyPair keyPair;
private AcmeProvider provider;
private byte[] nonce;
private Map<String, Object> directoryMap;
private JSON directoryJson;
private Metadata metadata;
private Locale locale = Locale.getDefault();
protected Date directoryCacheExpiry;
@ -162,17 +161,14 @@ public class Session {
* Challenge JSON data
* @return {@link Challenge} instance
*/
public Challenge createChallenge(Map<String, Object> data) {
public Challenge createChallenge(JSON data) {
Objects.requireNonNull(data, "data");
String type = (String) data.get("type");
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type must not be empty or null");
}
String type = data.get("type").required().asString();
Challenge challenge = provider().createChallenge(this, type);
if (challenge == null) {
if (data.containsKey("token")) {
if (data.contains("token")) {
challenge = new TokenChallenge(this);
} else {
challenge = new Challenge(this);
@ -210,30 +206,25 @@ public class Session {
* Reads the provider's directory, then rebuild the resource map. The response is
* cached.
*/
@SuppressWarnings("unchecked")
private void readDirectory() throws AcmeException {
synchronized (this) {
Date now = new Date();
if (directoryMap == null || !directoryCacheExpiry.after(now)) {
directoryMap = provider().directory(this, getServerUri());
if (directoryJson == null || !directoryCacheExpiry.after(now)) {
directoryJson = provider().directory(this, getServerUri());
directoryCacheExpiry = new Date(now.getTime() + 60 * 60 * 1000L);
Object meta = directoryMap.get("meta");
if (meta != null && meta instanceof Map) {
metadata = new Metadata((Map<String, Object>) meta);
JSON meta = directoryJson.get("meta").asObject();
if (meta != null) {
metadata = new Metadata(meta);
} else {
metadata = new Metadata();
metadata = new Metadata(JSON.empty());
}
resourceMap.clear();
for (Map.Entry<String, Object> entry : directoryMap.entrySet()) {
Resource res = Resource.parse(entry.getKey());
if (res != null) {
try {
resourceMap.put(res, new URI(entry.getValue().toString()));
} catch (URISyntaxException ex) {
throw new AcmeProtocolException("Illegal URI for resource " + res, ex);
}
for (Resource res : Resource.values()) {
URI uri = directoryJson.get(res.path()).asURI();
if (uri != null) {
resourceMap.put(res, uri);
}
}
}

View File

@ -13,22 +13,11 @@
*/
package org.shredzone.acme4j.challenge;
import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.jose4j.json.JsonUtil;
import org.jose4j.lang.JoseException;
import org.shredzone.acme4j.AcmeResource;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.Status;
@ -36,6 +25,7 @@ import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -58,7 +48,7 @@ public class Challenge extends AcmeResource {
protected static final String KEY_URI = "uri";
protected static final String KEY_VALIDATED = "validated";
private transient Map<String, Object> data = new HashMap<>();
private JSON data = JSON.empty();
/**
* Returns a {@link Challenge} object of an existing challenge.
@ -79,8 +69,8 @@ public class Challenge extends AcmeResource {
conn.sendRequest(location, session);
conn.accept(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED);
Map<String, Object> json = conn.readJsonResponse();
if (!(json.containsKey("type"))) {
JSON json = conn.readJsonResponse();
if (!(json.contains("type"))) {
throw new IllegalArgumentException("Provided URI is not a challenge URI");
}
@ -102,14 +92,14 @@ public class Challenge extends AcmeResource {
* Returns the challenge type by name (e.g. "http-01").
*/
public String getType() {
return get(KEY_TYPE);
return data.get(KEY_TYPE).asString();
}
/**
* Returns the current status of the challenge.
*/
public Status getStatus() {
return Status.parse((String) get(KEY_STATUS), Status.PENDING);
return Status.parse(data.get(KEY_STATUS).asString(), Status.PENDING);
}
/**
@ -117,24 +107,21 @@ public class Challenge extends AcmeResource {
*/
@Override
public URI getLocation() {
String uri = get(KEY_URI);
if (uri == null) {
return null;
}
return URI.create(uri);
return data.get(KEY_URI).asURI();
}
/**
* Returns the validation date, if returned by the server.
*/
public Date getValidated() {
String valStr = get(KEY_VALIDATED);
if (valStr != null) {
return parseTimestamp(valStr);
} else {
return null;
}
return data.get(KEY_VALIDATED).asDate();
}
/**
* Returns the JSON representation of the challenge data.
*/
protected JSON getJSON() {
return data;
}
/**
@ -161,11 +148,11 @@ public class Challenge extends AcmeResource {
/**
* Sets the challenge state to the given JSON map.
*
* @param map
* JSON map containing the challenge data
* @param json
* JSON containing the challenge data
*/
public void unmarshall(Map<String, Object> map) {
String type = (String) map.get(KEY_TYPE);
public void unmarshall(JSON json) {
String type = json.get(KEY_TYPE).asString();
if (type == null) {
throw new IllegalArgumentException("map does not contain a type");
}
@ -173,39 +160,10 @@ public class Challenge extends AcmeResource {
throw new AcmeProtocolException("wrong type: " + type);
}
data.clear();
data.putAll(map);
data = json;
authorize();
}
/**
* Gets a value from the challenge state.
*
* @param key
* Key
* @return Value, or {@code null} if not set
*/
@SuppressWarnings("unchecked")
protected <T> T get(String key) {
return (T) data.get(key);
}
/**
* Gets an {@link URL} value from the challenge state.
*
* @param key
* Key
* @return Value, or {@code null} if not set
*/
protected URL getUrl(String key) {
try {
String value = get(key);
return value != null ? new URL(value) : null;
} catch (MalformedURLException ex) {
throw new AcmeProtocolException(key + ": invalid URL", ex);
}
}
/**
* Callback that is invoked when the challenge is supposed to compute its
* authorization data.
@ -260,24 +218,4 @@ public class Challenge extends AcmeResource {
}
}
/**
* 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 AcmeProtocolException("Cannot deserialize", ex);
}
}
}

View File

@ -43,7 +43,7 @@ public class OutOfBand01Challenge extends Challenge {
* challenge.
*/
public URL getValidationUrl() {
return getUrl("href");
return getJSON().get("href").asURL();
}
}

View File

@ -56,11 +56,7 @@ public class TokenChallenge extends Challenge {
* Gets the token.
*/
protected String getToken() {
String token = get(KEY_TOKEN);
if (token == null) {
throw new AcmeProtocolException("Challenge token required, but not set");
}
return token;
return getJSON().get(KEY_TOKEN).required().asString();
}
/**

View File

@ -17,11 +17,11 @@ import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.JSON;
/**
* Connects to the ACME server and offers different methods for invoking the API.
@ -63,9 +63,9 @@ public interface Connection extends AutoCloseable {
/**
* Reads a server response as JSON data.
*
* @return Map containing the parsed JSON data
* @return The JSON response
*/
Map<String, Object> readJsonResponse() throws AcmeException;
JSON readJsonResponse() throws AcmeException;
/**
* Reads a certificate.

View File

@ -15,10 +15,8 @@ package org.shredzone.acme4j.connector;
import static org.shredzone.acme4j.util.AcmeUtils.keyAlgorithm;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
@ -39,7 +37,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jose4j.base64url.Base64Url;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwk.PublicJsonWebKey;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.lang.JoseException;
@ -52,6 +49,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRateLimitExceededException;
import org.shredzone.acme4j.exception.AcmeServerException;
import org.shredzone.acme4j.exception.AcmeUnauthorizedException;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -177,15 +175,15 @@ public class DefaultConnection implements Connection {
throw new AcmeException("HTTP " + rc + ": " + conn.getResponseMessage());
}
Map<String, Object> map = readJsonResponse();
throw createAcmeException(rc, map);
JSON json = readJsonResponse();
throw createAcmeException(rc, json);
} catch (IOException ex) {
throw new AcmeNetworkException(ex);
}
}
@Override
public Map<String, Object> readJsonResponse() throws AcmeException {
public JSON readJsonResponse() throws AcmeException {
assertConnectionIsOpen();
String contentType = conn.getHeaderField("Content-Type");
@ -194,41 +192,23 @@ public class DefaultConnection implements Connection {
throw new AcmeProtocolException("Unexpected content type: " + contentType);
}
Map<String, Object> result = null;
JSON result = null;
String response = "";
try {
InputStream in =
conn.getResponseCode() < 400 ? conn.getInputStream() : conn.getErrorStream();
if (in != null) {
response = readStream(in);
result = JsonUtil.parseJson(response);
result = JSON.parse(in);
LOG.debug("Result JSON: {}", response);
}
} catch (IOException ex) {
throw new AcmeNetworkException(ex);
} catch (JoseException ex) {
throw new AcmeProtocolException("Failed to parse response: " + response, ex);
}
return result;
}
private String readStream(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"))) {
String line = reader.readLine();
while (line != null) {
sb.append(line.trim());
line = reader.readLine();
}
}
return sb.toString();
}
@Override
public X509Certificate readCertificate() throws AcmeException {
assertConnectionIsOpen();
@ -351,9 +331,9 @@ public class DefaultConnection implements Connection {
* {@link AcmeServerException} will be thrown. Otherwise a generic
* {@link AcmeException} is thrown.
*/
private AcmeException createAcmeException(int rc, Map<String, Object> map) {
String type = (String) map.get("type");
String detail = (String) map.get("detail");
private AcmeException createAcmeException(int rc, JSON json) {
String type = json.get("type").asString();
String detail = json.get("detail").asString();
if (detail == null) {
detail = "general problem";
@ -374,7 +354,7 @@ public class DefaultConnection implements Connection {
case ACME_ERROR_PREFIX + "agreementRequired":
case ACME_ERROR_PREFIX_DEPRECATED + "agreementRequired":
String instance = (String) map.get("instance");
String instance = json.get("instance").asString();
return new AcmeAgreementRequiredException(
type, detail, getLink("terms-of-service"),
instance != null ? resolveRelative(instance) : null);

View File

@ -15,18 +15,16 @@ package org.shredzone.acme4j.connector;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import org.shredzone.acme4j.AcmeResource;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.util.JSON;
/**
* An {@link Iterator} that fetches a batch of URIs from the ACME server, and
@ -147,7 +145,7 @@ public abstract class ResourceIterator<T extends AcmeResource> implements Iterat
conn.sendRequest(nextUri, session);
conn.accept(HttpURLConnection.HTTP_OK);
Map<String, Object> json = conn.readJsonResponse();
JSON json = conn.readJsonResponse();
fillUriList(json);
nextUri = conn.getLink("next");
@ -160,21 +158,13 @@ public abstract class ResourceIterator<T extends AcmeResource> implements Iterat
* @param json
* JSON map to read from
*/
private void fillUriList(Map<String, Object> json) {
try {
@SuppressWarnings("unchecked")
Collection<String> array = (Collection<String>) json.get(field);
if (array == null) {
return;
}
for (String uri : array) {
uriList.add(new URI(uri));
}
} catch (ClassCastException ex) {
throw new AcmeProtocolException("Expected an array", ex);
} catch (URISyntaxException ex) {
throw new AcmeProtocolException("Invalid URI", ex);
private void fillUriList(JSON json) {
JSON.Array array = json.get(field).asArray();
if (array == null) {
return;
}
for (JSON.Value v : array) {
uriList.add(v.asURI());
}
}

View File

@ -15,7 +15,6 @@ package org.shredzone.acme4j.provider;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Map;
import java.util.Objects;
import org.shredzone.acme4j.Session;
@ -28,6 +27,7 @@ import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.connector.DefaultConnection;
import org.shredzone.acme4j.connector.HttpConnector;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSON;
/**
* Abstract implementation of {@link AcmeProvider}. It consists of a challenge
@ -44,7 +44,7 @@ public abstract class AbstractAcmeProvider implements AcmeProvider {
}
@Override
public Map<String, Object> directory(Session session, URI serverUri) throws AcmeException {
public JSON directory(Session session, URI serverUri) throws AcmeException {
try (Connection conn = connect()) {
conn.sendRequest(resolve(serverUri), session);
conn.accept(HttpURLConnection.HTTP_OK);

View File

@ -14,13 +14,13 @@
package org.shredzone.acme4j.provider;
import java.net.URI;
import java.util.Map;
import java.util.ServiceLoader;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.challenge.Challenge;
import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSON;
/**
* An {@link AcmeProvider} provides methods to be used for communicating with the ACME
@ -69,9 +69,9 @@ public interface AcmeProvider {
* {@link Session} to be used
* @param serverUri
* Server {@link URI}
* @return Map of directory data
* @return Directory data, as JSON object
*/
Map<String, Object> directory(Session session, URI serverUri) throws AcmeException;
JSON directory(Session session, URI serverUri) throws AcmeException;
/**
* Creates a {@link Challenge} instance for the given challenge type.

View File

@ -0,0 +1,386 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2016 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j.util;
import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.jose4j.json.JsonUtil;
import org.jose4j.lang.JoseException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
/**
* A model containing a JSON result. The content is immutable.
*/
@SuppressWarnings("unchecked")
public final class JSON implements Serializable {
private static final long serialVersionUID = 3091273044605709204L;
private static final JSON EMPTY_JSON = new JSON(new HashMap<String, Object>());
private final String path;
private Map<String, Object> data;
/**
* Creates a new {@link JSON} root object.
*
* @param data
* {@link Map} containing the parsed JSON data
*/
private JSON(Map<String, Object> data) {
this("", data);
}
/**
* Creates a new {@link JSON} branch object.
*
* @param path
* Path leading to this branch.
* @param data
* {@link Map} containing the parsed JSON data
*/
private JSON(String path, Map<String, Object> data) {
this.path = path;
this.data = data;
}
/**
* Parses JSON from an {@link InputStream}.
*
* @param in
* {@link InputStream} to read from. Will be closed after use.
* @return {@link JSON} of the read content.
*/
public static JSON parse(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"))) {
String line = reader.readLine();
while (line != null) {
sb.append(line.trim());
line = reader.readLine();
}
}
return parse(sb.toString());
}
/**
* Parses JSON from a String.
*
* @param json
* JSON string
* @return {@link JSON} of the read content.
*/
public static JSON parse(String json) {
try {
return new JSON(JsonUtil.parseJson(json));
} catch (JoseException ex) {
throw new AcmeProtocolException("Bad JSON: " + json, ex);
}
}
/**
* Returns a {@link JSON} of an empty document.
*/
public static JSON empty() {
return EMPTY_JSON;
}
/**
* Returns a {@link Set} of all keys of this object.
*/
public Set<String> keySet() {
return Collections.unmodifiableSet(data.keySet());
}
/**
* Checks if this object contains the given key.
*
* @param key
* Name of the key to check
* @return {@code true} if the key is present
*/
public boolean contains(String key) {
return data.containsKey(key);
}
/**
* Returns the {@link Value} of the given key.
*
* @param key
* Key to read
* @return {@link Value} of the key
*/
public Value get(String key) {
return new Value(
path.isEmpty() ? key : path + '.' + key,
data.get(key));
}
/**
* Returns the content as JSON string.
*/
@Override
public String toString() {
return JsonUtil.toJson(data);
}
/**
* 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 AcmeProtocolException("Cannot deserialize", ex);
}
}
/**
* Represents a JSON array.
*/
public static final class Array implements Iterable<Value> {
private final String path;
private final List<Object> data;
/**
* Creates a new {@link Array} object.
*
* @param path
* JSON path to this array.
* @param data
* Array data
*/
private Array(String path, List<Object> data) {
this.path = path;
this.data = data;
}
/**
* Returns the array size.
*/
public int size() {
return data.size();
}
/**
* Gets the {@link Value} at the given index.
*
* @param index
* Array index to read from
* @return {@link Value} at this index
*/
public Value get(int index) {
return new Value(path + '[' + index + ']', data.get(index));
}
/**
* Creates a new {@link Iterator} that iterates over the array {@link Value}.
*/
@Override
public Iterator<Value> iterator() {
return new ValueIterator(this);
}
}
/**
* A single JSON value. This instance also covers {@code null} values.
*/
public static final class Value {
private final String path;
private final Object val;
/**
* Creates a new {@link Value}.
*
* @param path
* JSON path to this value
* @param val
* Value, may be {@code null}
*/
private Value(String path, Object val) {
this.path = path;
this.val = val;
}
/**
* Checks if the value is present. An {@link AcmeProtocolException} is thrown
* if the value is {@code null}.
*/
public Value required() {
if (val == null) {
throw new AcmeProtocolException(path + ": required, but not set");
}
return this;
}
/**
* Returns the value as {@link String}. May be {@code null}.
*/
public String asString() {
return val != null ? val.toString() : null;
}
/**
* Returns the value as {@link JSON} object. May be {@code null}.
*/
public JSON asObject() {
if (val == null) {
return null;
}
try {
return new JSON(path, (Map<String, Object>) val);
} catch (ClassCastException ex) {
throw new AcmeProtocolException(path + ": expected an object", ex);
}
}
/**
* Returns the value as JSON {@link Array}. May be {@code null}.
*/
public Array asArray() {
if (val == null) {
return null;
}
try {
return new Array(path, (List<Object>) val);
} catch (ClassCastException ex) {
throw new AcmeProtocolException(path + ": expected an array", ex);
}
}
/**
* Returns the value as int.
*/
public int asInt() {
required();
try {
return ((Number) val).intValue();
} catch (ClassCastException ex) {
throw new AcmeProtocolException(path + ": bad number " + val, ex);
}
}
/**
* Returns the value as {@link URI}. May be {@code null}.
*/
public URI asURI() {
if (val == null) {
return null;
}
try {
return new URI(val.toString());
} catch (URISyntaxException ex) {
throw new AcmeProtocolException(path + ": bad URI " + val, ex);
}
}
/**
* Returns the value as {@link URL}. May be {@code null}.
*/
public URL asURL() {
if (val == null) {
return null;
}
try {
return new URL(val.toString());
} catch (MalformedURLException ex) {
throw new AcmeProtocolException(path + ": bad URL " + val, ex);
}
}
/**
* Returns the value as {@link Date}. May be {@code null}. The returned
* {@link Date} object is not shared, changes are not reflected in the JSON
* object.
*/
public Date asDate() {
if (val == null) {
return null;
}
try {
return parseTimestamp(val.toString());
} catch (IllegalArgumentException ex) {
throw new AcmeProtocolException(path + ": bad date " + val, ex);
}
}
}
/**
* An {@link Iterator} over array {@link Value}.
*/
private static class ValueIterator implements Iterator<Value> {
private final Array array;
private int index = 0;
public ValueIterator(Array array) {
this.array = array;
}
@Override
public boolean hasNext() {
return index < array.size();
}
@Override
public Value next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return array.get(index++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -175,6 +175,13 @@ public class JSONBuilder {
return Collections.unmodifiableMap(data);
}
/**
* Returns a {@link JSON} representation of the current state.
*/
public JSON toJSON() {
return JSON.parse(toString());
}
/**
* Returns a JSON string representation of the current state.
*/

View File

@ -23,7 +23,6 @@ import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
@ -34,6 +33,7 @@ import org.shredzone.acme4j.challenge.TlsSni02Challenge;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
/**
@ -132,8 +132,8 @@ public class AuthorizationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateAuthorizationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateAuthorizationResponse");
}
};
@ -186,8 +186,8 @@ public class AuthorizationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateAuthorizationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateAuthorizationResponse");
}
};
@ -234,8 +234,8 @@ public class AuthorizationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateAuthorizationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateAuthorizationResponse");
}
@Override
@ -285,9 +285,9 @@ public class AuthorizationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) {
Map<String, Object> claimMap = claims.toMap();
assertThat(claimMap.get("resource"), is((Object) "authz"));
assertThat(claimMap.get("status"), is((Object) "deactivated"));
JSON json = claims.toJSON();
assertThat(json.get("resource").asString(), is("authz"));
assertThat(json.get("status").asString(), is("deactivated"));
assertThat(uri, is(locationUri));
assertThat(session, is(notNullValue()));
}
@ -318,7 +318,7 @@ public class AuthorizationTest {
provider.putTestChallenge(TlsSni02Challenge.TYPE, new TlsSni02Challenge(session));
Authorization authorization = new Authorization(session, locationUri);
authorization.unmarshalAuthorization(getJsonAsMap("authorizationChallenges"));
authorization.unmarshalAuthorization(getJsonAsObject("authorizationChallenges"));
return authorization;
}
}

View File

@ -23,11 +23,8 @@ import java.net.HttpURLConnection;
import java.net.URI;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
@ -43,6 +40,7 @@ import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.provider.AcmeProvider;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.TestUtils;
@ -62,7 +60,7 @@ public class RegistrationTest {
@Test
public void testUpdateRegistration() throws AcmeException, IOException {
TestableConnectionProvider provider = new TestableConnectionProvider() {
private Map<String, Object> jsonResponse;
private JSON jsonResponse;
private Integer response;
@Override
@ -70,24 +68,24 @@ public class RegistrationTest {
assertThat(uri, is(locationUri));
assertThat(claims.toString(), sameJSONAs(getJson("updateRegistration")));
assertThat(session, is(notNullValue()));
jsonResponse = getJsonAsMap("updateRegistrationResponse");
jsonResponse = getJsonAsObject("updateRegistrationResponse");
response = HttpURLConnection.HTTP_ACCEPTED;
}
@Override
public void sendRequest(URI uri, Session session) {
if (URI.create("https://example.com/acme/reg/1/authz").equals(uri)) {
jsonResponse = new HashMap<>();
jsonResponse.put("authorizations",
Arrays.asList("https://example.com/acme/auth/1"));
jsonResponse = new JSONBuilder()
.array("authorizations", "https://example.com/acme/auth/1")
.toJSON();
response = HttpURLConnection.HTTP_OK;
return;
}
if (URI.create("https://example.com/acme/reg/1/cert").equals(uri)) {
jsonResponse = new HashMap<>();
jsonResponse.put("certificates",
Arrays.asList("https://example.com/acme/cert/1"));
jsonResponse = new JSONBuilder()
.array("certificates", "https://example.com/acme/cert/1")
.toJSON();
response = HttpURLConnection.HTTP_OK;
return;
}
@ -102,7 +100,7 @@ public class RegistrationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
public JSON readJsonResponse() {
return jsonResponse;
}
@ -167,8 +165,8 @@ public class RegistrationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateRegistrationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateRegistrationResponse");
}
@Override
@ -221,8 +219,8 @@ public class RegistrationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("newAuthorizationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("newAuthorizationResponse");
}
@Override
@ -417,12 +415,12 @@ public class RegistrationTest {
assertThat(session, is(notNullValue()));
assertThat(session.getKeyPair(), is(sameInstance(oldKeyPair)));
Map<String, Object> json = payload.toMap();
assertThat((String) json.get("resource"), is("key-change")); // Required by Let's Encrypt
JSON json = payload.toJSON();
assertThat(json.get("resource").asString(), is("key-change")); // Required by Let's Encrypt
String encodedHeader = (String) json.get("protected");
String encodedSignature = (String) json.get("signature");
String encodedPayload = (String) json.get("payload");
String encodedHeader = json.get("protected").asString();
String encodedSignature = json.get("signature").asString();
String encodedPayload = json.get("payload").asString();
String serialized = CompactSerializer.serialize(encodedHeader, encodedPayload, encodedSignature);
JsonWebSignature jws = new JsonWebSignature();
@ -497,9 +495,9 @@ public class RegistrationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) {
Map<String, Object> claimMap = claims.toMap();
assertThat(claimMap.get("resource"), is((Object) "reg"));
assertThat(claimMap.get("status"), is((Object) "deactivated"));
JSON json = claims.toJSON();
assertThat(json.get("resource").asString(), is("reg"));
assertThat(json.get("status").asString(), is("deactivated"));
assertThat(uri, is(locationUri));
assertThat(session, is(notNullValue()));
}
@ -540,8 +538,8 @@ public class RegistrationTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("modifyRegistrationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("modifyRegistrationResponse");
}
@Override

View File

@ -16,12 +16,12 @@ package org.shredzone.acme4j;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import java.io.IOException;
import java.net.URI;
import java.security.KeyPair;
import java.util.Date;
import java.util.Map;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
@ -30,6 +30,7 @@ import org.shredzone.acme4j.challenge.Http01Challenge;
import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.provider.AcmeProvider;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.TestUtils;
@ -117,9 +118,9 @@ public class SessionTest {
URI serverUri = URI.create(TestUtils.ACME_SERVER_URI);
String challengeType = Http01Challenge.TYPE;
Map<String, Object> data = new JSONBuilder()
JSON data = new JSONBuilder()
.put("type", challengeType)
.toMap();
.toJSON();
Http01Challenge mockChallenge = mock(Http01Challenge.class);
final AcmeProvider mockProvider = mock(AcmeProvider.class);
@ -155,7 +156,7 @@ public class SessionTest {
when(mockProvider.directory(
ArgumentMatchers.any(Session.class),
ArgumentMatchers.eq(serverUri)))
.thenReturn(TestUtils.getJsonAsMap("directory"));
.thenReturn(getJsonAsObject("directory"));
Session session = new Session(serverUri, keyPair) {
@Override
@ -193,7 +194,7 @@ public class SessionTest {
when(mockProvider.directory(
ArgumentMatchers.any(Session.class),
ArgumentMatchers.eq(serverUri)))
.thenReturn(TestUtils.getJsonAsMap("directoryNoMeta"));
.thenReturn(getJsonAsObject("directoryNoMeta"));
Session session = new Session(serverUri, keyPair) {
@Override
@ -239,10 +240,8 @@ public class SessionTest {
assertThat(meta, not(nullValue()));
assertThat(meta.getTermsOfService(), is(URI.create("https://example.com/acme/terms")));
assertThat(meta.getWebsite(), is(URI.create("https://www.example.com/")));
assertThat(meta.getCaaIdentities(), is(arrayContaining("example.com")));
assertThat(meta.get("x-test-string"), is("foobar"));
assertThat(meta.getUri("x-test-uri"), is(URI.create("https://www.example.org")));
assertThat(meta.getStringArray("x-test-array"), is(arrayContaining("foo", "bar", "barfoo")));
assertThat(meta.getCaaIdentities(), containsInAnyOrder("example.com"));
assertThat(meta.getJSON(), is(notNullValue()));
}
}

View File

@ -19,20 +19,14 @@ import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp;
import static org.shredzone.acme4j.util.TestUtils.*;
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.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
import java.util.Map;
import org.jose4j.json.JsonUtil;
import org.jose4j.lang.JoseException;
import org.junit.Before;
import org.junit.Test;
@ -42,6 +36,7 @@ import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.TestUtils;
@ -77,8 +72,8 @@ public class ChallengeTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateHttpChallengeResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateHttpChallengeResponse");
}
};
@ -110,24 +105,17 @@ public class ChallengeTest {
assertThat(challenge.getValidated(), is(nullValue()));
// Unmarshall a challenge JSON
challenge.unmarshall(TestUtils.getJsonAsMap("genericChallenge"));
challenge.unmarshall(getJsonAsObject("genericChallenge"));
// Test unmarshalled values
assertThat(challenge.getType(), is("generic-01"));
assertThat(challenge.getStatus(), is(Status.VALID));
assertThat(challenge.getLocation(), is(new URI("http://example.com/challenge/123")));
assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z")));
assertThat((String) challenge.get("type"), is("generic-01"));
assertThat(challenge.getUrl("uri"), is(new URL("http://example.com/challenge/123")));
assertThat(challenge.get("not-present"), is(nullValue()));
assertThat(challenge.getUrl("not-present-url"), is(nullValue()));
try {
challenge.getUrl("type");
fail("bad URL is not detected");
} catch (AcmeProtocolException ex) {
// expected
}
assertThat(challenge.getJSON().get("type").asString(), is("generic-01"));
assertThat(challenge.getJSON().get("uri").asURL(), is(new URL("http://example.com/challenge/123")));
assertThat(challenge.getJSON().get("not-present").asString(), is(nullValue()));
assertThat(challenge.getJSON().get("not-present-url").asURL(), is(nullValue()));
}
/**
@ -138,7 +126,7 @@ public class ChallengeTest {
String json = TestUtils.getJson("genericChallenge");
Challenge challenge = new Challenge(session);
challenge.unmarshall(JsonUtil.parseJson(json));
challenge.unmarshall(JSON.parse(json));
JSONBuilder cb = new JSONBuilder();
challenge.respond(cb);
@ -152,7 +140,7 @@ public class ChallengeTest {
@Test(expected = AcmeProtocolException.class)
public void testNotAcceptable() throws URISyntaxException {
Http01Challenge challenge = new Http01Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("dnsChallenge"));
challenge.unmarshall(getJsonAsObject("dnsChallenge"));
}
/**
@ -176,15 +164,15 @@ public class ChallengeTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("triggerHttpChallengeResponse");
public JSON readJsonResponse() {
return getJsonAsObject("triggerHttpChallengeResponse");
}
};
Session session = provider.createSession();
Http01Challenge challenge = new Http01Challenge(session);
challenge.unmarshall(getJsonAsMap("triggerHttpChallenge"));
challenge.unmarshall(getJsonAsObject("triggerHttpChallenge"));
challenge.trigger();
@ -213,15 +201,15 @@ public class ChallengeTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateHttpChallengeResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateHttpChallengeResponse");
}
};
Session session = provider.createSession();
Challenge challenge = new Http01Challenge(session);
challenge.unmarshall(getJsonAsMap("triggerHttpChallengeResponse"));
challenge.unmarshall(getJsonAsObject("triggerHttpChallengeResponse"));
challenge.update();
@ -252,8 +240,8 @@ public class ChallengeTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateHttpChallengeResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateHttpChallengeResponse");
}
@Override
@ -265,7 +253,7 @@ public class ChallengeTest {
Session session = provider.createSession();
Challenge challenge = new Http01Challenge(session);
challenge.unmarshall(getJsonAsMap("triggerHttpChallengeResponse"));
challenge.unmarshall(getJsonAsObject("triggerHttpChallengeResponse"));
try {
challenge.update();
@ -319,8 +307,8 @@ public class ChallengeTest {
}
@Override
public Map<String, Object> readJsonResponse() {
return getJsonAsMap("updateRegistrationResponse");
public JSON readJsonResponse() {
return getJsonAsObject("updateRegistrationResponse");
}
};
@ -336,39 +324,7 @@ public class ChallengeTest {
@Test(expected = IllegalArgumentException.class)
public void testBadUnmarshall() {
Challenge challenge = new Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("updateRegistrationResponse"));
}
/**
* Test that challenge serialization works correctly.
*/
@Test
public void testSerialization() throws IOException, ClassNotFoundException {
Http01Challenge originalChallenge = new Http01Challenge(session);
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(Http01Challenge.class)));
assertThat(testChallenge.getType(), is(Http01Challenge.TYPE));
assertThat(testChallenge.getStatus(), is(Status.PENDING));
assertThat(((Http01Challenge )testChallenge).getToken(), is("rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ"));
challenge.unmarshall(getJsonAsObject("updateRegistrationResponse"));
}
}

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.challenge;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException;
@ -46,7 +47,7 @@ public class DnsChallengeTest {
@Test
public void testDnsChallenge() throws IOException {
Dns01Challenge challenge = new Dns01Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("dnsChallenge"));
challenge.unmarshall(getJsonAsObject("dnsChallenge"));
assertThat(challenge.getType(), is(Dns01Challenge.TYPE));
assertThat(challenge.getStatus(), is(Status.PENDING));

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.challenge;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException;
@ -49,7 +50,7 @@ public class HttpChallengeTest {
@Test
public void testHttpChallenge() throws IOException {
Http01Challenge challenge = new Http01Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("httpChallenge"));
challenge.unmarshall(getJsonAsObject("httpChallenge"));
assertThat(challenge.getType(), is(Http01Challenge.TYPE));
assertThat(challenge.getStatus(), is(Status.PENDING));
@ -69,7 +70,7 @@ public class HttpChallengeTest {
@Test(expected = AcmeProtocolException.class)
public void testNoTokenSet() {
Http01Challenge challenge = new Http01Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("httpNoTokenChallenge"));
challenge.unmarshall(getJsonAsObject("httpNoTokenChallenge"));
challenge.getToken();
}

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.challenge;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException;
@ -44,7 +45,7 @@ public class OutOfBandChallengeTest {
@Test
public void testHttpChallenge() throws IOException {
OutOfBand01Challenge challenge = new OutOfBand01Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("oobChallenge"));
challenge.unmarshall(getJsonAsObject("oobChallenge"));
assertThat(challenge.getType(), is(OutOfBand01Challenge.TYPE));
assertThat(challenge.getStatus(), is(Status.PENDING));

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.challenge;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException;
@ -47,7 +48,7 @@ public class TlsSni01ChallengeTest {
@Test
public void testTlsSniChallenge() throws IOException {
TlsSni01Challenge challenge = new TlsSni01Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("tlsSniChallenge"));
challenge.unmarshall(getJsonAsObject("tlsSniChallenge"));
assertThat(challenge.getType(), is(TlsSni01Challenge.TYPE));
assertThat(challenge.getStatus(), is(Status.PENDING));

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.challenge;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException;
@ -46,7 +47,7 @@ public class TlsSni02ChallengeTest {
@Test
public void testTlsSni02Challenge() throws IOException {
TlsSni02Challenge challenge = new TlsSni02Challenge(session);
challenge.unmarshall(TestUtils.getJsonAsMap("tlsSni02Challenge"));
challenge.unmarshall(getJsonAsObject("tlsSni02Challenge"));
assertThat(challenge.getType(), is(TlsSni02Challenge.TYPE));
assertThat(challenge.getStatus(), is(Status.PENDING));

View File

@ -44,6 +44,7 @@ import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeNetworkException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeServerException;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.TestUtils;
@ -362,11 +363,11 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
@Override
public Map<String,Object> readJsonResponse() {
Map<String, Object> result = new HashMap<>();
public JSON readJsonResponse() {
JSONBuilder result = new JSONBuilder();
result.put("type", "urn:zombie:error:apocalypse");
result.put("detail", "Zombie apocalypse in progress");
return result;
return result.toJSON();
};
}) {
conn.conn = mockUrlConnection;
@ -397,8 +398,8 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
@Override
public Map<String,Object> readJsonResponse() {
return new HashMap<>();
public JSON readJsonResponse() {
return JSON.empty();
};
}) {
conn.conn = mockUrlConnection;
@ -553,10 +554,10 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
Map<String, Object> result = conn.readJsonResponse();
JSON result = conn.readJsonResponse();
assertThat(result.keySet(), hasSize(2));
assertThat(result, hasEntry("foo", (Object) 123L));
assertThat(result, hasEntry("bar", (Object) "a-string"));
assertThat(result.get("foo").asInt(), is(123));
assertThat(result.get("bar").asString(), is("a-string"));
}
verify(mockUrlConnection).getHeaderField("Content-Type");

View File

@ -17,11 +17,11 @@ import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.JSON;
/**
* Dummy implementation of {@link Connection} that always fails. Single methods are
@ -45,7 +45,7 @@ public class DummyConnection implements Connection {
}
@Override
public Map<String, Object> readJsonResponse() {
public JSON readJsonResponse() {
throw new UnsupportedOperationException();
}

View File

@ -23,19 +23,16 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import org.jose4j.json.JsonUtil;
import org.jose4j.lang.JoseException;
import org.junit.Before;
import org.junit.Test;
import org.shredzone.acme4j.Authorization;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.JSON;
/**
* Unit test for {@link ResourceIterator}.
@ -147,19 +144,14 @@ public class ResourceIteratorTest {
}
@Override
public Map<String, Object> readJsonResponse() {
try {
int start = ix * RESOURCES_PER_PAGE;
int end = (ix + 1) * RESOURCES_PER_PAGE;
public JSON readJsonResponse() {
int start = ix * RESOURCES_PER_PAGE;
int end = (ix + 1) * RESOURCES_PER_PAGE;
JSONBuilder cb = new JSONBuilder();
cb.array(TYPE, resourceURIs.subList(start, end).toArray());
JSONBuilder cb = new JSONBuilder();
cb.array(TYPE, resourceURIs.subList(start, end).toArray());
// Make sure to use the JSON parser
return JsonUtil.parseJson(cb.toString());
} catch (JoseException ex) {
throw new AcmeProtocolException("Invalid JSON", ex);
}
return JSON.parse(cb.toString());
}
@Override

View File

@ -19,7 +19,6 @@ import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.net.URI;
import java.security.KeyPair;
import java.util.Map;
import java.util.ServiceLoader;
import org.junit.Before;
@ -28,6 +27,7 @@ import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.challenge.Challenge;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.provider.AcmeProvider;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.TestUtils;
/**
@ -97,7 +97,7 @@ public class SessionProviderTest {
}
@Override
public Map<String, Object> directory(Session session, URI serverUri) throws AcmeException {
public JSON directory(Session session, URI serverUri) throws AcmeException {
throw new UnsupportedOperationException();
}
@ -125,7 +125,7 @@ public class SessionProviderTest {
}
@Override
public Map<String, Object> directory(Session session, URI serverUri) throws AcmeException {
public JSON directory(Session session, URI serverUri) throws AcmeException {
throw new UnsupportedOperationException();
}

View File

@ -17,14 +17,13 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jose4j.json.JsonUtil;
import org.junit.Test;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.challenge.Challenge;
@ -35,6 +34,7 @@ import org.shredzone.acme4j.challenge.TlsSni02Challenge;
import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.connector.DefaultConnection;
import org.shredzone.acme4j.connector.HttpConnector;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.TestUtils;
/**
@ -84,7 +84,7 @@ public class AbstractAcmeProviderTest {
final Session session = mock(Session.class);
when(connection.accept(any(Integer.class))).thenReturn(HttpURLConnection.HTTP_OK);
when(connection.readJsonResponse()).thenReturn(TestUtils.getJsonAsMap("directory"));
when(connection.readJsonResponse()).thenReturn(getJsonAsObject("directory"));
AbstractAcmeProvider provider = new AbstractAcmeProvider() {
@Override
@ -105,8 +105,8 @@ public class AbstractAcmeProviderTest {
}
};
Map<String, Object> map = provider.directory(session, testServerUri);
assertThat(JsonUtil.toJson(map), sameJSONAs(TestUtils.getJson("directory")));
JSON map = provider.directory(session, testServerUri);
assertThat(map.toString(), sameJSONAs(TestUtils.getJson("directory")));
verify(connection).sendRequest(testResolvedUri, session);
verify(connection).accept(any(Integer.class));

View File

@ -25,6 +25,7 @@ import org.shredzone.acme4j.connector.DummyConnection;
import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.TestUtils;
/**
@ -84,12 +85,11 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP
}
@Override
public Map<String, Object> directory(Session session, URI serverUri) throws AcmeException {
Map<String, Object> result = directory.toMap();
if (result.isEmpty()) {
public JSON directory(Session session, URI serverUri) throws AcmeException {
if (directory.toMap().isEmpty()) {
throw new UnsupportedOperationException();
}
return result;
return directory.toJSON();
}
@Override

View File

@ -69,6 +69,11 @@ public class JSONBuilderTest {
hasEntry("fooInt", (Object) 456),
hasEntry("fooStr", (Object) "String")
));
JSON json = cb.toJSON();
assertThat(json.keySet(), hasSize(2));
assertThat(json.get("fooInt").asInt(), is(456));
assertThat(json.get("fooStr").asString(), is("String"));
}
/**

View File

@ -0,0 +1,285 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2016 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j.util;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Calendar;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import org.junit.Test;
import org.shredzone.acme4j.exception.AcmeProtocolException;
/**
* Unit test for {@link JSON}.
*/
public class JSONTest {
/**
* Test that an empty {@link JSON} is empty.
*/
@Test
public void testEmpty() {
JSON empty = JSON.empty();
assertThat(empty.toString(), is("{}"));
}
/**
* Test parsers.
*/
@Test
public void testParsers() throws IOException {
String json = "{\"foo\":\"a-text\",\n\"bar\":123}";
JSON fromString = JSON.parse(json);
assertThat(fromString.toString(), is(sameJSONAs(json)));
try (InputStream in = new ByteArrayInputStream(json.getBytes("utf-8"))) {
JSON fromStream = JSON.parse(in);
assertThat(fromStream.toString(), is(sameJSONAs(json)));
}
}
/**
* Test that bad JSON fails.
*/
@Test(expected = AcmeProtocolException.class)
public void testParsersBadJSON() throws IOException {
JSON.parse("This is no JSON.");
}
/**
* Test all object related methods.
*/
@Test
public void testObject() {
JSON json = TestUtils.getJsonAsObject("json");
assertThat(json.keySet(), containsInAnyOrder(
"text", "number", "uri", "url", "date", "array", "collect"));
assertThat(json.contains("text"), is(true));
assertThat(json.contains("music"), is(false));
assertThat(json.get("text"), is(notNullValue()));
assertThat(json.get("music"), is(notNullValue()));
}
/**
* Test all array related methods.
*/
@Test
public void testArray() {
JSON json = TestUtils.getJsonAsObject("json");
JSON.Array array = json.get("array").asArray();
assertThat(array.size(), is(4));
assertThat(array.get(0), is(notNullValue()));
assertThat(array.get(1), is(notNullValue()));
assertThat(array.get(2), is(notNullValue()));
assertThat(array.get(3), is(notNullValue()));
}
/**
* Test all array iterator related methods.
*/
@Test
public void testArrayIterator() {
JSON json = TestUtils.getJsonAsObject("json");
JSON.Array array = json.get("array").asArray();
Iterator<JSON.Value> it = array.iterator();
assertThat(it, is(notNullValue()));
assertThat(it.hasNext(), is(true));
assertThat(it.next().asString(), is("foo"));
assertThat(it.hasNext(), is(true));
assertThat(it.next().asInt(), is(987));
assertThat(it.hasNext(), is(true));
assertThat(it.next().asArray().size(), is(3));
assertThat(it.hasNext(), is(true));
try {
it.remove();
fail("was able to remove from array");
} catch (UnsupportedOperationException ex) {
// expected
}
assertThat(it.next().asObject(), is(notNullValue()));
assertThat(it.hasNext(), is(false));
try {
it.next();
fail("next past last element");
} catch (NoSuchElementException ex) {
// expected
}
}
/**
* Test all getters on existing values.
*/
@Test
public void testGetter() throws MalformedURLException {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.clear();
cal.set(2016, 0, 8);
JSON json = TestUtils.getJsonAsObject("json");
assertThat(json.get("text").asString(), is("lorem ipsum"));
assertThat(json.get("number").asInt(), is(123));
assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com")));
assertThat(json.get("url").asURL(), is(new URL("http://example.com")));
assertThat(json.get("date").asDate(), is(cal.getTime()));
JSON.Array array = json.get("array").asArray();
assertThat(array.get(0).asString(), is("foo"));
assertThat(array.get(1).asInt(), is(987));
JSON.Array array2 = array.get(2).asArray();
assertThat(array2.get(0).asInt(), is(1));
assertThat(array2.get(1).asInt(), is(2));
assertThat(array2.get(2).asInt(), is(3));
JSON sub = array.get(3).asObject();
assertThat(sub.get("test").asString(), is("ok"));
}
/**
* Test that getters are null safe.
*/
@Test
public void testNullGetter() throws MalformedURLException {
JSON json = TestUtils.getJsonAsObject("json");
assertThat(json.get("none"), is(notNullValue()));
assertThat(json.get("none").asString(), is(nullValue()));
assertThat(json.get("none").asURI(), is(nullValue()));
assertThat(json.get("none").asURL(), is(nullValue()));
assertThat(json.get("none").asDate(), is(nullValue()));
assertThat(json.get("none").asArray(), is(nullValue()));
assertThat(json.get("none").asObject(), is(nullValue()));
try {
json.get("none").asInt();
fail("asInt did not fail");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("none").required();
fail("required did not fail");
} catch (AcmeProtocolException ex) {
// expected
}
JSON.Value textv = json.get("text");
assertThat(textv.required(), is(textv));
}
/**
* Test that wrong getters return an exception.
*/
@Test
public void testWrongGetter() throws MalformedURLException {
JSON json = TestUtils.getJsonAsObject("json");
try {
json.get("text").asObject();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asArray();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asInt();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asURI();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asURL();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asDate();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
}
/**
* Test that serialization works correctly.
*/
@Test
public void testSerialization() throws IOException, ClassNotFoundException {
JSON originalJson = TestUtils.getJsonAsObject("newAuthorizationResponse");
// Serialize
byte[] data;
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
oos.writeObject(originalJson);
}
data = out.toByteArray();
}
// Deserialize
JSON testJson;
try (ByteArrayInputStream in = new ByteArrayInputStream(data)) {
try (ObjectInputStream ois = new ObjectInputStream(in)) {
testJson = (JSON) ois.readObject();
}
}
assertThat(testJson, not(sameInstance(originalJson)));
assertThat(testJson.toString(), not(isEmptyOrNullString()));
assertThat(testJson.toString(), is(sameJSONAs(originalJson.toString())));
}
}

View File

@ -46,7 +46,6 @@ import org.jose4j.base64url.Base64Url;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
import org.jose4j.lang.JoseException;
import org.shredzone.acme4j.Session;
import org.shredzone.acme4j.provider.AcmeProvider;
@ -109,12 +108,8 @@ public final class TestUtils {
* JSON resource
* @return Parsed JSON resource
*/
public static Map<String, Object> getJsonAsMap(String key) {
try {
return JsonUtil.parseJson(getJson(key));
} catch (JoseException ex) {
throw new RuntimeException("JSON error", ex);
}
public static JSON getJsonAsObject(String key) {
return JSON.parse(getJson(key));
}
/**

View File

@ -34,6 +34,16 @@ directoryNoMeta = \
"new-cert": "https://example.com/acme/new-cert"\
}
json = \
{\
"text": "lorem ipsum",\
"number": 123,\
"uri": "mailto:foo@example.com",\
"url": "http://example.com",\
"date": "2016-01-08T00:00:00Z",\
"array": ["foo", 987, [1, 2, 3], {"test": "ok"}],\
"collect": ["foo", "bar", "barfoo"]\
}
newRegistration = \
{"resource":"new-reg",\