mirror of https://github.com/shred/acme4j
Review exceptions, closes issue #10
parent
bfa3f92a93
commit
158c3c46d1
|
@ -68,7 +68,6 @@ public interface AcmeClient {
|
|||
* @param registration
|
||||
* {@link Registration}, with the new key pair and the account location URI
|
||||
* set
|
||||
* @throws AcmeException
|
||||
*/
|
||||
void recoverRegistration(Registration registration) throws AcmeException;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.provider.AcmeClientProvider;
|
||||
|
||||
/**
|
||||
|
@ -44,13 +43,12 @@ public final class AcmeClientFactory {
|
|||
* URI of the ACME server. This can either be a http/https URI to the
|
||||
* server's directory service, or a special acme URI for specific
|
||||
* implementations.
|
||||
* @return {@link AcmeClient} for communication with the server
|
||||
*/
|
||||
public static AcmeClient connect(String serverUri) throws AcmeException {
|
||||
public static AcmeClient connect(String serverUri) {
|
||||
try {
|
||||
return connect(new URI(serverUri));
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
throw new IllegalArgumentException("Invalid server URI", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +61,7 @@ public final class AcmeClientFactory {
|
|||
* implementations.
|
||||
* @return {@link AcmeClient} for communication with the server
|
||||
*/
|
||||
public static AcmeClient connect(URI serverUri) throws AcmeException {
|
||||
public static AcmeClient connect(URI serverUri) {
|
||||
if (serverUri == null) {
|
||||
throw new NullPointerException("serverUri must not be null");
|
||||
}
|
||||
|
@ -76,9 +74,9 @@ public final class AcmeClientFactory {
|
|||
}
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
throw new AcmeException("No ACME provider found for " + serverUri);
|
||||
throw new IllegalArgumentException("No ACME provider found for " + serverUri);
|
||||
} else if (candidates.size() > 1) {
|
||||
throw new AcmeException("There are " + candidates.size() + " "
|
||||
throw new IllegalStateException("There are " + candidates.size() + " "
|
||||
+ AcmeClientProvider.class.getSimpleName() + " accepting " + serverUri
|
||||
+ ". Please check your classpath.");
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.security.MessageDigest;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.jose4j.base64url.Base64Url;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
||||
/**
|
||||
* Implements the {@value TYPE} challenge.
|
||||
|
@ -45,8 +46,7 @@ public class Dns01Challenge extends GenericTokenChallenge {
|
|||
byte[] digest = md.digest();
|
||||
return Base64Url.encode(digest);
|
||||
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
|
||||
// both should be standard in JDK...
|
||||
throw new RuntimeException(ex);
|
||||
throw new AcmeProtocolException("Failed to compute digest", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.jose4j.jwk.JsonWebKey;
|
|||
import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
|
||||
import org.jose4j.lang.JoseException;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.TimestampParser;
|
||||
|
||||
|
@ -75,7 +76,7 @@ public class GenericChallenge implements Challenge {
|
|||
try {
|
||||
return new URI(uri);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Invalid URI", ex);
|
||||
throw new AcmeProtocolException("Invalid URI", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ public class GenericChallenge implements Challenge {
|
|||
throw new IllegalArgumentException("map does not contain a type");
|
||||
}
|
||||
if (!acceptable(type)) {
|
||||
throw new IllegalArgumentException("wrong type: " + type);
|
||||
throw new AcmeProtocolException("wrong type: " + type);
|
||||
}
|
||||
|
||||
data.clear();
|
||||
|
@ -155,7 +156,7 @@ public class GenericChallenge implements Challenge {
|
|||
md.update(cb.toString().getBytes("UTF-8"));
|
||||
return md.digest();
|
||||
} catch (JoseException | NoSuchAlgorithmException | UnsupportedEncodingException ex) {
|
||||
throw new IllegalArgumentException("Cannot compute key thumbprint", ex);
|
||||
throw new AcmeProtocolException("Cannot compute key thumbprint", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +176,7 @@ public class GenericChallenge implements Challenge {
|
|||
data = new HashMap<>(JsonUtil.parseJson(in.readUTF()));
|
||||
in.defaultReadObject();
|
||||
} catch (JoseException ex) {
|
||||
throw new IOException("Cannot deserialize", ex);
|
||||
throw new AcmeProtocolException("Cannot deserialize", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.jose4j.base64url.Base64Url;
|
|||
import org.jose4j.json.JsonUtil;
|
||||
import org.jose4j.lang.JoseException;
|
||||
import org.shredzone.acme4j.Registration;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.ValidationBuilder;
|
||||
|
||||
|
@ -112,7 +113,7 @@ public class ProofOfPossession01Challenge extends GenericChallenge {
|
|||
}
|
||||
}
|
||||
} catch (CertificateException | IOException ex) {
|
||||
throw new IllegalArgumentException("Invalid certs", ex);
|
||||
throw new AcmeProtocolException("Invalid certificates", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ public class ProofOfPossession01Challenge extends GenericChallenge {
|
|||
cb.put(KEY_AUTHORIZATION, JsonUtil.parseJson(validation));
|
||||
} catch (JoseException ex) {
|
||||
// should not happen, as the JSON is prevalidated in the setter
|
||||
throw new IllegalStateException("validation: invalid JSON", ex);
|
||||
throw new AcmeProtocolException("validation: invalid JSON", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.security.MessageDigest;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.shredzone.acme4j.Registration;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
||||
/**
|
||||
* Implements the {@value TYPE} challenge.
|
||||
|
@ -75,8 +76,7 @@ public class TlsSni01Challenge extends GenericTokenChallenge {
|
|||
}
|
||||
return new String(result);
|
||||
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
|
||||
// Algorithm and Encoding are standard on Java
|
||||
throw new RuntimeException(ex);
|
||||
throw new AcmeProtocolException("Could not compute hash", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
package org.shredzone.acme4j.connector;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Map;
|
||||
|
@ -36,7 +37,7 @@ public interface Connection extends AutoCloseable {
|
|||
* {@link URI} to send the request to.
|
||||
* @return HTTP response code
|
||||
*/
|
||||
int sendRequest(URI uri) throws AcmeException;
|
||||
int sendRequest(URI uri) throws IOException;
|
||||
|
||||
/**
|
||||
* Sends a signed POST request.
|
||||
|
@ -52,28 +53,28 @@ public interface Connection extends AutoCloseable {
|
|||
* @return HTTP response code
|
||||
*/
|
||||
int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration)
|
||||
throws AcmeException;
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Reads a server response as JSON data.
|
||||
*
|
||||
* @return Map containing the parsed JSON data
|
||||
*/
|
||||
Map<String, Object> readJsonResponse() throws AcmeException;
|
||||
Map<String, Object> readJsonResponse() throws IOException;
|
||||
|
||||
/**
|
||||
* Reads a certificate.
|
||||
*
|
||||
* @return {@link X509Certificate} that was read.
|
||||
*/
|
||||
X509Certificate readCertificate() throws AcmeException;
|
||||
X509Certificate readCertificate() throws IOException;
|
||||
|
||||
/**
|
||||
* Reads a resource directory.
|
||||
*
|
||||
* @return Map of {@link Resource} and the respective {@link URI} to invoke
|
||||
*/
|
||||
Map<Resource, URI> readDirectory() throws AcmeException;
|
||||
Map<Resource, URI> readDirectory() throws IOException;
|
||||
|
||||
/**
|
||||
* Updates a {@link Session} by evaluating the HTTP response header.
|
||||
|
@ -81,14 +82,14 @@ public interface Connection extends AutoCloseable {
|
|||
* @param session
|
||||
* {@link Session} instance to be updated
|
||||
*/
|
||||
void updateSession(Session session) throws AcmeException;
|
||||
void updateSession(Session session);
|
||||
|
||||
/**
|
||||
* Gets a location from the {@code Location} header.
|
||||
*
|
||||
* @return Location {@link URI}, or {@code null} if no Location header was set
|
||||
*/
|
||||
URI getLocation() throws AcmeException;
|
||||
URI getLocation();
|
||||
|
||||
/**
|
||||
* Gets a link relation from the header.
|
||||
|
@ -97,14 +98,14 @@ public interface Connection extends AutoCloseable {
|
|||
* Link relation
|
||||
* @return Link, or {@code null} if there was no such link relation
|
||||
*/
|
||||
URI getLink(String relation) throws AcmeException;
|
||||
URI getLink(String relation);
|
||||
|
||||
/**
|
||||
* Handles a problem by throwing an exception. If a JSON problem was returned, an
|
||||
* {@link AcmeServerException} will be thrown. Otherwise a generic
|
||||
* {@link AcmeException} is thrown.
|
||||
*/
|
||||
void throwAcmeException() throws AcmeException;
|
||||
void throwAcmeException() throws AcmeException, IOException;
|
||||
|
||||
/**
|
||||
* Closes the {@link Connection}, releasing all resources.
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.exception;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a network error occured while communicating with the
|
||||
* server.
|
||||
*
|
||||
* @author Richard "Shred" Körber
|
||||
*/
|
||||
public class AcmeNetworkException extends AcmeException {
|
||||
private static final long serialVersionUID = 2054398693543329179L;
|
||||
|
||||
/**
|
||||
* Create a new {@link AcmeNetworkException}.
|
||||
*
|
||||
* @param cause
|
||||
* {@link IOException} that caused the network error
|
||||
*/
|
||||
public AcmeNetworkException(IOException cause) {
|
||||
super("Network error", cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.exception;
|
||||
|
||||
/**
|
||||
* This runtime exception is thrown on ACME protocol errors that should not occur. For
|
||||
* example, this exception is thrown when a server response could not be parsed.
|
||||
*
|
||||
* @author Richard "Shred" Körber
|
||||
*/
|
||||
public class AcmeProtocolException extends RuntimeException {
|
||||
private static final long serialVersionUID = 2031203835755725193L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AcmeProtocolException}.
|
||||
*
|
||||
* @param msg
|
||||
* Reason of the exception
|
||||
*/
|
||||
public AcmeProtocolException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AcmeProtocolException}.
|
||||
*
|
||||
* @param msg
|
||||
* Reason of the exception
|
||||
* @param cause
|
||||
* Cause
|
||||
*/
|
||||
public AcmeProtocolException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
package org.shredzone.acme4j.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
|
@ -37,6 +38,8 @@ import org.shredzone.acme4j.connector.Resource;
|
|||
import org.shredzone.acme4j.connector.Session;
|
||||
import org.shredzone.acme4j.exception.AcmeConflictException;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeNetworkException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.SignatureUtils;
|
||||
import org.shredzone.acme4j.util.TimestampParser;
|
||||
|
@ -125,6 +128,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
if (rc == HttpURLConnection.HTTP_CONFLICT) {
|
||||
throw new AcmeConflictException("Account is already registered", location);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,6 +167,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
if (tos != null) {
|
||||
registration.setAgreement(tos);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +205,7 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
|
||||
newKey = jws.getCompactSerialization();
|
||||
} catch (JoseException ex) {
|
||||
throw new IllegalArgumentException("Bad newKeyPair", ex);
|
||||
throw new AcmeProtocolException("Bad newKeyPair", ex);
|
||||
}
|
||||
|
||||
LOG.debug("changeRegistrationKey");
|
||||
|
@ -211,6 +218,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
if (rc != HttpURLConnection.HTTP_ACCEPTED) {
|
||||
conn.throwAcmeException();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,6 +253,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
if (tos != null) {
|
||||
registration.setAgreement(tos);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,6 +287,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
|
||||
Map<String, Object> result = conn.readJsonResponse();
|
||||
unmarshalAuthorization(result, auth);
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,6 +312,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
|
||||
Map<String, Object> result = conn.readJsonResponse();
|
||||
unmarshalAuthorization(result, auth);
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,6 +341,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
}
|
||||
|
||||
challenge.unmarshall(conn.readJsonResponse());
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,6 +363,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
}
|
||||
|
||||
challenge.unmarshall(conn.readJsonResponse());
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,10 +384,12 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
|
||||
Map<String, Object> json = conn.readJsonResponse();
|
||||
if (!(json.containsKey("type"))) {
|
||||
throw new AcmeException("Provided URI is not a challenge URI");
|
||||
throw new IllegalArgumentException("Provided URI is not a challenge URI");
|
||||
}
|
||||
|
||||
return (T) createChallenge(json);
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,6 +419,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
// X509Certificate cert = conn.readCertificate();
|
||||
|
||||
return conn.getLocation();
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,6 +438,8 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
}
|
||||
|
||||
return conn.readCertificate();
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,7 +455,7 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
LOG.debug("revokeCertificate");
|
||||
URI resUri = resourceUri(Resource.REVOKE_CERT);
|
||||
if (resUri == null) {
|
||||
throw new AcmeException("CA does not support certificate revocation");
|
||||
throw new AcmeProtocolException("CA does not support certificate revocation");
|
||||
}
|
||||
|
||||
try (Connection conn = createConnection()) {
|
||||
|
@ -443,7 +468,9 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
|||
conn.throwAcmeException();
|
||||
}
|
||||
} catch (CertificateEncodingException ex) {
|
||||
throw new IllegalArgumentException("Invalid certificate", ex);
|
||||
throw new AcmeProtocolException("Invalid certificate", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.shredzone.acme4j.connector.Resource;
|
|||
import org.shredzone.acme4j.connector.Session;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeRateLimitExceededException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.exception.AcmeServerException;
|
||||
import org.shredzone.acme4j.exception.AcmeUnauthorizedException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
|
@ -72,35 +73,29 @@ public class DefaultConnection implements Connection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int sendRequest(URI uri) throws AcmeException {
|
||||
public int sendRequest(URI uri) throws IOException {
|
||||
if (uri == null) {
|
||||
throw new NullPointerException("uri must not be null");
|
||||
}
|
||||
if (conn != null) {
|
||||
throw new IllegalStateException("Connection was not closed. Race condition?");
|
||||
}
|
||||
assertConnectionIsClosed();
|
||||
|
||||
try {
|
||||
LOG.debug("GET {}", uri);
|
||||
LOG.debug("GET {}", uri);
|
||||
|
||||
conn = httpConnector.openConnection(uri);
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
||||
conn.setDoOutput(false);
|
||||
conn = httpConnector.openConnection(uri);
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
||||
conn.setDoOutput(false);
|
||||
|
||||
conn.connect();
|
||||
conn.connect();
|
||||
|
||||
logHeaders();
|
||||
logHeaders();
|
||||
|
||||
return conn.getResponseCode();
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeException("Request failed: " + uri, ex);
|
||||
}
|
||||
return conn.getResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration)
|
||||
throws AcmeException {
|
||||
throws IOException {
|
||||
if (uri == null) {
|
||||
throw new NullPointerException("uri must not be null");
|
||||
}
|
||||
|
@ -113,9 +108,7 @@ public class DefaultConnection implements Connection {
|
|||
if (registration == null) {
|
||||
throw new NullPointerException("registration must not be null");
|
||||
}
|
||||
if (conn != null) {
|
||||
throw new IllegalStateException("Connection was not closed. Race condition?");
|
||||
}
|
||||
assertConnectionIsClosed();
|
||||
|
||||
try {
|
||||
KeyPair keypair = registration.getKeyPair();
|
||||
|
@ -130,7 +123,7 @@ public class DefaultConnection implements Connection {
|
|||
}
|
||||
|
||||
if (session.getNonce() == null) {
|
||||
throw new AcmeException("No nonce available");
|
||||
throw new AcmeProtocolException("Server did not provide a nonce");
|
||||
}
|
||||
|
||||
LOG.debug("POST {} with claims: {}", uri, claims);
|
||||
|
@ -164,21 +157,19 @@ public class DefaultConnection implements Connection {
|
|||
updateSession(session);
|
||||
|
||||
return conn.getResponseCode();
|
||||
} catch (JoseException | IOException ex) {
|
||||
throw new AcmeException("Request failed: " + uri, ex);
|
||||
} catch (JoseException ex) {
|
||||
throw new AcmeProtocolException("Failed to generate a JSON request", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public Map<String, Object> readJsonResponse() throws IOException {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
String contentType = conn.getHeaderField("Content-Type");
|
||||
if (!("application/json".equals(contentType)
|
||||
|| "application/problem+json".equals(contentType))) {
|
||||
throw new AcmeException("Unexpected content type: " + contentType);
|
||||
throw new AcmeProtocolException("Unexpected content type: " + contentType);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
@ -195,41 +186,37 @@ public class DefaultConnection implements Connection {
|
|||
LOG.debug("Result JSON: {}", sb);
|
||||
}
|
||||
|
||||
} catch (JoseException | IOException ex) {
|
||||
throw new AcmeException("Failed to parse response: " + sb, ex);
|
||||
} catch (JoseException ex) {
|
||||
throw new AcmeProtocolException("Failed to parse response: " + sb, ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate readCertificate() throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public X509Certificate readCertificate() throws IOException {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
String contentType = conn.getHeaderField("Content-Type");
|
||||
if (!("application/pkix-cert".equals(contentType))) {
|
||||
throw new AcmeException("Unexpected content type: " + contentType);
|
||||
throw new AcmeProtocolException("Unexpected content type: " + contentType);
|
||||
}
|
||||
|
||||
try (InputStream in = conn.getInputStream()) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) cf.generateCertificate(in);
|
||||
} catch (CertificateException | IOException ex) {
|
||||
throw new AcmeException("Failed to read certificate", ex);
|
||||
} catch (CertificateException ex) {
|
||||
throw new AcmeProtocolException("Failed to read certificate", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Resource, URI> readDirectory() throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public Map<Resource, URI> readDirectory() throws IOException {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
String contentType = conn.getHeaderField("Content-Type");
|
||||
if (!("application/json".equals(contentType))) {
|
||||
throw new AcmeException("Unexpected content type: " + contentType);
|
||||
throw new AcmeProtocolException("Unexpected content type: " + contentType);
|
||||
}
|
||||
|
||||
EnumMap<Resource, URI> resourceMap = new EnumMap<>(Resource.class);
|
||||
|
@ -250,18 +237,16 @@ public class DefaultConnection implements Connection {
|
|||
}
|
||||
|
||||
LOG.debug("Resource directory: {}", resourceMap);
|
||||
} catch (JoseException | URISyntaxException | IOException ex) {
|
||||
throw new AcmeException("Failed to read directory: " + sb, ex);
|
||||
} catch (JoseException | URISyntaxException ex) {
|
||||
throw new AcmeProtocolException("Failed to read directory: " + sb, ex);
|
||||
}
|
||||
|
||||
return resourceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSession(Session session) throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public void updateSession(Session session) {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
String nonceHeader = conn.getHeaderField("Replay-Nonce");
|
||||
if (nonceHeader == null || nonceHeader.trim().isEmpty()) {
|
||||
|
@ -269,7 +254,7 @@ public class DefaultConnection implements Connection {
|
|||
}
|
||||
|
||||
if (!BASE64URL_PATTERN.matcher(nonceHeader).matches()) {
|
||||
throw new AcmeException("Invalid replay nonce: " + nonceHeader);
|
||||
throw new AcmeProtocolException("Invalid replay nonce: " + nonceHeader);
|
||||
}
|
||||
|
||||
LOG.debug("Replay Nonce: {}", nonceHeader);
|
||||
|
@ -278,10 +263,8 @@ public class DefaultConnection implements Connection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public URI getLocation() {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
String location = conn.getHeaderField("Location");
|
||||
if (location == null) {
|
||||
|
@ -292,15 +275,13 @@ public class DefaultConnection implements Connection {
|
|||
LOG.debug("Location: {}", location);
|
||||
return new URI(location);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new AcmeException("Bad Location header: " + location);
|
||||
throw new AcmeProtocolException("Bad Location header: " + location);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLink(String relation) throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public URI getLink(String relation) {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
List<String> links = conn.getHeaderFields().get("Link");
|
||||
if (links != null) {
|
||||
|
@ -313,19 +294,18 @@ public class DefaultConnection implements Connection {
|
|||
LOG.debug("Link: {} -> {}", relation, location);
|
||||
return new URI(location);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new AcmeException("Bad '" + relation + "' Link header: " + link);
|
||||
throw new AcmeProtocolException("Bad '" + relation + "' Link header: " + link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void throwAcmeException() throws AcmeException {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected");
|
||||
}
|
||||
public void throwAcmeException() throws AcmeException, IOException {
|
||||
assertConnectionIsOpen();
|
||||
|
||||
if ("application/problem+json".equals(conn.getHeaderField("Content-Type"))) {
|
||||
Map<String, Object> map = readJsonResponse();
|
||||
|
@ -351,12 +331,8 @@ public class DefaultConnection implements Connection {
|
|||
throw new AcmeServerException(type, detail);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
throw new AcmeException("HTTP " + conn.getResponseCode() + ": "
|
||||
+ conn.getResponseMessage());
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeException("Network error");
|
||||
}
|
||||
throw new AcmeException("HTTP " + conn.getResponseCode() + ": "
|
||||
+ conn.getResponseMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,6 +341,24 @@ public class DefaultConnection implements Connection {
|
|||
conn = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the connection is currently open. Throws an exception if not.
|
||||
*/
|
||||
private void assertConnectionIsOpen() {
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Not connected.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the connection is currently closed. Throws an exception if not.
|
||||
*/
|
||||
private void assertConnectionIsClosed() {
|
||||
if (conn != null) {
|
||||
throw new IllegalStateException("Previous connection is not closed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log all HTTP headers in debug mode.
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
package org.shredzone.acme4j.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
|
@ -26,6 +27,8 @@ import org.shredzone.acme4j.challenge.GenericTokenChallenge;
|
|||
import org.shredzone.acme4j.connector.Connection;
|
||||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeNetworkException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.provider.AcmeClientProvider;
|
||||
|
||||
/**
|
||||
|
@ -92,7 +95,7 @@ public class GenericAcmeClient extends AbstractAcmeClient {
|
|||
|
||||
if (directoryMap.isEmpty() || !directoryCacheExpiry.after(now)) {
|
||||
if (directoryUri == null) {
|
||||
throw new IllegalStateException("directoryUri was null on construction time");
|
||||
throw new AcmeProtocolException("directoryUri was null on construction time");
|
||||
}
|
||||
|
||||
try (Connection conn = createConnection()) {
|
||||
|
@ -110,6 +113,8 @@ public class GenericAcmeClient extends AbstractAcmeClient {
|
|||
directoryMap.clear();
|
||||
directoryMap.putAll(newMap);
|
||||
directoryCacheExpiry = new Date(now.getTime() + 60 * 60 * 1000L);
|
||||
} catch (IOException ex) {
|
||||
throw new AcmeNetworkException(ex);
|
||||
}
|
||||
}
|
||||
return directoryMap.get(resource);
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.net.URI;
|
|||
import java.net.URISyntaxException;
|
||||
|
||||
import org.shredzone.acme4j.connector.HttpConnector;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.provider.AbstractAcmeClientProvider;
|
||||
import org.shredzone.acme4j.provider.AcmeClientProvider;
|
||||
|
||||
|
@ -58,7 +59,7 @@ public class LetsEncryptAcmeClientProvider extends AbstractAcmeClientProvider {
|
|||
try {
|
||||
return new URI(directoryUri);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException(directoryUri, ex);
|
||||
throw new AcmeProtocolException(directoryUri, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.jose4j.jwk.JsonWebKey;
|
|||
import org.jose4j.jwk.PublicJsonWebKey;
|
||||
import org.jose4j.lang.JoseException;
|
||||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
||||
/**
|
||||
* Builder for claim structures.
|
||||
|
@ -128,7 +129,7 @@ public class ClaimBuilder {
|
|||
object(key).putAll(jwkParams);
|
||||
return this;
|
||||
} catch (JoseException ex) {
|
||||
throw new IllegalArgumentException("Invalid key", ex);
|
||||
throw new AcmeProtocolException("Invalid key", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.jose4j.jws.JsonWebSignature;
|
|||
import org.jose4j.lang.JoseException;
|
||||
import org.shredzone.acme4j.Registration;
|
||||
import org.shredzone.acme4j.challenge.ProofOfPossession01Challenge;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
||||
/**
|
||||
* Generates a validation string for {@link ProofOfPossession01Challenge}.
|
||||
|
@ -121,7 +122,7 @@ public class ValidationBuilder {
|
|||
auth.put("signature", jws.getEncodedSignature());
|
||||
return auth.toString();
|
||||
} catch (JoseException ex) {
|
||||
throw new IllegalArgumentException("Failed to sign", ex);
|
||||
throw new AcmeProtocolException("Failed to sign", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.ServiceLoader;
|
|||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.challenge.Challenge;
|
||||
import org.shredzone.acme4j.connector.Connection;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.provider.AcmeClientProvider;
|
||||
|
||||
/**
|
||||
|
@ -43,26 +42,26 @@ public class AcmeClientFactoryTest {
|
|||
* the correct {@link AcmeClientProvider}.
|
||||
*/
|
||||
@Test
|
||||
public void testConnectURI() throws URISyntaxException, AcmeException {
|
||||
public void testConnectURI() throws URISyntaxException {
|
||||
AcmeClient client = AcmeClientFactory.connect(new URI("acme://example.com"));
|
||||
assertThat(client, is(sameInstance(DUMMY_CLIENT)));
|
||||
}
|
||||
|
||||
/**
|
||||
* There are no testing providers accepting {@code acme://example.org}. Test that
|
||||
* connecting to this URI will result in an {@link AcmeException}.
|
||||
* connecting to this URI will result in an {@link IllegalArgumentException}.
|
||||
*/
|
||||
@Test(expected = AcmeException.class)
|
||||
public void testNone() throws URISyntaxException, AcmeException {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNone() throws URISyntaxException {
|
||||
AcmeClientFactory.connect(new URI("acme://example.org"));
|
||||
}
|
||||
|
||||
/**
|
||||
* There are two testing providers accepting {@code acme://example.net}. Test that
|
||||
* connecting to this URI will result in an {@link AcmeException}.
|
||||
* connecting to this URI will result in an {@link IllegalStateException}.
|
||||
*/
|
||||
@Test(expected = AcmeException.class)
|
||||
public void testDuplicate() throws URISyntaxException, AcmeException {
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testDuplicate() throws URISyntaxException {
|
||||
AcmeClientFactory.connect(new URI("acme://example.net"));
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.jose4j.jwk.JsonWebKey.OutputControlLevel;
|
|||
import org.jose4j.lang.JoseException;
|
||||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.TestUtils;
|
||||
import org.shredzone.acme4j.util.TimestampParser;
|
||||
|
@ -86,7 +87,7 @@ public class GenericChallengeTest {
|
|||
/**
|
||||
* Test that an exception is thrown on challenge type mismatch.
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test(expected = AcmeProtocolException.class)
|
||||
public void testNotAcceptable() throws URISyntaxException {
|
||||
Http01Challenge challenge = new Http01Challenge();
|
||||
challenge.unmarshall(TestUtils.getJsonAsMap("dnsChallenge"));
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.shredzone.acme4j.connector.Connection;
|
|||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.connector.Session;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.TestUtils;
|
||||
import org.shredzone.acme4j.util.TimestampParser;
|
||||
|
@ -80,7 +81,7 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(uri, is(resourceUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("newRegistration")));
|
||||
assertThat(session, is(notNullValue()));
|
||||
|
@ -89,12 +90,12 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
return locationUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLink(String relation) throws AcmeException {
|
||||
public URI getLink(String relation) {
|
||||
switch(relation) {
|
||||
case "terms-of-service": return agreementUri;
|
||||
default: return null;
|
||||
|
@ -123,7 +124,7 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(uri, is(locationUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("modifyRegistration")));
|
||||
assertThat(session, is(notNullValue()));
|
||||
|
@ -132,12 +133,12 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
return locationUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLink(String relation) throws AcmeException {
|
||||
public URI getLink(String relation) {
|
||||
switch(relation) {
|
||||
case "terms-of-service": return agreementUri;
|
||||
default: return null;
|
||||
|
@ -165,7 +166,7 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
Map<String, Object> claimMap = claims.toMap();
|
||||
assertThat(claimMap.get("resource"), is((Object) "reg"));
|
||||
assertThat(claimMap.get("newKey"), not(nullValue()));
|
||||
|
@ -185,7 +186,7 @@ public class AbstractAcmeClientTest {
|
|||
jws.setKey(newKeyPair.getPublic());
|
||||
assertThat(jws.getPayload(), sameJSONAs(expectedPayload.toString()));
|
||||
} catch (JoseException ex) {
|
||||
throw new AcmeException("Bad newKey", ex);
|
||||
throw new AcmeProtocolException("Bad newKey", ex);
|
||||
}
|
||||
|
||||
assertThat(uri, is(locationUri));
|
||||
|
@ -195,7 +196,7 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
return locationUri;
|
||||
}
|
||||
};
|
||||
|
@ -209,7 +210,7 @@ public class AbstractAcmeClientTest {
|
|||
* Test that the same account key is not accepted for change
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testChangeRegistrationSameKey() throws AcmeException, IOException {
|
||||
public void testChangeRegistrationSameKey() throws AcmeException {
|
||||
Registration registration = new Registration(accountKeyPair);
|
||||
registration.setLocation(locationUri);
|
||||
|
||||
|
@ -230,21 +231,19 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
assertThat(uri, is(resourceUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("recoverRegistration")));
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(session, is(notNullValue()));
|
||||
assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair)));
|
||||
return HttpURLConnection.HTTP_CREATED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
return anotherLocationUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLink(String relation) throws AcmeException {
|
||||
public URI getLink(String relation) {
|
||||
switch(relation) {
|
||||
case "terms-of-service": return agreementUri;
|
||||
default: return null;
|
||||
|
@ -271,7 +270,7 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(uri, is(resourceUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("newAuthorizationRequest")));
|
||||
assertThat(session, is(notNullValue()));
|
||||
|
@ -280,12 +279,12 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String, Object> readJsonResponse() {
|
||||
return getJsonAsMap("newAuthorizationResponse");
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
return locationUri;
|
||||
}
|
||||
};
|
||||
|
@ -324,13 +323,13 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendRequest(URI uri) throws AcmeException {
|
||||
public int sendRequest(URI uri) {
|
||||
assertThat(uri, is(locationUri));
|
||||
return HttpURLConnection.HTTP_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String, Object> readJsonResponse() {
|
||||
return getJsonAsMap("updateAuthorizationResponse");
|
||||
}
|
||||
};
|
||||
|
@ -366,7 +365,7 @@ public class AbstractAcmeClientTest {
|
|||
public void testTriggerChallenge() throws AcmeException {
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(uri, is(resourceUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("triggerHttpChallengeRequest")));
|
||||
assertThat(session, is(notNullValue()));
|
||||
|
@ -375,7 +374,7 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String, Object> readJsonResponse() {
|
||||
return getJsonAsMap("triggerHttpChallengeResponse");
|
||||
}
|
||||
};
|
||||
|
@ -399,13 +398,13 @@ public class AbstractAcmeClientTest {
|
|||
public void testUpdateChallenge() throws AcmeException {
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendRequest(URI uri) throws AcmeException {
|
||||
public int sendRequest(URI uri) {
|
||||
assertThat(uri, is(locationUri));
|
||||
return HttpURLConnection.HTTP_ACCEPTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String, Object> readJsonResponse() {
|
||||
return getJsonAsMap("updateHttpChallengeResponse");
|
||||
}
|
||||
};
|
||||
|
@ -425,13 +424,13 @@ public class AbstractAcmeClientTest {
|
|||
public void testRestoreChallenge() throws AcmeException {
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendRequest(URI uri) throws AcmeException {
|
||||
public int sendRequest(URI uri) {
|
||||
assertThat(uri, is(locationUri));
|
||||
return HttpURLConnection.HTTP_ACCEPTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String, Object> readJsonResponse() {
|
||||
return getJsonAsMap("updateHttpChallengeResponse");
|
||||
}
|
||||
};
|
||||
|
@ -452,7 +451,7 @@ public class AbstractAcmeClientTest {
|
|||
public void testRequestCertificate() throws AcmeException, IOException {
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(uri, is(resourceUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequest")));
|
||||
assertThat(session, is(notNullValue()));
|
||||
|
@ -461,7 +460,7 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
return locationUri;
|
||||
}
|
||||
};
|
||||
|
@ -484,13 +483,13 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendRequest(URI uri) throws AcmeException {
|
||||
public int sendRequest(URI uri) {
|
||||
assertThat(uri, is(locationUri));
|
||||
return HttpURLConnection.HTTP_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate readCertificate() throws AcmeException {
|
||||
public X509Certificate readCertificate() {
|
||||
return originalCert;
|
||||
}
|
||||
};
|
||||
|
@ -510,7 +509,7 @@ public class AbstractAcmeClientTest {
|
|||
|
||||
Connection connection = new DummyConnection() {
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
assertThat(uri, is(resourceUri));
|
||||
assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateRequest")));
|
||||
assertThat(session, is(notNullValue()));
|
||||
|
@ -566,7 +565,7 @@ public class AbstractAcmeClientTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected URI resourceUri(Resource resource) throws AcmeException {
|
||||
protected URI resourceUri(Resource resource) {
|
||||
if (resourceMap.isEmpty()) {
|
||||
fail("Unexpected invocation of resourceUri()");
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.shredzone.acme4j.connector.HttpConnector;
|
|||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.connector.Session;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.exception.AcmeServerException;
|
||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||
import org.shredzone.acme4j.util.TestUtils;
|
||||
|
@ -91,7 +92,7 @@ public class DefaultConnectionTest {
|
|||
* {@code Replay-Nonce} header correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testGetNonceFromHeader() throws AcmeException {
|
||||
public void testGetNonceFromHeader() {
|
||||
byte[] nonce = "foo-nonce-foo".getBytes();
|
||||
|
||||
when(mockUrlConnection.getHeaderField("Replay-Nonce"))
|
||||
|
@ -113,7 +114,7 @@ public class DefaultConnectionTest {
|
|||
* {@code Replay-Nonce} header.
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidNonceFromHeader() throws AcmeException {
|
||||
public void testInvalidNonceFromHeader() {
|
||||
String badNonce = "#$%&/*+*#'";
|
||||
|
||||
when(mockUrlConnection.getHeaderField("Replay-Nonce")).thenReturn(badNonce);
|
||||
|
@ -123,7 +124,7 @@ public class DefaultConnectionTest {
|
|||
conn.conn = mockUrlConnection;
|
||||
conn.updateSession(session);
|
||||
fail("Expected to fail");
|
||||
} catch (AcmeException ex) {
|
||||
} catch (AcmeProtocolException ex) {
|
||||
assertThat(ex.getMessage(), org.hamcrest.Matchers.startsWith("Invalid replay nonce"));
|
||||
}
|
||||
|
||||
|
@ -227,7 +228,7 @@ public class DefaultConnectionTest {
|
|||
|
||||
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
|
||||
@Override
|
||||
public Map<String,Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String,Object> readJsonResponse() {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("type", "urn:zombie:error:apocalypse");
|
||||
result.put("detail", "Zombie apocalypse in progress");
|
||||
|
@ -241,7 +242,7 @@ public class DefaultConnectionTest {
|
|||
assertThat(ex.getType(), is("urn:zombie:error:apocalypse"));
|
||||
assertThat(ex.getMessage(), is("Zombie apocalypse in progress"));
|
||||
assertThat(ex.getAcmeErrorType(), is(nullValue()));
|
||||
} catch (AcmeException ex) {
|
||||
} catch (AcmeException | IOException ex) {
|
||||
fail("Expected an AcmeServerException");
|
||||
}
|
||||
|
||||
|
@ -259,7 +260,7 @@ public class DefaultConnectionTest {
|
|||
|
||||
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
|
||||
@Override
|
||||
public Map<String,Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String,Object> readJsonResponse() {
|
||||
return new HashMap<String, Object>();
|
||||
};
|
||||
}) {
|
||||
|
@ -268,6 +269,8 @@ public class DefaultConnectionTest {
|
|||
fail("Expected to fail");
|
||||
} catch (AcmeException ex) {
|
||||
assertThat(ex.getMessage(), not(isEmptyOrNullString()));
|
||||
} catch (IOException ex) {
|
||||
fail("Expected an AcmeException");
|
||||
}
|
||||
|
||||
verify(mockUrlConnection).getHeaderField("Content-Type");
|
||||
|
@ -305,7 +308,7 @@ public class DefaultConnectionTest {
|
|||
|
||||
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) {
|
||||
@Override
|
||||
public void updateSession(Session session) throws AcmeException {
|
||||
public void updateSession(Session session) {
|
||||
assertThat(session, is(sameInstance(testSession)));
|
||||
if (session.getNonce() == null) {
|
||||
session.setNonce(nonce1);
|
||||
|
|
|
@ -33,42 +33,42 @@ import org.shredzone.acme4j.util.ClaimBuilder;
|
|||
public class DummyConnection implements Connection {
|
||||
|
||||
@Override
|
||||
public int sendRequest(URI uri) throws AcmeException {
|
||||
public int sendRequest(URI uri) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException {
|
||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> readJsonResponse() throws AcmeException {
|
||||
public Map<String, Object> readJsonResponse() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate readCertificate() throws AcmeException {
|
||||
public X509Certificate readCertificate() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Resource, URI> readDirectory() throws AcmeException {
|
||||
public Map<Resource, URI> readDirectory() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSession(Session session) throws AcmeException {
|
||||
public void updateSession(Session session) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() throws AcmeException {
|
||||
public URI getLocation() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLink(String relation) throws AcmeException {
|
||||
public URI getLink(String relation) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import static org.hamcrest.Matchers.*;
|
|||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Date;
|
||||
|
@ -88,7 +89,7 @@ public class GenericAcmeClientTest {
|
|||
* Test that the directory is properly read and cached.
|
||||
*/
|
||||
@Test
|
||||
public void testResourceUri() throws AcmeException, URISyntaxException {
|
||||
public void testResourceUri() throws AcmeException, IOException, URISyntaxException {
|
||||
Map<Resource, URI> directoryMap = new HashMap<Resource, URI>();
|
||||
directoryMap.put(Resource.NEW_AUTHZ, new URI("http://example.com/acme/new-authz"));
|
||||
directoryMap.put(Resource.NEW_CERT, new URI("http://example.com/acme/new-cert"));
|
||||
|
|
Loading…
Reference in New Issue