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 ba22be74..5f13bbed 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java
@@ -131,7 +131,6 @@ public class Account extends AcmeResource {
JSONBuilder claims = new JSONBuilder();
conn.sendSignedRequest(getLocation(), claims, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
unmarshal(conn.readJsonResponse());
}
@@ -180,8 +179,7 @@ public class Account extends AcmeResource {
.put("type", "dns")
.put("value", toAce(domain));
- conn.sendSignedRequest(newAuthzUrl, claims, getSession());
- conn.accept(HttpURLConnection.HTTP_CREATED);
+ conn.sendSignedRequest(newAuthzUrl, claims, getSession(), HttpURLConnection.HTTP_CREATED);
JSON json = conn.readJsonResponse();
@@ -231,7 +229,6 @@ public class Account extends AcmeResource {
outerClaim.put("payload", innerJws.getEncodedPayload());
conn.sendSignedRequest(keyChangeUrl, outerClaim, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
getSession().setKeyPair(newKeyPair);
} catch (JoseException ex) {
@@ -252,7 +249,6 @@ public class Account extends AcmeResource {
claims.put(KEY_STATUS, "deactivated");
conn.sendSignedRequest(getLocation(), claims, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
unmarshal(conn.readJsonResponse());
}
@@ -366,7 +362,6 @@ public class Account extends AcmeResource {
}
conn.sendSignedRequest(getLocation(), claims, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
JSON json = conn.readJsonResponse();
unmarshal(json);
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java
index 29a87306..0a81a02b 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java
@@ -177,8 +177,7 @@ public class AccountBuilder {
claims.put("only-return-existing", onlyExisting);
}
- conn.sendSignedRequest(resourceUrl, claims, session, true);
- int resp = conn.accept(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_CREATED);
+ int resp = conn.sendSignedRequest(resourceUrl, claims, session, true, HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_CREATED);
URL location = conn.getLocation();
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 dc850db5..baefec3d 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java
@@ -16,7 +16,6 @@ package org.shredzone.acme4j;
import static java.util.stream.Collectors.toList;
import static org.shredzone.acme4j.toolbox.AcmeUtils.parseTimestamp;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Instant;
import java.util.Collections;
@@ -131,7 +130,6 @@ public class Authorization extends AcmeResource {
LOG.debug("update");
try (Connection conn = getSession().provider().connect()) {
conn.sendRequest(getLocation(), getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
unmarshalAuthorization(conn.readJsonResponse());
@@ -149,7 +147,6 @@ public class Authorization extends AcmeResource {
claims.put("status", "deactivated");
conn.sendSignedRequest(getLocation(), claims, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
unmarshalAuthorization(conn.readJsonResponse());
}
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java
index 72288268..dab4b7e1 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java
@@ -17,7 +17,6 @@ import static java.util.Collections.unmodifiableList;
import java.io.IOException;
import java.io.Writer;
-import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.security.KeyPair;
@@ -82,7 +81,6 @@ public class Certificate extends AcmeResource {
LOG.debug("download");
try (Connection conn = getSession().provider().connect()) {
conn.sendRequest(getLocation(), getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
alternates = new ArrayList<>(conn.getLinks("alternate"));
certChain = new ArrayList<>(conn.readCertificates());
}
@@ -172,7 +170,6 @@ public class Certificate extends AcmeResource {
}
conn.sendSignedRequest(resUrl, claims, getSession(), true);
- conn.accept(HttpURLConnection.HTTP_OK);
} catch (CertificateEncodingException ex) {
throw new AcmeProtocolException("Invalid certificate", ex);
}
@@ -211,7 +208,6 @@ public class Certificate extends AcmeResource {
}
conn.sendSignedRequest(resUrl, claims, session, true);
- conn.accept(HttpURLConnection.HTTP_OK);
} catch (CertificateEncodingException ex) {
throw new AcmeProtocolException("Invalid certificate", ex);
}
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java
index 4170ab4a..18137e4f 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java
@@ -15,7 +15,6 @@ package org.shredzone.acme4j;
import static java.util.stream.Collectors.toList;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Instant;
import java.util.List;
@@ -153,7 +152,6 @@ public class Order extends AcmeResource {
claims.putBase64("csr", csr);
conn.sendSignedRequest(getFinalizeLocation(), claims, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
}
loaded = false; // invalidate this object
}
@@ -173,7 +171,6 @@ public class Order extends AcmeResource {
LOG.debug("update");
try (Connection conn = getSession().provider().connect()) {
conn.sendRequest(getLocation(), getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
JSON json = conn.readJsonResponse();
unmarshal(json);
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java
index 2a2eb6dd..1ff98d42 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java
@@ -148,8 +148,7 @@ public class OrderBuilder {
claims.put("notAfter", notAfter);
}
- conn.sendSignedRequest(session.resourceUrl(Resource.NEW_ORDER), claims, session);
- conn.accept(HttpURLConnection.HTTP_CREATED);
+ conn.sendSignedRequest(session.resourceUrl(Resource.NEW_ORDER), claims, session, HttpURLConnection.HTTP_CREATED);
JSON json = conn.readJsonResponse();
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 5c235ed1..a77434f6 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
@@ -15,7 +15,6 @@ package org.shredzone.acme4j.challenge;
import static java.util.stream.Collectors.toList;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Instant;
import java.util.Collections;
@@ -84,7 +83,6 @@ public class Challenge extends AcmeResource {
LOG.debug("bind");
try (Connection conn = session.provider().connect()) {
conn.sendRequest(location, session);
- conn.accept(HttpURLConnection.HTTP_OK);
JSON json = conn.readJsonResponse();
if (!(json.contains(KEY_TYPE))) {
@@ -218,7 +216,6 @@ public class Challenge extends AcmeResource {
respond(claims);
conn.sendSignedRequest(getLocation(), claims, getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
unmarshall(conn.readJsonResponse());
}
@@ -238,7 +235,6 @@ public class Challenge extends AcmeResource {
LOG.debug("update");
try (Connection conn = getSession().provider().connect()) {
conn.sendRequest(getLocation(), getSession());
- conn.accept(HttpURLConnection.HTTP_OK);
unmarshall(conn.readJsonResponse());
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java
index 5876a044..1c9b718b 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java
@@ -13,6 +13,7 @@
*/
package org.shredzone.acme4j.connector;
+import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.Collection;
@@ -39,6 +40,9 @@ public interface Connection extends AutoCloseable {
/**
* Sends a simple GET request.
+ *
+ * If the response code was not {@link HttpURLConnection#HTTP_OK}, an
+ * {@link AcmeException} matching the error is raised.
*
* @param url
* {@link URL} to send the request to.
@@ -57,12 +61,19 @@ public interface Connection extends AutoCloseable {
* {@link JSONBuilder} containing claims. Must not be {@code null}.
* @param session
* {@link Session} instance to be used for signing and tracking
+ * @param httpStatus
+ * Acceptable HTTP states. 200 OK if empty.
+ * @return HTTP 200 class status that was returned
*/
- void sendSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException;
+ int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus)
+ throws AcmeException;
/**
* Sends a signed POST request. If the session's KeyIdentifier is set, a "kid"
* protected header field is sent. If not, a "jwk" protected header field is sent.
+ *
+ * If the server does not return a 200 class status code, an {@link AcmeException} is
+ * raised matching the error.
*
* @param url
* {@link URL} to send the request to.
@@ -74,19 +85,12 @@ public interface Connection extends AutoCloseable {
* {@code true} to enforce a "jwk" header field even if a KeyIdentifier is
* set, {@code false} to choose between "kid" and "jwk" header field
* automatically
- */
- void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk)
- throws AcmeException;
-
- /**
- * Checks if the HTTP response status is in the given list of acceptable HTTP states,
- * otherwise raises an {@link AcmeException} matching the error.
- *
* @param httpStatus
- * Acceptable HTTP states
- * @return Actual HTTP status that was accepted
+ * Acceptable HTTP states. 200 OK if empty.
+ * @return HTTP 200 class status that was returned
*/
- int accept(int... httpStatus) throws AcmeException;
+ int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus)
+ throws AcmeException;
/**
* Reads a server response as JSON data.
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java
index 5978a61c..f129e1d7 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java
@@ -35,7 +35,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.OptionalInt;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -78,6 +77,9 @@ public class DefaultConnection implements Connection {
private static final Pattern BASE64URL_PATTERN = Pattern.compile("[0-9A-Za-z_-]+");
+ private static final URI BAD_NONCE_ERROR = URI.create("urn:ietf:params:acme:error:badNonce");
+ private static final int MAX_ATTEMPTS = 10;
+
protected final HttpConnector httpConnector;
protected HttpURLConnection conn;
@@ -107,8 +109,7 @@ public class DefaultConnection implements Connection {
int rc = conn.getResponseCode();
if (rc != HttpURLConnection.HTTP_OK && rc != HttpURLConnection.HTTP_NO_CONTENT) {
- throw new AcmeProtocolException("Fetching a nonce returned " + rc + " "
- + conn.getResponseMessage());
+ throwAcmeException();
}
updateSession(session);
@@ -141,108 +142,49 @@ public class DefaultConnection implements Connection {
conn.connect();
logHeaders();
+
+ int rc = conn.getResponseCode();
+ if (rc != HttpURLConnection.HTTP_OK) {
+ throwAcmeException();
+ }
+
} catch (IOException ex) {
throw new AcmeNetworkException(ex);
}
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) throws AcmeException {
if (session.getKeyIdentifier() == null) {
throw new IllegalStateException("session has no KeyIdentifier set");
}
- sendSignedRequest(url, claims, session, false);
+ return sendSignedRequest(url, claims, session, false, httpStatus);
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk)
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus)
throws AcmeException {
Objects.requireNonNull(url, "url");
Objects.requireNonNull(claims, "claims");
Objects.requireNonNull(session, "session");
assertConnectionIsClosed();
- try {
- KeyPair keypair = session.getKeyPair();
+ AcmeException lastException = null;
- if (session.getNonce() == null) {
- resetNonce(session);
+ for (int attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
+ try {
+ return performRequest(url, claims, session, enforceJwk, httpStatus);
+ } catch (AcmeServerException ex) {
+ if (!BAD_NONCE_ERROR.equals(ex.getType())) {
+ throw ex;
+ }
+ lastException = ex;
+ LOG.info("Bad Replay Nonce, trying again (attempt {}/{})", attempt, MAX_ATTEMPTS);
}
-
- conn = httpConnector.openConnection(url);
- conn.setRequestMethod("POST");
- conn.setRequestProperty(ACCEPT_HEADER, "application/json");
- conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET);
- conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag());
- conn.setRequestProperty(CONTENT_TYPE_HEADER, "application/jose+json");
- conn.setDoOutput(true);
-
- final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic());
- JsonWebSignature jws = new JsonWebSignature();
- jws.setPayload(claims.toString());
- jws.getHeaders().setObjectHeaderValue("nonce", Base64Url.encode(session.getNonce()));
- jws.getHeaders().setObjectHeaderValue("url", url);
- if (enforceJwk || session.getKeyIdentifier() == null) {
- jws.getHeaders().setJwkHeaderValue("jwk", jwk);
- } else {
- jws.getHeaders().setObjectHeaderValue("kid", session.getKeyIdentifier());
- }
-
- jws.setAlgorithmHeaderValue(keyAlgorithm(jwk));
- jws.setKey(keypair.getPrivate());
- jws.sign();
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("POST {}", url);
- LOG.debug(" Payload: {}", claims.toString());
- LOG.debug(" JWS Header: {}", jws.getHeaders().getFullHeaderAsJsonString());
- }
-
- JSONBuilder jb = new JSONBuilder();
- jb.put("protected", jws.getHeaders().getEncodedHeader());
- jb.put("payload", jws.getEncodedPayload());
- jb.put("signature", jws.getEncodedSignature());
- byte[] outputData = jb.toString().getBytes(DEFAULT_CHARSET);
-
- conn.setFixedLengthStreamingMode(outputData.length);
- conn.connect();
-
- try (OutputStream out = conn.getOutputStream()) {
- out.write(outputData);
- }
-
- logHeaders();
-
- updateSession(session);
- } catch (IOException ex) {
- throw new AcmeNetworkException(ex);
- } catch (JoseException ex) {
- throw new AcmeProtocolException("Failed to generate a JSON request", ex);
}
- }
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertConnectionIsOpen();
-
- try {
- int rc = conn.getResponseCode();
- OptionalInt match = Arrays.stream(httpStatus).filter(s -> s == rc).findFirst();
- if (match.isPresent()) {
- return match.getAsInt();
- }
-
- String contentType = AcmeUtils.getContentType(conn.getHeaderField(CONTENT_TYPE_HEADER));
- if (!"application/problem+json".equals(contentType)) {
- throw new AcmeException("HTTP " + rc + ": " + conn.getResponseMessage());
- }
-
- Problem problem = new Problem(readJsonResponse(), conn.getURL());
- throw createAcmeException(problem);
- } catch (IOException ex) {
- throw new AcmeNetworkException(ex);
- }
+ throw new AcmeException("Too many reattempts", lastException);
}
@Override
@@ -345,6 +287,91 @@ public class DefaultConnection implements Connection {
conn = null;
}
+ /**
+ * Performs the POST request.
+ *
+ * @param url
+ * {@link URL} to send the request to.
+ * @param claims
+ * {@link JSONBuilder} containing claims. Must not be {@code null}.
+ * @param session
+ * {@link Session} instance to be used for signing and tracking
+ * @param enforceJwk
+ * {@code true} to enforce a "jwk" header field even if a KeyIdentifier is
+ * set, {@code false} to choose between "kid" and "jwk" header field
+ * automatically
+ * @param httpStatus
+ * Acceptable HTTP states. 200 OK if empty.
+ * @return HTTP 200 class status that was returned
+ */
+ private int performRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus)
+ throws AcmeException {
+ try {
+ KeyPair keypair = session.getKeyPair();
+
+ if (session.getNonce() == null) {
+ resetNonce(session);
+ }
+
+ conn = httpConnector.openConnection(url);
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty(ACCEPT_HEADER, "application/json");
+ conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET);
+ conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag());
+ conn.setRequestProperty(CONTENT_TYPE_HEADER, "application/jose+json");
+ conn.setDoOutput(true);
+
+ final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic());
+ JsonWebSignature jws = new JsonWebSignature();
+ jws.setPayload(claims.toString());
+ jws.getHeaders().setObjectHeaderValue("nonce", Base64Url.encode(session.getNonce()));
+ jws.getHeaders().setObjectHeaderValue("url", url);
+ if (enforceJwk || session.getKeyIdentifier() == null) {
+ jws.getHeaders().setJwkHeaderValue("jwk", jwk);
+ } else {
+ jws.getHeaders().setObjectHeaderValue("kid", session.getKeyIdentifier());
+ }
+
+ jws.setAlgorithmHeaderValue(keyAlgorithm(jwk));
+ jws.setKey(keypair.getPrivate());
+ jws.sign();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("POST {}", url);
+ LOG.debug(" Payload: {}", claims.toString());
+ LOG.debug(" JWS Header: {}", jws.getHeaders().getFullHeaderAsJsonString());
+ }
+
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("protected", jws.getHeaders().getEncodedHeader());
+ jb.put("payload", jws.getEncodedPayload());
+ jb.put("signature", jws.getEncodedSignature());
+ byte[] outputData = jb.toString().getBytes(DEFAULT_CHARSET);
+
+ conn.setFixedLengthStreamingMode(outputData.length);
+ conn.connect();
+
+ try (OutputStream out = conn.getOutputStream()) {
+ out.write(outputData);
+ }
+
+ logHeaders();
+
+ updateSession(session);
+
+ int rc = conn.getResponseCode();
+ if ((httpStatus.length == 0 && rc != HttpURLConnection.HTTP_OK)
+ || (httpStatus.length > 0 && !Arrays.stream(httpStatus).filter(s -> s == rc).findFirst().isPresent())) {
+ throwAcmeException();
+ }
+ return rc;
+ } catch (IOException ex) {
+ throw new AcmeNetworkException(ex);
+ } catch (JoseException ex) {
+ throw new AcmeProtocolException("Failed to generate a JSON request", ex);
+ }
+ }
+
/**
* Gets the instant sent with the Retry-After header.
*/
@@ -374,42 +401,52 @@ public class DefaultConnection implements Connection {
}
/**
- * Handles a problem by throwing an exception. If a JSON problem was returned, an
- * {@link AcmeServerException} or subtype will be thrown. Otherwise a generic
- * {@link AcmeException} is thrown.
+ * Throws an {@link AcmeException}. This method throws an exception that tries to
+ * explain the error as precisely as possible.
*/
- private AcmeException createAcmeException(Problem problem) {
- if (problem.getType() == null) {
- return new AcmeException(problem.getDetail());
+ private void throwAcmeException() throws AcmeException {
+ try {
+ String contentType = AcmeUtils.getContentType(conn.getHeaderField(CONTENT_TYPE_HEADER));
+ if (!"application/problem+json".equals(contentType)) {
+ throw new AcmeException("HTTP " + conn.getResponseCode() + ": " + conn.getResponseMessage());
+ }
+
+ Problem problem = new Problem(readJsonResponse(), conn.getURL());
+
+ if (problem.getType() == null) {
+ throw new AcmeException(problem.getDetail());
+ }
+
+ String error = AcmeUtils.stripErrorPrefix(problem.getType().toString());
+
+ if ("unauthorized".equals(error)) {
+ throw new AcmeUnauthorizedException(problem);
+ }
+
+ if ("userActionRequired".equals(error)) {
+ URI tos = collectLinks("terms-of-service").stream()
+ .findFirst()
+ .map(it -> {
+ try {
+ return conn.getURL().toURI().resolve(it);
+ } catch (URISyntaxException ex) {
+ throw new AcmeProtocolException("Invalid TOS URI", ex);
+ }
+ })
+ .orElse(null);
+ throw new AcmeUserActionRequiredException(problem, tos);
+ }
+
+ if ("rateLimited".equals(error)) {
+ Optional retryAfter = getRetryAfterHeader();
+ Collection rateLimits = getLinks("urn:ietf:params:acme:documentation");
+ throw new AcmeRateLimitedException(problem, retryAfter.orElse(null), rateLimits);
+ }
+
+ throw new AcmeServerException(problem);
+ } catch (IOException ex) {
+ throw new AcmeNetworkException(ex);
}
-
- String error = AcmeUtils.stripErrorPrefix(problem.getType().toString());
-
- if ("unauthorized".equals(error)) {
- return new AcmeUnauthorizedException(problem);
- }
-
- if ("userActionRequired".equals(error)) {
- URI tos = collectLinks("terms-of-service").stream()
- .findFirst()
- .map(it -> {
- try {
- return conn.getURL().toURI().resolve(it);
- } catch (URISyntaxException ex) {
- throw new AcmeProtocolException("Invalid TOS URI", ex);
- }
- })
- .orElse(null);
- return new AcmeUserActionRequiredException(problem, tos);
- }
-
- if ("rateLimited".equals(error)) {
- Optional retryAfter = getRetryAfterHeader();
- Collection rateLimits = getLinks("urn:ietf:params:acme:documentation");
- return new AcmeRateLimitedException(problem, retryAfter.orElse(null), rateLimits);
- }
-
- return new AcmeServerException(problem);
}
/**
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java
index 2be55688..3b5b1ef9 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java
@@ -13,7 +13,6 @@
*/
package org.shredzone.acme4j.connector;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.Deque;
@@ -141,7 +140,6 @@ public class ResourceIterator implements Iterator {
private void readAndQueue() throws AcmeException {
try (Connection conn = session.provider().connect()) {
conn.sendRequest(nextUrl, session);
- conn.accept(HttpURLConnection.HTTP_OK);
JSON json = conn.readJsonResponse();
fillUrlList(json);
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java
index 38e678f2..66bdd3c6 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java
@@ -13,7 +13,6 @@
*/
package org.shredzone.acme4j.provider;
-import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
@@ -52,7 +51,6 @@ public abstract class AbstractAcmeProvider implements AcmeProvider {
public JSON directory(Session session, URI serverUri) throws AcmeException {
try (Connection conn = connect()) {
conn.sendRequest(resolve(serverUri), session);
- conn.accept(HttpURLConnection.HTTP_OK);
// use nonce header if there is one, saves a HEAD request...
conn.updateSession(session);
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountBuilderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountBuilderTest.java
index d14a9d44..ed1fde52 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountBuilderTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountBuilderTest.java
@@ -28,7 +28,6 @@ import org.jose4j.jwx.CompactSerializer;
import org.jose4j.lang.JoseException;
import org.junit.Test;
import org.shredzone.acme4j.connector.Resource;
-import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.toolbox.AcmeUtils;
import org.shredzone.acme4j.toolbox.JSON;
@@ -52,31 +51,24 @@ public class AccountBuilderTest {
private boolean isUpdate;
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(session, is(notNullValue()));
assertThat(url, is(locationUrl));
assertThat(isUpdate, is(false));
isUpdate = true;
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
+ return HttpURLConnection.HTTP_OK;
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus) {
assertThat(session, is(notNullValue()));
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("newAccount").toString()));
assertThat(enforceJwk, is(true));
isUpdate = false;
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- if (isUpdate) {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- } else {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_CREATED));
- return HttpURLConnection.HTTP_CREATED;
- }
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_CREATED));
+ return HttpURLConnection.HTTP_CREATED;
}
@Override
@@ -125,7 +117,7 @@ public class AccountBuilderTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus) {
try {
assertThat(session, is(notNullValue()));
assertThat(url, is(resourceUrl));
@@ -162,10 +154,7 @@ public class AccountBuilderTest {
ex.printStackTrace();
fail("decoding inner payload failed");
}
- }
- @Override
- public int accept(int... httpStatus) throws AcmeException {
assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_CREATED));
return HttpURLConnection.HTTP_CREATED;
}
@@ -202,15 +191,11 @@ public class AccountBuilderTest {
public void testOnlyExistingRegistration() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus) {
assertThat(session, is(notNullValue()));
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("newAccountOnlyExisting").toString()));
assertThat(enforceJwk, is(true));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_CREATED));
return HttpURLConnection.HTTP_OK;
}
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java
index c5043146..31f63a48 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java
@@ -63,15 +63,14 @@ public class AccountTest {
public void testUpdateAccount() throws AcmeException, IOException, URISyntaxException {
TestableConnectionProvider provider = new TestableConnectionProvider() {
private JSON jsonResponse;
- private Integer response;
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(url, is(locationUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("updateAccount").toString()));
assertThat(session, is(notNullValue()));
jsonResponse = getJSON("updateAccountResponse");
- response = HttpURLConnection.HTTP_OK;
+ return HttpURLConnection.HTTP_OK;
}
@Override
@@ -80,17 +79,7 @@ public class AccountTest {
jsonResponse = new JSONBuilder()
.array("orders", "https://example.com/acme/order/1")
.toJSON();
- response = HttpURLConnection.HTTP_OK;
- return;
}
-
- response = HttpURLConnection.HTTP_NOT_FOUND;
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(response, not(nullValue()));
- return response;
}
@Override
@@ -137,14 +126,10 @@ public class AccountTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
requestWasSent.set(true);
assertThat(url, is(locationUrl));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
@@ -190,14 +175,10 @@ public class AccountTest {
public void testPreAuthorizeDomain() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("newAuthorizationRequest").toString()));
assertThat(session, is(notNullValue()));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_CREATED));
return HttpURLConnection.HTTP_CREATED;
}
@@ -248,14 +229,11 @@ public class AccountTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) throws AcmeException {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("newAuthorizationRequest").toString()));
assertThat(session, is(notNullValue()));
- }
- @Override
- public int accept(int... httpStatus) throws AcmeException {
Problem problem = TestUtils.createProblem(problemType, problemDetail, resourceUrl);
throw new AcmeServerException(problem);
}
@@ -325,7 +303,7 @@ public class AccountTest {
final TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder payload, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder payload, Session session, int... httpStatus) {
try {
assertThat(url, is(locationUrl));
assertThat(session, is(notNullValue()));
@@ -356,11 +334,8 @@ public class AccountTest {
} catch (JoseException ex) {
fail("decoding inner payload failed");
}
- }
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
@@ -408,16 +383,12 @@ public class AccountTest {
public void testDeactivate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
JSON json = claims.toJSON();
assertThat(json.get("status").asString(), is("deactivated"));
assertThat(url, is(locationUrl));
assertThat(session, is(notNullValue()));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
@@ -442,15 +413,11 @@ public class AccountTest {
public void testModify() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(url, is(locationUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("modifyAccount").toString()));
assertThat(session, is(notNullValue()));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java
index 0c4d844b..4d55c615 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java
@@ -95,12 +95,6 @@ public class AuthorizationTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateAuthorizationResponse");
@@ -147,12 +141,6 @@ public class AuthorizationTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateAuthorizationResponse");
@@ -199,12 +187,6 @@ public class AuthorizationTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateAuthorizationResponse");
@@ -250,16 +232,12 @@ public class AuthorizationTest {
public void testDeactivate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
JSON json = claims.toJSON();
assertThat(json.get("status").asString(), is("deactivated"));
assertThat(url, is(locationUrl));
assertThat(session, is(notNullValue()));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java
index eaed7cef..b13e552f 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java
@@ -61,12 +61,6 @@ public class CertificateTest {
assertThat(session, is(notNullValue()));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public List readCertificates() throws AcmeException {
return originalCert;
@@ -138,18 +132,14 @@ public class CertificateTest {
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("revokeCertificateRequest").toString()));
assertThat(session, is(notNullValue()));
assertThat(session.getKeyIdentifier(), is(nullValue()));
assertThat(enforceJwk, is(true));
certRequested = false;
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
@@ -192,17 +182,13 @@ public class CertificateTest {
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("revokeCertificateWithReasonRequest").toString()));
assertThat(session, is(notNullValue()));
assertThat(enforceJwk, is(true));
certRequested = false;
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
@@ -246,18 +232,14 @@ public class CertificateTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk)
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus)
throws AcmeException {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("revokeCertificateWithReasonRequest").toString()));
assertThat(session, is(notNullValue()));
assertThat(session.getKeyPair(), is(certKeyPair));
assertThat(enforceJwk, is(true));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
};
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java
index 7d9941e7..3503e1cb 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java
@@ -26,7 +26,6 @@ import java.util.Arrays;
import org.junit.Test;
import org.shredzone.acme4j.connector.Resource;
-import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSONBuilder;
@@ -49,14 +48,10 @@ public class OrderBuilderTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("requestOrderRequest").toString()));
assertThat(session, is(notNullValue()));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_CREATED));
return HttpURLConnection.HTTP_CREATED;
}
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java
index e3364f86..96d29559 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java
@@ -26,7 +26,6 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
-import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSONBuilder;
@@ -51,12 +50,6 @@ public class OrderTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateOrderResponse");
@@ -106,12 +99,6 @@ public class OrderTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateOrderResponse");
@@ -153,16 +140,12 @@ public class OrderTest {
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(url, is(finalizeUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("finalizeRequest").toString()));
assertThat(session, is(notNullValue()));
isFinalized = true;
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java
index 07f1ecfb..86a2307b 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java
@@ -66,12 +66,6 @@ public class ChallengeTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateHttpChallengeResponse");
@@ -165,15 +159,11 @@ public class ChallengeTest {
public void testTrigger() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("triggerHttpChallengeRequest").toString()));
assertThat(session, is(notNullValue()));
- }
-
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
+ assertThat(httpStatus, isIntArrayContainingInAnyOrder());
return HttpURLConnection.HTTP_OK;
}
@@ -207,12 +197,6 @@ public class ChallengeTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateHttpChallengeResponse");
@@ -250,12 +234,6 @@ public class ChallengeTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateHttpChallengeResponse");
@@ -317,12 +295,6 @@ public class ChallengeTest {
assertThat(url, is(locationUrl));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
return getJSON("updateAccountResponse");
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java
index 70a454e9..3faebe75 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java
@@ -111,16 +111,14 @@ public class DefaultConnectionTest {
*/
@Test
public void testGetNonceFromHeader() {
- byte[] nonce = "foo-nonce-foo".getBytes();
-
when(mockUrlConnection.getHeaderField("Replay-Nonce"))
- .thenReturn(Base64Url.encode(nonce));
+ .thenReturn(Base64Url.encode(TestUtils.DUMMY_NONCE));
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
conn.updateSession(session);
}
- assertThat(session.getNonce(), is(nonce));
+ assertThat(session.getNonce(), is(TestUtils.DUMMY_NONCE));
verify(mockUrlConnection).getHeaderField("Replay-Nonce");
verifyNoMoreInteractions(mockUrlConnection);
@@ -154,8 +152,6 @@ public class DefaultConnectionTest {
*/
@Test
public void testResetNonce() throws AcmeException, IOException {
- byte[] nonce = "foo-nonce-foo".getBytes();
-
when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce")))
.thenReturn(mockUrlConnection);
when(mockUrlConnection.getResponseCode())
@@ -173,13 +169,13 @@ public class DefaultConnectionTest {
assertThat(session.getNonce(), is(nullValue()));
when(mockUrlConnection.getHeaderField("Replay-Nonce"))
- .thenReturn(Base64Url.encode(nonce));
+ .thenReturn(Base64Url.encode(TestUtils.DUMMY_NONCE));
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.resetNonce(session);
}
- assertThat(session.getNonce(), is(nonce));
+ assertThat(session.getNonce(), is(TestUtils.DUMMY_NONCE));
verify(mockUrlConnection, atLeastOnce()).setRequestMethod("HEAD");
verify(mockUrlConnection, atLeastOnce()).setRequestProperty("Accept-Language", "ja-JP");
@@ -404,15 +400,17 @@ public class DefaultConnectionTest {
@Test
public void testAccept() throws Exception {
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+ when(mockUrlConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
+
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
- conn.conn = mockUrlConnection;
- int rc = conn.accept(HttpURLConnection.HTTP_OK);
+ int rc = conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
assertThat(rc, is(HttpURLConnection.HTTP_OK));
}
verify(mockUrlConnection).getResponseCode();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -424,12 +422,15 @@ public class DefaultConnectionTest {
when(mockUrlConnection.getHeaderField("Content-Type")).thenReturn("application/problem+json");
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_FORBIDDEN);
+ when(mockUrlConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
when(mockUrlConnection.getErrorStream()).thenReturn(new ByteArrayInputStream(jsonData.getBytes("utf-8")));
when(mockUrlConnection.getURL()).thenReturn(url("https://example.com/acme/1"));
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
+
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
- conn.conn = mockUrlConnection;
- conn.accept(HttpURLConnection.HTTP_OK);
+ conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
fail("Expected to fail");
} catch (AcmeUnauthorizedException ex) {
assertThat(ex.getType(), is(URI.create("urn:ietf:params:acme:error:unauthorized")));
@@ -442,7 +443,6 @@ public class DefaultConnectionTest {
verify(mockUrlConnection, atLeastOnce()).getResponseCode();
verify(mockUrlConnection).getErrorStream();
verify(mockUrlConnection).getURL();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -458,12 +458,15 @@ public class DefaultConnectionTest {
when(mockUrlConnection.getHeaderField("Content-Type")).thenReturn("application/problem+json");
when(mockUrlConnection.getHeaderFields()).thenReturn(linkHeader);
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_FORBIDDEN);
+ when(mockUrlConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
when(mockUrlConnection.getErrorStream()).thenReturn(new ByteArrayInputStream(jsonData.getBytes("utf-8")));
when(mockUrlConnection.getURL()).thenReturn(url("https://example.com/acme/1"));
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
+
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
- conn.conn = mockUrlConnection;
- conn.accept(HttpURLConnection.HTTP_OK);
+ conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
fail("Expected to fail");
} catch (AcmeUserActionRequiredException ex) {
assertThat(ex.getType(), is(URI.create("urn:ietf:params:acme:error:userActionRequired")));
@@ -478,7 +481,6 @@ public class DefaultConnectionTest {
verify(mockUrlConnection, atLeastOnce()).getResponseCode();
verify(mockUrlConnection).getErrorStream();
verify(mockUrlConnection, atLeastOnce()).getURL();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -498,12 +500,15 @@ public class DefaultConnectionTest {
when(mockUrlConnection.getHeaderFieldDate("Retry-After", 0L)).thenReturn(retryAfter.toEpochMilli());
when(mockUrlConnection.getHeaderFields()).thenReturn(linkHeader);
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_FORBIDDEN);
+ when(mockUrlConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
when(mockUrlConnection.getErrorStream()).thenReturn(new ByteArrayInputStream(jsonData.getBytes("utf-8")));
when(mockUrlConnection.getURL()).thenReturn(url("https://example.com/acme/1"));
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
+
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
- conn.conn = mockUrlConnection;
- conn.accept(HttpURLConnection.HTTP_OK);
+ conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
fail("Expected to fail");
} catch (AcmeRateLimitedException ex) {
assertThat(ex.getType(), is(URI.create("urn:ietf:params:acme:error:rateLimited")));
@@ -523,7 +528,6 @@ public class DefaultConnectionTest {
verify(mockUrlConnection, atLeastOnce()).getResponseCode();
verify(mockUrlConnection).getErrorStream();
verify(mockUrlConnection, atLeastOnce()).getURL();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -537,6 +541,11 @@ public class DefaultConnectionTest {
.thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR);
when(mockUrlConnection.getURL())
.thenReturn(url("https://example.com/acme/1"));
+ when(mockUrlConnection.getOutputStream())
+ .thenReturn(new ByteArrayOutputStream());
+
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
@Override
@@ -547,8 +556,7 @@ public class DefaultConnectionTest {
return result.toJSON();
};
}) {
- conn.conn = mockUrlConnection;
- conn.accept(HttpURLConnection.HTTP_OK);
+ conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
fail("Expected to fail");
} catch (AcmeServerException ex) {
assertThat(ex.getType(), is(URI.create("urn:zombie:error:apocalypse")));
@@ -560,7 +568,6 @@ public class DefaultConnectionTest {
verify(mockUrlConnection).getHeaderField("Content-Type");
verify(mockUrlConnection, atLeastOnce()).getResponseCode();
verify(mockUrlConnection).getURL();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -574,6 +581,11 @@ public class DefaultConnectionTest {
.thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR);
when(mockUrlConnection.getURL())
.thenReturn(url("https://example.com/acme/1"));
+ when(mockUrlConnection.getOutputStream())
+ .thenReturn(new ByteArrayOutputStream());
+
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
@Override
@@ -581,8 +593,7 @@ public class DefaultConnectionTest {
return JSON.empty();
};
}) {
- conn.conn = mockUrlConnection;
- conn.accept(HttpURLConnection.HTTP_OK);
+ conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
fail("Expected to fail");
} catch (AcmeNetworkException ex) {
fail("Did not expect an AcmeNetworkException");
@@ -593,7 +604,6 @@ public class DefaultConnectionTest {
verify(mockUrlConnection).getHeaderField("Content-Type");
verify(mockUrlConnection, atLeastOnce()).getResponseCode();
verify(mockUrlConnection).getURL();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -607,10 +617,14 @@ public class DefaultConnectionTest {
.thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR);
when(mockUrlConnection.getResponseMessage())
.thenReturn("Infernal Server Error");
+ when(mockUrlConnection.getOutputStream())
+ .thenReturn(new ByteArrayOutputStream());
+
+ session.setKeyIdentifier(keyIdentifier);
+ session.setNonce(TestUtils.DUMMY_NONCE);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
- conn.conn = mockUrlConnection;
- conn.accept(HttpURLConnection.HTTP_OK);
+ conn.sendSignedRequest(requestUrl, new JSONBuilder(), session);
fail("Expected to fail");
} catch (AcmeException ex) {
assertThat(ex.getMessage(), is("HTTP 500: Infernal Server Error"));
@@ -619,7 +633,6 @@ public class DefaultConnectionTest {
verify(mockUrlConnection).getHeaderField("Content-Type");
verify(mockUrlConnection, atLeastOnce()).getResponseCode();
verify(mockUrlConnection, atLeastOnce()).getResponseMessage();
- verifyNoMoreInteractions(mockUrlConnection);
}
/**
@@ -627,6 +640,8 @@ public class DefaultConnectionTest {
*/
@Test
public void testSendRequest() throws Exception {
+ when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.sendRequest(requestUrl, session);
}
@@ -636,6 +651,7 @@ public class DefaultConnectionTest {
verify(mockUrlConnection).setRequestProperty("Accept-Language", "ja-JP");
verify(mockUrlConnection).setDoOutput(false);
verify(mockUrlConnection).connect();
+ verify(mockUrlConnection).getResponseCode();
verify(mockUrlConnection, atLeast(0)).getHeaderFields();
verifyNoMoreInteractions(mockUrlConnection);
}
@@ -649,6 +665,7 @@ public class DefaultConnectionTest {
final byte[] nonce2 = "foo-nonce-2-foo".getBytes();
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
when(mockUrlConnection.getOutputStream()).thenReturn(outputStream);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
@@ -686,6 +703,7 @@ public class DefaultConnectionTest {
verify(mockUrlConnection).connect();
verify(mockUrlConnection).setDoOutput(true);
verify(mockUrlConnection).setFixedLengthStreamingMode(outputStream.toByteArray().length);
+ verify(mockUrlConnection).getResponseCode();
verify(mockUrlConnection).getOutputStream();
verify(mockUrlConnection, atLeast(0)).getHeaderFields();
verifyNoMoreInteractions(mockUrlConnection);
@@ -722,6 +740,7 @@ public class DefaultConnectionTest {
final byte[] nonce2 = "foo-nonce-2-foo".getBytes();
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
when(mockUrlConnection.getOutputStream()).thenReturn(outputStream);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
@@ -758,6 +777,7 @@ public class DefaultConnectionTest {
verify(mockUrlConnection).connect();
verify(mockUrlConnection).setDoOutput(true);
verify(mockUrlConnection).setFixedLengthStreamingMode(outputStream.toByteArray().length);
+ verify(mockUrlConnection).getResponseCode();
verify(mockUrlConnection).getOutputStream();
verify(mockUrlConnection, atLeast(0)).getHeaderFields();
verifyNoMoreInteractions(mockUrlConnection);
@@ -802,7 +822,7 @@ public class DefaultConnectionTest {
/**
* Test signed POST requests if there is no nonce.
*/
- @Test(expected = AcmeProtocolException.class)
+ @Test(expected = AcmeException.class)
public void testSendSignedRequestNoNonce() throws Exception {
when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce")))
.thenReturn(mockUrlConnection);
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java
index 4bef9178..d9ec1fa0 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java
@@ -40,18 +40,14 @@ public class DummyConnection implements Connection {
}
@Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk)
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus)
throws AcmeException {
throw new UnsupportedOperationException();
}
@Override
- public int accept(int... httpStatus) throws AcmeException {
+ public int sendSignedRequest(URL url, JSONBuilder claims, Session session, boolean enforceJwk, int... httpStatus)
+ throws AcmeException {
throw new UnsupportedOperationException();
}
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java
index 259034c2..2dbe45b8 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java
@@ -15,10 +15,9 @@ package org.shredzone.acme4j.connector;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
-import static org.shredzone.acme4j.toolbox.TestUtils.*;
+import static org.shredzone.acme4j.toolbox.TestUtils.url;
import java.io.IOException;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -32,7 +31,6 @@ 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.provider.TestableConnectionProvider;
import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSONBuilder;
@@ -140,12 +138,6 @@ public class ResourceIteratorTest {
assertThat(ix, is(greaterThanOrEqualTo(0)));
}
- @Override
- public int accept(int... httpStatus) throws AcmeException {
- assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_OK));
- return HttpURLConnection.HTTP_OK;
- }
-
@Override
public JSON readJsonResponse() {
int start = ix * RESOURCES_PER_PAGE;
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeProviderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeProviderTest.java
index 6ed1dfcd..4f9ef8c4 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeProviderTest.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeProviderTest.java
@@ -20,7 +20,6 @@ import static org.mockito.Mockito.*;
import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
-import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -84,7 +83,6 @@ public class AbstractAcmeProviderTest {
final Connection connection = mock(Connection.class);
final Session session = mock(Session.class);
- when(connection.accept(any(Integer.class))).thenReturn(HttpURLConnection.HTTP_OK);
when(connection.readJsonResponse()).thenReturn(getJSON("directory"));
AbstractAcmeProvider provider = new AbstractAcmeProvider() {
@@ -110,7 +108,6 @@ public class AbstractAcmeProviderTest {
assertThat(map.toString(), sameJSONAs(TestUtils.getJSON("directory").toString()));
verify(connection).sendRequest(testResolvedUrl, session);
- verify(connection).accept(any(Integer.class));
verify(connection).updateSession(any(Session.class));
verify(connection).readJsonResponse();
verify(connection).close();
diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/toolbox/TestUtils.java b/acme4j-client/src/test/java/org/shredzone/acme4j/toolbox/TestUtils.java
index 128e6dd8..4fa20890 100644
--- a/acme4j-client/src/test/java/org/shredzone/acme4j/toolbox/TestUtils.java
+++ b/acme4j-client/src/test/java/org/shredzone/acme4j/toolbox/TestUtils.java
@@ -75,6 +75,8 @@ public final class TestUtils {
public static final String ACME_SERVER_URI = "https://example.com/acme";
+ public static final byte[] DUMMY_NONCE = "foo-nonce-foo".getBytes();
+
private TestUtils() {
// utility class without constructor
}