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 ca15d2ab..d306390d 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java @@ -116,7 +116,6 @@ public class Authorization extends AcmeJsonResource { * @throws ClassCastException * if the type does not match the expected Challenge class type */ - @SuppressWarnings("unchecked") @CheckForNull public T findChallenge(final String type) { return (T) getChallenges().stream() @@ -125,6 +124,25 @@ public class Authorization extends AcmeJsonResource { .orElse(null); } + /** + * Finds a {@link Challenge} of the given class type. Responding to this {@link + * Challenge} is sufficient for authorization. + * + * @param type + * Challenge type (e.g. "Http01Challenge.class") + * @return {@link Challenge} of that type, or {@code null} if there is no such + * challenge, or if the challenge alone is not sufficient for authorization. + * @since 2.8 + */ + @CheckForNull + public T findChallenge(Class type) { + return getChallenges().stream() + .filter(type::isInstance) + .map(type::cast) + .reduce((a, b) -> {throw new AcmeProtocolException("Found more than one challenge of type " + type.getName());}) + .orElse(null); + } + /** * Permanently deactivates the {@link Authorization}. */ 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 4c9a3c59..f609090c 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java @@ -76,6 +76,30 @@ public class AuthorizationTest { assertThat(c4, is(instanceOf(TlsAlpn01Challenge.class))); } + /** + * Test that {@link Authorization#findChallenge(Class)} finds challenges. + */ + @Test + public void testFindChallengeByType() throws IOException { + Authorization authorization = createChallengeAuthorization(); + + // A snail mail challenge is not available at all + NonExistingChallenge c1 = authorization.findChallenge(NonExistingChallenge.class); + assertThat(c1, is(nullValue())); + + // HttpChallenge is available + Http01Challenge c2 = authorization.findChallenge(Http01Challenge.class); + assertThat(c2, is(notNullValue())); + + // Dns01Challenge is available + Dns01Challenge c3 = authorization.findChallenge(Dns01Challenge.class); + assertThat(c3, is(notNullValue())); + + // TlsAlpn01Challenge is available + TlsAlpn01Challenge c4 = authorization.findChallenge(TlsAlpn01Challenge.class); + assertThat(c4, is(notNullValue())); + } + /** * Test that {@link Authorization#findChallenge(String)} fails on duplicate * challenges. @@ -329,4 +353,13 @@ public class AuthorizationTest { } } + /** + * Dummy challenge that is never going to be created. + */ + private static class NonExistingChallenge extends Challenge { + public NonExistingChallenge(Login login, JSON data) { + super(login, data); + } + } + } diff --git a/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java b/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java index 926d132e..2fc790f9 100644 --- a/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java +++ b/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java @@ -304,7 +304,7 @@ public class ClientTest { */ public Challenge httpChallenge(Authorization auth) throws AcmeException { // Find a single http-01 challenge - Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); + Http01Challenge challenge = auth.findChallenge(Http01Challenge.class); if (challenge == null) { throw new AcmeException("Found no " + Http01Challenge.TYPE + " challenge, don't know what to do..."); } diff --git a/src/site/markdown/usage/order.md b/src/site/markdown/usage/order.md index 4a2014d6..1ea8bcfe 100644 --- a/src/site/markdown/usage/order.md +++ b/src/site/markdown/usage/order.md @@ -33,10 +33,11 @@ The `Authorization` instance contains further details about how you can prove ow `getChallenges()` returns a collection of all `Challenge`s offered by the CA for domain ownership validation. You only need to complete _one_ of them to successfully authorize your domain. -The simplest way is to invoke `findChallenge()`, stating the challenge type your system is able to provide: +The simplest way is to invoke `findChallenge()`, stating the challenge type your system is able to provide (either as challenge name or challenge class type): ```java -Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); +Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); // by name +Http01Challenge challenge = auth.findChallenge(Http01Challenge.class); // by type ``` It returns a properly casted `Challenge` object, or `null` if your challenge type was not acceptable. In this example, your system is able to respond to a [http-01](../challenge/http-01.html) challenge.