From 62ed304f3a670405b8f4e9dd6b62f1e74e3ae399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Sun, 13 Dec 2015 16:01:25 +0100 Subject: [PATCH] Refactor, make AbstractAcmeClientProvider easier to use (and test) --- .../provider/AbstractAcmeClientProvider.java | 55 +++++++++++++++++++ .../provider/GenericAcmeClientProvider.java | 11 +--- .../LetsEncryptAcmeClientProvider.java | 49 +++-------------- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java index 51485cc2..616c0490 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java @@ -16,19 +16,26 @@ package org.shredzone.acme4j.provider; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URI; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.shredzone.acme4j.AcmeClient; import org.shredzone.acme4j.challenge.Challenge; import org.shredzone.acme4j.challenge.DnsChallenge; import org.shredzone.acme4j.challenge.GenericChallenge; import org.shredzone.acme4j.challenge.HttpChallenge; import org.shredzone.acme4j.challenge.ProofOfPossessionChallenge; import org.shredzone.acme4j.challenge.TlsSniChallenge; +import org.shredzone.acme4j.impl.GenericAcmeClient; /** * Abstract implementation of {@link AcmeClientProvider}. It consists of a challenge * registry and a standard {@link #openConnection(URI)} implementation. + *

+ * Implementing classes must implement at least {@link AcmeClientProvider#accepts(URI)} + * and {@link AbstractAcmeClientProvider#resolve(URI)}. * * @author Richard "Shred" Körber */ @@ -42,6 +49,26 @@ public abstract class AbstractAcmeClientProvider implements AcmeClientProvider { registerBaseChallenges(); } + /** + * Resolves the server URI and returns the matching directory URI. + * + * @param serverUri + * Server {@link URI} + * @return Resolved directory {@link URI} + * @throws IllegalArgumentException + * if the server {@link URI} is not accepted + */ + protected abstract URI resolve(URI serverUri); + + @Override + public AcmeClient connect(URI serverUri) { + if (!accepts(serverUri)) { + throw new IllegalArgumentException("This provider does not accept " + serverUri); + } + + return createAcmeClient(resolve(serverUri)); + } + @Override @SuppressWarnings("unchecked") public T createChallenge(String type) { @@ -79,9 +106,26 @@ public abstract class AbstractAcmeClientProvider implements AcmeClientProvider { * constructor. */ protected void registerChallenge(String type, Class clazz) { + if (type == null) { + throw new NullPointerException("type must not be null"); + } + if (clazz == null) { + throw new NullPointerException("Challenge class must not be null"); + } + if (type.trim().isEmpty()) { + throw new IllegalArgumentException("type must not be empty"); + } + challenges.put(type, clazz); } + /** + * Returns all registered challenge types. + */ + protected Collection getRegisteredChallengeTypes() { + return Collections.unmodifiableCollection(challenges.keySet()); + } + /** * Registers all standard challenges as specified in the ACME specifications. *

@@ -95,4 +139,15 @@ public abstract class AbstractAcmeClientProvider implements AcmeClientProvider { registerChallenge(HttpChallenge.TYPE, HttpChallenge.class); } + /** + * Creates an {@link AcmeClient} for the given directory URI. + * + * @param directoryUri + * Directory {@link URI} + * @return {@link AcmeClient} + */ + protected AcmeClient createAcmeClient(URI directoryUri) { + return new GenericAcmeClient(this, directoryUri); + } + } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/GenericAcmeClientProvider.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/GenericAcmeClientProvider.java index 5fea0872..0e97663b 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/GenericAcmeClientProvider.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/GenericAcmeClientProvider.java @@ -15,9 +15,6 @@ package org.shredzone.acme4j.provider; import java.net.URI; -import org.shredzone.acme4j.AcmeClient; -import org.shredzone.acme4j.impl.GenericAcmeClient; - /** * A generic {@link AcmeClientProvider}. It should be working for all ACME servers * complying to the ACME specifications. @@ -35,12 +32,8 @@ public class GenericAcmeClientProvider extends AbstractAcmeClientProvider { } @Override - public AcmeClient connect(URI serverUri) { - if (!accepts(serverUri)) { - throw new IllegalArgumentException("This provider does not accept " + serverUri); - } - - return new GenericAcmeClient(this, serverUri); + protected URI resolve(URI serverUri) { + return serverUri; } } diff --git a/acme4j-letsencrypt/src/main/java/org/shredzone/acme4j/provider/LetsEncryptAcmeClientProvider.java b/acme4j-letsencrypt/src/main/java/org/shredzone/acme4j/provider/LetsEncryptAcmeClientProvider.java index 1c0cb905..ac543600 100644 --- a/acme4j-letsencrypt/src/main/java/org/shredzone/acme4j/provider/LetsEncryptAcmeClientProvider.java +++ b/acme4j-letsencrypt/src/main/java/org/shredzone/acme4j/provider/LetsEncryptAcmeClientProvider.java @@ -28,9 +28,6 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; -import org.shredzone.acme4j.AcmeClient; -import org.shredzone.acme4j.impl.GenericAcmeClient; - /** * An {@link AcmeClientProvider} for Let's Encrypt. *

@@ -57,44 +54,7 @@ public class LetsEncryptAcmeClientProvider extends AbstractAcmeClientProvider { } @Override - public AcmeClient connect(URI serverUri) { - return createAcmeClient(resolve(serverUri)); - } - - @Override - public HttpURLConnection openConnection(URI uri) throws IOException { - HttpURLConnection conn = super.openConnection(uri); - if (conn instanceof HttpsURLConnection) { - ((HttpsURLConnection) conn).setSSLSocketFactory(createSocketFactory()); - } - return conn; - } - - /** - * Creates an {@link AcmeClient} for the given directory URI. - * - * @param directoryUri - * Directory {@link URI} - * @return {@link AcmeClient} - */ - protected AcmeClient createAcmeClient(URI directoryUri) { - return new GenericAcmeClient(this, directoryUri); - } - - /** - * Resolves the server URI and returns the matching directory URI. - * - * @param serverUri - * Server {@link URI} to resolve - * @return Directory {@link URI} - * @throws IllegalArgumentException - * if the server URI cannot be resolved - */ protected URI resolve(URI serverUri) { - if (!accepts(serverUri)) { - throw new IllegalArgumentException("Unknown URI " + serverUri); - } - String path = serverUri.getPath(); String directoryUri; if (path == null || "".equals(path) || "/".equals(path) || "/v01".equals(path)) { @@ -112,6 +72,15 @@ public class LetsEncryptAcmeClientProvider extends AbstractAcmeClientProvider { } } + @Override + public HttpURLConnection openConnection(URI uri) throws IOException { + HttpURLConnection conn = super.openConnection(uri); + if (conn instanceof HttpsURLConnection) { + ((HttpsURLConnection) conn).setSSLSocketFactory(createSocketFactory()); + } + return conn; + } + /** * Lazily creates an {@link SSLSocketFactory} that exclusively accepts the Let's * Encrypt certificate.