From 9e4ba4fcb18973ea83eafa4d77d773e2dcb3e42a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Mon, 20 Aug 2018 23:09:41 +0200 Subject: [PATCH] Allow to pre-authorize and order Identifier objects --- .../java/org/shredzone/acme4j/Account.java | 27 +++++++++++++++-- .../main/java/org/shredzone/acme4j/Order.java | 19 ++++++++++-- .../org/shredzone/acme4j/OrderBuilder.java | 29 +++++++++++++++++-- .../org/shredzone/acme4j/IdentifierTest.java | 19 +++++++++++- .../shredzone/acme4j/OrderBuilderTest.java | 18 +++++++++++- .../resources/json/requestOrderRequest.json | 12 ++++++++ .../resources/json/requestOrderResponse.json | 12 ++++++++ 7 files changed, 128 insertions(+), 8 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java index 7e89c8f3..86ebb085 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java @@ -154,13 +154,36 @@ public class Account extends AcmeJsonResource { if (domain.isEmpty()) { throw new IllegalArgumentException("domain must not be empty"); } + return preAuthorize(Identifier.dns(domain)); + } + + /** + * Pre-authorizes an {@link Identifier}. The CA will check if it accepts the + * identifier for certification, and returns the necessary challenges. + *

+ * Some servers may not allow pre-authorization. + *

+ * It is not possible to pre-authorize wildcard domains. + * + * @param identifier + * {@link Identifier} to be pre-authorized. + * @return {@link Authorization} object for this identifier + * @throws AcmeException + * if the server does not allow pre-authorization + * @throws AcmeServerException + * if the server allows pre-authorization, but will refuse to issue a + * certificate for this identifier + * @since 2.3 + */ + public Authorization preAuthorize(Identifier identifier) throws AcmeException { + Objects.requireNonNull(identifier, "identifier"); URL newAuthzUrl = getSession().resourceUrl(Resource.NEW_AUTHZ); - LOG.debug("preAuthorizeDomain {}", domain); + LOG.debug("preAuthorize {}", identifier); try (Connection conn = connect()) { JSONBuilder claims = new JSONBuilder(); - claims.put("identifier", Identifier.dns(domain).toMap()); + claims.put("identifier", identifier.toMap()); conn.sendSignedRequest(newAuthzUrl, claims, getLogin()); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java index de0e4005..e82d348c 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java @@ -70,13 +70,28 @@ public class Order extends AcmeJsonResource { /** * Gets the list of domain names to be ordered. + * + * @deprecated Use {@link #getIdentifiers()}. This method only returns DNS type + * identifiers for compatibility reasons. */ + @Deprecated public List getDomains() { + return getIdentifiers().stream() + .filter(i -> Identifier.DNS.equals(i.getType())) + .map(Identifier::getDomain) + .collect(toList()); + } + + /** + * Gets the list of {@link Identifier} to be ordered. + * + * @since 2.3 + */ + public List getIdentifiers() { return Collections.unmodifiableList(getJSON().get("identifiers") .asArray() .stream() - .map(Value::asObject) - .map(it -> it.get("value").asString()) + .map(Value::asIdentifier) .collect(toList())); } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java index d7b46eca..8bd40f61 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java @@ -65,8 +65,7 @@ public class OrderBuilder { * @return itself */ public OrderBuilder domain(String domain) { - identifierSet.add(Identifier.dns(domain)); - return this; + return identifier(Identifier.dns(domain)); } /** @@ -99,6 +98,32 @@ public class OrderBuilder { return this; } + /** + * Adds an {@link Identifier} to the order. + * + * @param identifier + * {@link Identifier} to be added to the order. + * @return itself + * @since 2.3 + */ + public OrderBuilder identifier(Identifier identifier) { + identifierSet.add(requireNonNull(identifier, "identifier")); + return this; + } + + /** + * Adds a collection of {@link Identifier} to the order. + * + * @param identifiers + * Collection of {@link Identifier} to be added to the order. + * @return itself + * @since 2.3 + */ + public OrderBuilder identifiers(Collection identifiers) { + requireNonNull(identifiers, "identifiers").forEach(this::identifier); + return this; + } + /** * Sets a "not before" date in the certificate. May be ignored by the CA. * diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/IdentifierTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/IdentifierTest.java index 753eb538..4a560ac5 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/IdentifierTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/IdentifierTest.java @@ -14,7 +14,7 @@ package org.shredzone.acme4j; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import java.util.Map; @@ -94,4 +94,21 @@ public class IdentifierTest { assertThat(idRef.equals(null), is(false)); } + @Test + public void testNull() { + try { + new Identifier(null, "123.456"); + fail("accepted null"); + } catch (NullPointerException ex) { + // expected + } + + try { + new Identifier("foo", null); + fail("accepted null"); + } catch (NullPointerException ex) { + // expected + } + } + } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java index 40938beb..d3758eb7 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderBuilderTest.java @@ -43,6 +43,7 @@ public class OrderBuilderTest { * Test that a new {@link Order} can be created. */ @Test + @SuppressWarnings("deprecation") public void testOrderCertificate() throws Exception { Instant notBefore = parseTimestamp("2016-01-01T00:00:00Z"); Instant notAfter = parseTimestamp("2016-01-08T00:00:00Z"); @@ -76,6 +77,10 @@ public class OrderBuilderTest { .domains("example.com", "www.example.com") .domain("example.org") .domains(Arrays.asList("m.example.com", "m.example.org")) + .identifier(Identifier.dns("d.example.com")) + .identifiers(Arrays.asList( + Identifier.dns("d2.example.com"), + new Identifier("ip", "192.168.1.2"))) .notBefore(notBefore) .notAfter(notAfter) .create(); @@ -83,7 +88,18 @@ public class OrderBuilderTest { assertThat(order.getDomains(), containsInAnyOrder( "example.com", "www.example.com", "example.org", - "m.example.com", "m.example.org")); + "m.example.com", "m.example.org", + "d.example.com", + "d2.example.com")); + assertThat(order.getIdentifiers(), containsInAnyOrder( + Identifier.dns("example.com"), + Identifier.dns("www.example.com"), + Identifier.dns("example.org"), + Identifier.dns("m.example.com"), + Identifier.dns("m.example.org"), + Identifier.dns("d.example.com"), + Identifier.dns("d2.example.com"), + new Identifier("ip", "192.168.1.2"))); assertThat(order.getNotBefore(), is(parseTimestamp("2016-01-01T00:10:00Z"))); assertThat(order.getNotAfter(), is(parseTimestamp("2016-01-08T00:10:00Z"))); assertThat(order.getExpires(), is(parseTimestamp("2016-01-10T00:00:00Z"))); diff --git a/acme4j-client/src/test/resources/json/requestOrderRequest.json b/acme4j-client/src/test/resources/json/requestOrderRequest.json index c29a2195..ab9a2993 100644 --- a/acme4j-client/src/test/resources/json/requestOrderRequest.json +++ b/acme4j-client/src/test/resources/json/requestOrderRequest.json @@ -19,6 +19,18 @@ { "type": "dns", "value": "m.example.org" + }, + { + "type": "dns", + "value": "d.example.com" + }, + { + "type": "dns", + "value": "d2.example.com" + }, + { + "type": "ip", + "value": "192.168.1.2" } ], "notBefore": "2016-01-01T00:00:00Z", diff --git a/acme4j-client/src/test/resources/json/requestOrderResponse.json b/acme4j-client/src/test/resources/json/requestOrderResponse.json index 09f642a2..07e0f2a8 100644 --- a/acme4j-client/src/test/resources/json/requestOrderResponse.json +++ b/acme4j-client/src/test/resources/json/requestOrderResponse.json @@ -21,6 +21,18 @@ { "type": "dns", "value": "m.example.org" + }, + { + "type": "dns", + "value": "d.example.com" + }, + { + "type": "dns", + "value": "d2.example.com" + }, + { + "type": "ip", + "value": "192.168.1.2" } ], "notBefore": "2016-01-01T00:10:00Z",