diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java index 4a684441..ce130ad7 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java @@ -176,17 +176,14 @@ public class Session { public Challenge createChallenge(JSON data) { Objects.requireNonNull(data, "data"); - String type = data.get("type").required().asString(); - - Challenge challenge = provider().createChallenge(this, type); + Challenge challenge = provider().createChallenge(this, data); if (challenge == null) { if (data.contains("token")) { - challenge = new TokenChallenge(this); + challenge = new TokenChallenge(this, data); } else { - challenge = new Challenge(this); + challenge = new Challenge(this, data); } } - challenge.setJSON(data); return challenge; } 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 2c4f80d8..d2285b67 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 @@ -58,9 +58,11 @@ public class Challenge extends AcmeJsonResource { * * @param session * {@link Session} to bind to. + * @param data + * {@link JSON} challenge data */ - public Challenge(Session session) { - super(session); + public Challenge(Session session, JSON data) { + super(session, data); } /** @@ -159,16 +161,14 @@ public class Challenge extends AcmeJsonResource { } @Override - public void setJSON(JSON json) { - String type = json.get(KEY_TYPE).asString(); - if (type == null) { - throw new IllegalArgumentException("map does not contain a type"); - } + protected void setJSON(JSON json) { + String type = json.get(KEY_TYPE).required().asString(); + if (!acceptable(type)) { - throw new AcmeProtocolException("wrong type: " + type); + throw new AcmeProtocolException("incompatible type " + type + " for this challenge"); } - setLocation(json.get(KEY_URL).asURL()); + setLocation(json.get(KEY_URL).required().asURL()); super.setJSON(json); } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java index 1925b6ea..23caab74 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java @@ -16,6 +16,7 @@ package org.shredzone.acme4j.challenge; import static org.shredzone.acme4j.toolbox.AcmeUtils.*; import org.shredzone.acme4j.Session; +import org.shredzone.acme4j.toolbox.JSON; /** * Implements the {@value TYPE} challenge. @@ -33,9 +34,11 @@ public class Dns01Challenge extends TokenChallenge { * * @param session * {@link Session} to bind to. + * @param data + * {@link JSON} challenge data */ - public Dns01Challenge(Session session) { - super(session); + public Dns01Challenge(Session session, JSON data) { + super(session, data); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java index deec912d..4ec28324 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java @@ -14,6 +14,7 @@ package org.shredzone.acme4j.challenge; import org.shredzone.acme4j.Session; +import org.shredzone.acme4j.toolbox.JSON; /** * Implements the {@value TYPE} challenge. @@ -31,9 +32,11 @@ public class Http01Challenge extends TokenChallenge { * * @param session * {@link Session} to bind to. + * @param data + * {@link JSON} challenge data */ - public Http01Challenge(Session session) { - super(session); + public Http01Challenge(Session session, JSON data) { + super(session, data); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSni02Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSni02Challenge.java index 66c4513e..0bf4690a 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSni02Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsSni02Challenge.java @@ -16,6 +16,7 @@ package org.shredzone.acme4j.challenge; import static org.shredzone.acme4j.toolbox.AcmeUtils.*; import org.shredzone.acme4j.Session; +import org.shredzone.acme4j.toolbox.JSON; /** * Implements the {@value TYPE} challenge. @@ -33,9 +34,11 @@ public class TlsSni02Challenge extends TokenChallenge { * * @param session * {@link Session} to bind to. + * @param data + * {@link JSON} challenge data */ - public TlsSni02Challenge(Session session) { - super(session); + public TlsSni02Challenge(Session session, JSON data) { + super(session, data); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java index e406756d..2b8641bc 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java @@ -21,6 +21,7 @@ import org.jose4j.jwk.PublicJsonWebKey; import org.jose4j.lang.JoseException; import org.shredzone.acme4j.Session; import org.shredzone.acme4j.exception.AcmeProtocolException; +import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSONBuilder; /** @@ -38,9 +39,11 @@ public class TokenChallenge extends Challenge { * * @param session * {@link Session} to bind to. + * @param data + * {@link JSON} challenge data */ - public TokenChallenge(Session session) { - super(session); + public TokenChallenge(Session session, JSON data) { + super(session, data); } @Override 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 66bdd3c6..7ebb5be0 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 @@ -18,7 +18,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.function.Function; +import java.util.function.BiFunction; import org.shredzone.acme4j.Session; import org.shredzone.acme4j.challenge.Challenge; @@ -40,7 +40,7 @@ import org.shredzone.acme4j.toolbox.JSON; */ public abstract class AbstractAcmeProvider implements AcmeProvider { - private static final Map> CHALLENGES = challengeMap(); + private static final Map> CHALLENGES = challengeMap(); @Override public Connection connect() { @@ -59,8 +59,8 @@ public abstract class AbstractAcmeProvider implements AcmeProvider { } } - private static Map> challengeMap() { - Map> map = new HashMap<>(); + private static Map> challengeMap() { + Map> map = new HashMap<>(); map.put(Dns01Challenge.TYPE, Dns01Challenge::new); map.put(TlsSni02Challenge.TYPE, TlsSni02Challenge::new); @@ -69,17 +69,25 @@ public abstract class AbstractAcmeProvider implements AcmeProvider { return Collections.unmodifiableMap(map); } + /** + * {@inheritDoc} + *

+ * Custom provider implementations may override this method to provide challenges that + * are unique to the provider. + */ @Override - public Challenge createChallenge(Session session, String type) { + public Challenge createChallenge(Session session, JSON data) { Objects.requireNonNull(session, "session"); - Objects.requireNonNull(type, "type"); + Objects.requireNonNull(data, "data"); - Function constructor = CHALLENGES.get(type); + String type = data.get("type").required().asString(); + + BiFunction constructor = CHALLENGES.get(type); if (constructor == null) { return null; } - return constructor.apply(session); + return constructor.apply(session, data); } /** diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AcmeProvider.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AcmeProvider.java index e4c3f640..7a477ae8 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AcmeProvider.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AcmeProvider.java @@ -75,17 +75,15 @@ public interface AcmeProvider { JSON directory(Session session, URI serverUri) throws AcmeException; /** - * Creates a {@link Challenge} instance for the given challenge type. - *

- * Custom provider implementations may override this method to provide challenges that - * are unique to the provider. + * Creates a {@link Challenge} instance for the given challenge data. * * @param session * {@link Session} to bind the challenge to - * @param type - * Challenge type - * @return {@link Challenge} instance + * @param data + * Challenge {@link JSON} data + * @return {@link Challenge} instance, or {@code null} if this provider is unable to + * generate a matching {@link Challenge} instance. */ - Challenge createChallenge(Session session, String type); + Challenge createChallenge(Session session, JSON data); } 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 37ded4e5..f8f384ce 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java @@ -35,7 +35,6 @@ import org.jose4j.jwx.CompactSerializer; import org.jose4j.lang.JoseException; import org.junit.Test; import org.shredzone.acme4j.Account.EditableAccount; -import org.shredzone.acme4j.challenge.Challenge; import org.shredzone.acme4j.challenge.Dns01Challenge; import org.shredzone.acme4j.challenge.Http01Challenge; import org.shredzone.acme4j.connector.Resource; @@ -196,12 +195,9 @@ public class AccountTest { Session session = provider.createSession(); - Http01Challenge httpChallenge = new Http01Challenge(session); - Dns01Challenge dnsChallenge = new Dns01Challenge(session); - provider.putTestResource(Resource.NEW_AUTHZ, resourceUrl); - provider.putTestChallenge(Http01Challenge.TYPE, httpChallenge); - provider.putTestChallenge(Dns01Challenge.TYPE, dnsChallenge); + provider.putTestChallenge(Http01Challenge.TYPE, Http01Challenge::new); + provider.putTestChallenge(Dns01Challenge.TYPE, Dns01Challenge::new); String domainName = "example.org"; @@ -214,7 +210,8 @@ public class AccountTest { assertThat(auth.getLocation(), is(locationUrl)); assertThat(auth.getChallenges(), containsInAnyOrder( - (Challenge) httpChallenge, (Challenge) dnsChallenge)); + provider.getChallenge(Http01Challenge.TYPE), + provider.getChallenge(Dns01Challenge.TYPE))); provider.close(); } 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 45c69967..99132dac 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java @@ -108,10 +108,8 @@ public class AuthorizationTest { Session session = provider.createSession(); - Http01Challenge httpChallenge = new Http01Challenge(session); - Dns01Challenge dnsChallenge = new Dns01Challenge(session); - provider.putTestChallenge("http-01", httpChallenge); - provider.putTestChallenge("dns-01", dnsChallenge); + provider.putTestChallenge("http-01", Http01Challenge::new); + provider.putTestChallenge("dns-01", Dns01Challenge::new); Authorization auth = new Authorization(session, locationUrl); auth.update(); @@ -122,7 +120,8 @@ public class AuthorizationTest { assertThat(auth.getLocation(), is(locationUrl)); assertThat(auth.getChallenges(), containsInAnyOrder( - (Challenge) httpChallenge, (Challenge) dnsChallenge)); + provider.getChallenge(Http01Challenge.TYPE), + provider.getChallenge(Dns01Challenge.TYPE))); provider.close(); } @@ -154,8 +153,8 @@ public class AuthorizationTest { Session session = provider.createSession(); - provider.putTestChallenge("http-01", new Http01Challenge(session)); - provider.putTestChallenge("dns-01", new Dns01Challenge(session)); + provider.putTestChallenge("http-01", Http01Challenge::new); + provider.putTestChallenge("dns-01", Dns01Challenge::new); Authorization auth = new Authorization(session, locationUrl); @@ -200,10 +199,8 @@ public class AuthorizationTest { Session session = provider.createSession(); - Http01Challenge httpChallenge = new Http01Challenge(session); - Dns01Challenge dnsChallenge = new Dns01Challenge(session); - provider.putTestChallenge("http-01", httpChallenge); - provider.putTestChallenge("dns-01", dnsChallenge); + provider.putTestChallenge("http-01", Http01Challenge::new); + provider.putTestChallenge("dns-01", Dns01Challenge::new); Authorization auth = new Authorization(session, locationUrl); @@ -220,7 +217,8 @@ public class AuthorizationTest { assertThat(auth.getLocation(), is(locationUrl)); assertThat(auth.getChallenges(), containsInAnyOrder( - (Challenge) httpChallenge, (Challenge) dnsChallenge)); + provider.getChallenge(Http01Challenge.TYPE), + provider.getChallenge(Dns01Challenge.TYPE))); provider.close(); } @@ -249,10 +247,8 @@ public class AuthorizationTest { Session session = provider.createSession(); - Http01Challenge httpChallenge = new Http01Challenge(session); - Dns01Challenge dnsChallenge = new Dns01Challenge(session); - provider.putTestChallenge("http-01", httpChallenge); - provider.putTestChallenge("dns-01", dnsChallenge); + provider.putTestChallenge("http-01", Http01Challenge::new); + provider.putTestChallenge("dns-01", Dns01Challenge::new); Authorization auth = new Authorization(session, locationUrl); auth.deactivate(); @@ -267,10 +263,10 @@ public class AuthorizationTest { try (TestableConnectionProvider provider = new TestableConnectionProvider()) { Session session = provider.createSession(); - provider.putTestChallenge(Http01Challenge.TYPE, new Http01Challenge(session)); - provider.putTestChallenge(Dns01Challenge.TYPE, new Dns01Challenge(session)); - provider.putTestChallenge(TlsSni02Challenge.TYPE, new TlsSni02Challenge(session)); - provider.putTestChallenge(DUPLICATE_TYPE, new Challenge(session)); + provider.putTestChallenge(Http01Challenge.TYPE, Http01Challenge::new); + provider.putTestChallenge(Dns01Challenge.TYPE, Dns01Challenge::new); + provider.putTestChallenge(TlsSni02Challenge.TYPE, TlsSni02Challenge::new); + provider.putTestChallenge(DUPLICATE_TYPE, Challenge::new); Authorization authorization = new Authorization(session, locationUrl); authorization.setJSON(getJSON("authorizationChallenges")); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java index 8531affe..eb16b44f 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java @@ -125,9 +125,11 @@ public class SessionTest { KeyPair keyPair = TestUtils.createKeyPair(); URI serverUri = URI.create(TestUtils.ACME_SERVER_URI); String challengeType = Http01Challenge.TYPE; + URL challengeUrl = new URL("https://example.com/acme/authz/0"); JSON data = new JSONBuilder() .put("type", challengeType) + .put("url", challengeUrl) .toJSON(); Http01Challenge mockChallenge = mock(Http01Challenge.class); @@ -135,7 +137,7 @@ public class SessionTest { when(mockProvider.createChallenge( ArgumentMatchers.any(Session.class), - ArgumentMatchers.eq(challengeType))) + ArgumentMatchers.eq(data))) .thenReturn(mockChallenge); Session session = new Session(serverUri, keyPair) { @@ -149,7 +151,7 @@ public class SessionTest { assertThat(challenge, is(instanceOf(Http01Challenge.class))); assertThat(challenge, is(sameInstance((Challenge) mockChallenge))); - verify(mockProvider).createChallenge(session, challengeType); + verify(mockProvider).createChallenge(session, data); } /** 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 6f7222e6..f8c0ea5b 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 @@ -47,7 +47,6 @@ import org.shredzone.acme4j.toolbox.TestUtils; */ public class ChallengeTest { private Session session; - private URL resourceUrl = url("https://example.com/acme/some-resource"); private URL locationUrl = url("https://example.com/acme/some-location"); @Before @@ -74,7 +73,7 @@ public class ChallengeTest { Session session = provider.createSession(); - provider.putTestChallenge(Http01Challenge.TYPE, new Http01Challenge(session)); + provider.putTestChallenge(Http01Challenge.TYPE, Http01Challenge::new); Http01Challenge challenge = Challenge.bind(session, locationUrl); @@ -91,8 +90,7 @@ public class ChallengeTest { */ @Test public void testUnmarshal() throws URISyntaxException { - Challenge challenge = new Challenge(session); - challenge.setJSON(getJSON("genericChallenge")); + Challenge challenge = new Challenge(session, getJSON("genericChallenge")); // Test unmarshalled values assertThat(challenge.getType(), is("generic-01")); @@ -126,8 +124,7 @@ public class ChallengeTest { */ @Test public void testRespond() throws JoseException { - Challenge challenge = new Challenge(session); - challenge.setJSON(getJSON("genericChallenge")); + Challenge challenge = new Challenge(session, getJSON("genericChallenge")); JSONBuilder cb = new JSONBuilder(); challenge.respond(cb); @@ -140,8 +137,7 @@ public class ChallengeTest { */ @Test(expected = AcmeProtocolException.class) public void testNotAcceptable() throws URISyntaxException { - Http01Challenge challenge = new Http01Challenge(session); - challenge.setJSON(getJSON("dnsChallenge")); + new Http01Challenge(session, getJSON("dnsChallenge")); } /** @@ -152,7 +148,7 @@ public class ChallengeTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override public int sendSignedRequest(URL url, JSONBuilder claims, Session session, int... httpStatus) { - assertThat(url, is(resourceUrl)); + assertThat(url, is(locationUrl)); assertThat(claims.toString(), sameJSONAs(getJSON("triggerHttpChallengeRequest").toString())); assertThat(session, is(notNullValue())); assertThat(httpStatus, isIntArrayContainingInAnyOrder()); @@ -167,8 +163,7 @@ public class ChallengeTest { Session session = provider.createSession(); - Http01Challenge challenge = new Http01Challenge(session); - challenge.setJSON(getJSON("triggerHttpChallenge")); + Http01Challenge challenge = new Http01Challenge(session, getJSON("triggerHttpChallenge")); challenge.trigger(); @@ -202,8 +197,7 @@ public class ChallengeTest { Session session = provider.createSession(); - Challenge challenge = new Http01Challenge(session); - challenge.setJSON(getJSON("triggerHttpChallengeResponse")); + Challenge challenge = new Http01Challenge(session, getJSON("triggerHttpChallengeResponse")); challenge.update(); @@ -240,8 +234,7 @@ public class ChallengeTest { Session session = provider.createSession(); - Challenge challenge = new Http01Challenge(session); - challenge.setJSON(getJSON("triggerHttpChallengeResponse")); + Challenge challenge = new Http01Challenge(session, getJSON("triggerHttpChallengeResponse")); try { challenge.update(); @@ -302,10 +295,9 @@ public class ChallengeTest { /** * Test that unmarshalling something different like a challenge fails. */ - @Test(expected = IllegalArgumentException.class) + @Test(expected = AcmeProtocolException.class) public void testBadUnmarshall() { - Challenge challenge = new Challenge(session); - challenge.setJSON(getJSON("updateAccountResponse")); + new Challenge(session, getJSON("updateAccountResponse")); } } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/DnsChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/DnsChallengeTest.java index 3b2d273f..b75b8e10 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/DnsChallengeTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/DnsChallengeTest.java @@ -46,8 +46,7 @@ public class DnsChallengeTest { */ @Test public void testDnsChallenge() throws IOException { - Dns01Challenge challenge = new Dns01Challenge(session); - challenge.setJSON(getJSON("dnsChallenge")); + Dns01Challenge challenge = new Dns01Challenge(session, getJSON("dnsChallenge")); assertThat(challenge.getType(), is(Dns01Challenge.TYPE)); assertThat(challenge.getStatus(), is(Status.PENDING)); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/HttpChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/HttpChallengeTest.java index 0e4695c6..3b784e39 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/HttpChallengeTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/HttpChallengeTest.java @@ -49,8 +49,7 @@ public class HttpChallengeTest { */ @Test public void testHttpChallenge() throws IOException { - Http01Challenge challenge = new Http01Challenge(session); - challenge.setJSON(getJSON("httpChallenge")); + Http01Challenge challenge = new Http01Challenge(session, getJSON("httpChallenge")); assertThat(challenge.getType(), is(Http01Challenge.TYPE)); assertThat(challenge.getStatus(), is(Status.PENDING)); @@ -69,8 +68,7 @@ public class HttpChallengeTest { */ @Test(expected = AcmeProtocolException.class) public void testNoTokenSet() { - Http01Challenge challenge = new Http01Challenge(session); - challenge.setJSON(getJSON("httpNoTokenChallenge")); + Http01Challenge challenge = new Http01Challenge(session, getJSON("httpNoTokenChallenge")); challenge.getToken(); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/TlsSni02ChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/TlsSni02ChallengeTest.java index 1937b2e8..490775c4 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/TlsSni02ChallengeTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/TlsSni02ChallengeTest.java @@ -46,8 +46,7 @@ public class TlsSni02ChallengeTest { */ @Test public void testTlsSni02Challenge() throws IOException { - TlsSni02Challenge challenge = new TlsSni02Challenge(session); - challenge.setJSON(getJSON("tlsSni02Challenge")); + TlsSni02Challenge challenge = new TlsSni02Challenge(session, getJSON("tlsSni02Challenge")); assertThat(challenge.getType(), is(TlsSni02Challenge.TYPE)); assertThat(challenge.getStatus(), is(Status.PENDING)); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/SessionProviderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/SessionProviderTest.java index 0c6e8004..b0f160a9 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/SessionProviderTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/SessionProviderTest.java @@ -103,7 +103,7 @@ public class SessionProviderTest { } @Override - public Challenge createChallenge(Session session, String type) { + public Challenge createChallenge(Session session, JSON data) { throw new UnsupportedOperationException(); } } @@ -131,7 +131,7 @@ public class SessionProviderTest { } @Override - public Challenge createChallenge(Session session, String type) { + public Challenge createChallenge(Session session, JSON data) { throw new UnsupportedOperationException(); } } 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 4f9ef8c4..125ccdff 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 @@ -34,7 +34,9 @@ import org.shredzone.acme4j.connector.Connection; import org.shredzone.acme4j.connector.DefaultConnection; import org.shredzone.acme4j.connector.HttpConnector; import org.shredzone.acme4j.exception.AcmeException; +import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.toolbox.JSON; +import org.shredzone.acme4j.toolbox.JSONBuilder; import org.shredzone.acme4j.toolbox.TestUtils; /** @@ -133,29 +135,40 @@ public class AbstractAcmeProviderTest { } }; - Challenge c1 = provider.createChallenge(session, Http01Challenge.TYPE); + Challenge c1 = provider.createChallenge(session, getJSON("httpChallenge")); assertThat(c1, not(nullValue())); assertThat(c1, instanceOf(Http01Challenge.class)); - Challenge c2 = provider.createChallenge(session, Http01Challenge.TYPE); + Challenge c2 = provider.createChallenge(session, getJSON("httpChallenge")); assertThat(c2, not(sameInstance(c1))); - Challenge c3 = provider.createChallenge(session, Dns01Challenge.TYPE); + Challenge c3 = provider.createChallenge(session, getJSON("dnsChallenge")); assertThat(c3, not(nullValue())); assertThat(c3, instanceOf(Dns01Challenge.class)); - Challenge c5 = provider.createChallenge(session, TlsSni02Challenge.TYPE); + Challenge c5 = provider.createChallenge(session, getJSON("tlsSni02Challenge")); assertThat(c5, not(nullValue())); assertThat(c5, instanceOf(TlsSni02Challenge.class)); - Challenge c6 = provider.createChallenge(session, "foobar-01"); + JSON json6 = new JSONBuilder() + .put("type", "foobar-01") + .put("url", "https://example.com/some/challenge") + .toJSON(); + Challenge c6 = provider.createChallenge(session, json6); assertThat(c6, is(nullValue())); - Challenge c7 = provider.createChallenge(session, ""); - assertThat(c7, is(nullValue())); + try { + JSON json7 = new JSONBuilder() + .put("url", "https://example.com/some/challenge") + .toJSON(); + provider.createChallenge(session, json7); + fail("Challenge without type was accepted"); + } catch (AcmeProtocolException ex) { + // expected + } try { - provider.createChallenge(session, (String) null); + provider.createChallenge(session, null); fail("null was accepted"); } catch (NullPointerException ex) { // expected diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/provider/TestableConnectionProvider.java b/acme4j-client/src/test/java/org/shredzone/acme4j/provider/TestableConnectionProvider.java index b80f2117..e2539da2 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/provider/TestableConnectionProvider.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/provider/TestableConnectionProvider.java @@ -18,6 +18,7 @@ import java.net.URI; import java.net.URL; import java.util.HashMap; import java.util.Map; +import java.util.function.BiFunction; import org.shredzone.acme4j.Session; import org.shredzone.acme4j.challenge.Challenge; @@ -34,7 +35,8 @@ import org.shredzone.acme4j.toolbox.TestUtils; * of {@link Connection} that is always returned on {@link #connect()}. */ public class TestableConnectionProvider extends DummyConnection implements AcmeProvider { - private final Map challengeMap = new HashMap<>(); + private final Map> creatorMap = new HashMap<>(); + private final Map createdMap = new HashMap<>(); private final JSONBuilder directory = new JSONBuilder(); /** @@ -50,17 +52,29 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP } /** - * Register a {@link Challenge}. For the sake of simplicity, - * {@link #createChallenge(Session, String)} will always return the same - * {@link Challenge} instance in this test suite. + * Register a {@link Challenge}. * - * @param s - * Challenge type - * @param c - * {@link Challenge} instance. + * @param type + * Challenge type to register. + * @param creator + * Creator {@link BiFunction} that creates a matching {@link Challenge} */ - public void putTestChallenge(String s, Challenge c) { - challengeMap.put(s, c); + public void putTestChallenge(String type, BiFunction creator) { + creatorMap.put(type, creator); + } + + /** + * Returns the {@link Challenge} instance that has been created. Fails if no such + * challenge was created. + * + * @param type Challenge type + * @return Created {@link Challenge} instance + */ + public Challenge getChallenge(String type) { + if (!createdMap.containsKey(type)) { + throw new IllegalArgumentException("No challenge of type " + type + " was created"); + } + return createdMap.get(type); } /** @@ -94,16 +108,23 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP } @Override - public Challenge createChallenge(Session session, String type) { - if (challengeMap.isEmpty()) { + public Challenge createChallenge(Session session, JSON data) { + if (creatorMap.isEmpty()) { throw new UnsupportedOperationException(); } - if (challengeMap.containsKey(type)) { - return challengeMap.get(type); + Challenge created; + + String type = data.get("type").asString(); + if (creatorMap.containsKey(type)) { + created = creatorMap.get(type).apply(session, data); } else { - return new Challenge(session); + created = new Challenge(session, data); } + + createdMap.put(type, created); + + return created; } } diff --git a/acme4j-client/src/test/resources/json/triggerHttpChallenge.json b/acme4j-client/src/test/resources/json/triggerHttpChallenge.json index d67d346a..42ce743d 100644 --- a/acme4j-client/src/test/resources/json/triggerHttpChallenge.json +++ b/acme4j-client/src/test/resources/json/triggerHttpChallenge.json @@ -1,6 +1,6 @@ { "type": "http-01", "status": "pending", - "url": "https://example.com/acme/some-resource", + "url": "https://example.com/acme/some-location", "token": "IlirfxKKXAsHtmzK29Pj8A" } diff --git a/src/site/markdown/development/provider.md b/src/site/markdown/development/provider.md index caa1296f..583ec31f 100644 --- a/src/site/markdown/development/provider.md +++ b/src/site/markdown/development/provider.md @@ -37,7 +37,7 @@ The standard Java mechanisms are used to verify the HTTPS certificate provided b If your ACME server provides challenges that are not specified in the ACME protocol, there should be an own `Challenge` implementation for each of your challenge, by extending the [`Challenge`](../apidocs/org/shredzone/acme4j/challenge/Challenge.html) class. -In your `AcmeProvider` implementation, override the `createChallenge(Session, String)` method so it returns a new instance of your `Challenge` implementation when your individual challenge type is requested. All other types should be delegated to the super method. +In your `AcmeProvider` implementation, override the `createChallenge(Session, JSON)` method so it returns a new instance of your `Challenge` implementation when your individual challenge type is requested. All other types should be delegated to the super method. ## Amended Directory Service