Support acme-star-09 draft, change API and documentation

pull/89/head
Richard Körber 2020-01-23 23:26:48 +01:00
parent f1e3048dd2
commit 9d62cb6a55
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
16 changed files with 252 additions and 204 deletions

View File

@ -19,6 +19,7 @@ import java.net.URI;
import java.net.URL;
import java.time.Duration;
import java.util.Collection;
import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.ParametersAreNonnullByDefault;
@ -88,8 +89,8 @@ public class Metadata {
*
* @since 2.3
*/
public boolean isStarEnabled() {
return meta.get("star-enabled").map(Value::asBoolean).orElse(false);
public boolean isAutoRenewalEnabled() {
return meta.get("auto-renewal").isPresent();
}
/**
@ -99,18 +100,26 @@ public class Metadata {
*
* @since 2.3
*/
public Duration getStarMinCertValidity() {
return meta.get("star-min-cert-validity").map(Value::asDuration).orElse(null);
public Duration getAutoRenewalMinLifetime() {
Optional<JSON> ar = meta.get("auto-renewal").optional().map(Value::asObject);
if (!ar.isPresent()) {
return null;
}
return ar.get().get("min-lifetime").map(Value::asDuration).orElse(null);
}
/**
* Returns the maximum delta between recurrent end date and recurrent start date.
* {@code null} if the CA does not support short-term auto renewal.
* Returns the maximum delta between auto-renewal end date and auto-renewal start
* date. {@code null} if the CA does not support short-term auto renewal.
*
* @since 2.3
*/
public Duration getStarMaxRenewal() {
return meta.get("star-max-renewal").map(Value::asDuration).orElse(null);
public Duration getAutoRenewalMaxDuration() {
Optional<JSON> ar = meta.get("auto-renewal").optional().map(Value::asObject);
if (!ar.isPresent()) {
return null;
}
return ar.get().get("max-duration").map(Value::asDuration).orElse(null);
}
/**
@ -118,8 +127,12 @@ public class Metadata {
*
* @since 2.6
*/
public boolean isStarCertificateGetAllowed() {
return meta.get("star-allow-certificate-get").map(Value::asBoolean).orElse(false);
public boolean isAutoRenewalGetAllowed() {
Optional<JSON> ar = meta.get("auto-renewal").optional().map(Value::asObject);
if (!ar.isPresent()) {
return false;
}
return ar.get().get("allow-certificate-get").map(Value::asBoolean).orElse(false);
}
/**

View File

@ -26,6 +26,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSON.Value;
import org.shredzone.acme4j.toolbox.JSONBuilder;
import org.slf4j.Logger;
@ -138,7 +139,7 @@ public class Order extends AcmeJsonResource {
* @since 2.6
*/
@CheckForNull
public Certificate getStarCertificate() {
public Certificate getAutoRenewalCertificate() {
return getJSON().get("star-certificate")
.map(Value::asURL)
.map(getLogin()::bindCertificate)
@ -171,15 +172,14 @@ public class Order extends AcmeJsonResource {
}
/**
* Checks if this order is recurrent, according to the ACME STAR specifications.
* Checks if this order is auto-renewing, according to the ACME STAR specifications.
*
* @since 2.3
*/
public boolean isRecurrent() {
return getJSON().get("recurrent")
public boolean isAutoRenewing() {
return getJSON().get("auto-renewal")
.optional()
.map(Value::asBoolean)
.orElse(false);
.isPresent();
}
/**
@ -189,8 +189,12 @@ public class Order extends AcmeJsonResource {
* @since 2.3
*/
@CheckForNull
public Instant getRecurrentStart() {
return getJSON().get("recurrent-start-date")
public Instant getAutoRenewalStartDate() {
return getJSON().get("auto-renewal")
.optional()
.map(Value::asObject)
.orElseGet(JSON::empty)
.get("start-date")
.optional()
.map(Value::asInstant)
.orElse(null);
@ -203,21 +207,29 @@ public class Order extends AcmeJsonResource {
* @since 2.3
*/
@CheckForNull
public Instant getRecurrentEnd() {
return getJSON().get("recurrent-end-date")
public Instant getAutoRenewalEndDate() {
return getJSON().get("auto-renewal")
.optional()
.map(Value::asObject)
.orElseGet(JSON::empty)
.get("end-date")
.optional()
.map(Value::asInstant)
.orElse(null);
}
/**
* Returns the maximum validity period of each certificate, or {@code null}.
* Returns the maximum lifetime of each certificate, or {@code null}.
*
* @since 2.3
*/
@CheckForNull
public Duration getRecurrentCertificateValidity() {
return getJSON().get("recurrent-certificate-validity")
public Duration getAutoRenewalLifetime() {
return getJSON().get("auto-renewal")
.optional()
.map(Value::asObject)
.orElseGet(JSON::empty)
.get("lifetime")
.optional()
.map(Value::asDuration)
.orElse(null);
@ -229,11 +241,15 @@ public class Order extends AcmeJsonResource {
* @since 2.7
*/
@CheckForNull
public Duration getRecurrentCertificatePredate() {
return getJSON().get("recurrent-certificate-predate")
.optional()
.map(Value::asDuration)
.orElse(null);
public Duration getAutoRenewalLifetimeAdjust() {
return getJSON().get("auto-renewal")
.optional()
.map(Value::asObject)
.orElseGet(JSON::empty)
.get("lifetime-adjust")
.optional()
.map(Value::asDuration)
.orElse(null);
}
/**
@ -242,20 +258,24 @@ public class Order extends AcmeJsonResource {
*
* @since 2.6
*/
public boolean isRecurrentGetEnabled() {
return getJSON().get("recurrent-certificate-get")
public boolean isAutoRenewalGetEnabled() {
return getJSON().get("auto-renewal")
.optional()
.map(Value::asObject)
.orElseGet(JSON::empty)
.get("allow-certificate-get")
.optional()
.map(Value::asBoolean)
.orElse(false);
}
/**
* Cancels a recurrent order.
* Cancels an auto-renewing order.
*
* @since 2.3
*/
public void cancelRecurrent() throws AcmeException {
if (!getSession().getMetadata().isStarEnabled()) {
public void cancelAutoRenewal() throws AcmeException {
if (!getSession().getMetadata().isAutoRenewalEnabled()) {
throw new AcmeException("CA does not support short-term automatic renewals");
}

View File

@ -45,12 +45,12 @@ public class OrderBuilder {
private final Set<Identifier> identifierSet = new LinkedHashSet<>();
private Instant notBefore;
private Instant notAfter;
private boolean recurrent;
private Instant recurrentStart;
private Instant recurrentEnd;
private Duration recurrentValidity;
private Duration recurrentPredate;
private boolean recurrentGet;
private boolean autoRenewal;
private Instant autoRenewalStart;
private Instant autoRenewalEnd;
private Duration autoRenewalLifetime;
private Duration autoRenewalLifetimeAdjust;
private boolean autoRenewalGet;
/**
* Create a new {@link OrderBuilder}.
@ -137,8 +137,8 @@ public class OrderBuilder {
* @return itself
*/
public OrderBuilder notBefore(Instant notBefore) {
if (recurrent) {
throw new IllegalArgumentException("cannot combine notBefore with recurrent");
if (autoRenewal) {
throw new IllegalArgumentException("cannot combine notBefore with autoRenew");
}
this.notBefore = requireNonNull(notBefore, "notBefore");
return this;
@ -151,8 +151,8 @@ public class OrderBuilder {
* @return itself
*/
public OrderBuilder notAfter(Instant notAfter) {
if (recurrent) {
throw new IllegalArgumentException("cannot combine notAfter with recurrent");
if (autoRenewal) {
throw new IllegalArgumentException("cannot combine notAfter with autoRenew");
}
this.notAfter = requireNonNull(notAfter, "notAfter");
return this;
@ -162,17 +162,17 @@ public class OrderBuilder {
* Enables short-term automatic renewal of the certificate. Must be supported by the
* CA.
* <p>
* Recurrent renewals cannot be combined with {@link #notBefore(Instant)} or
* {@link #notAfter(Instant)}.
* Automatic renewals cannot be combined with {@link #notBefore(Instant)} or {@link
* #notAfter(Instant)}.
*
* @return itself
* @since 2.3
*/
public OrderBuilder recurrent() {
public OrderBuilder autoRenewal() {
if (notBefore != null || notAfter != null) {
throw new IllegalArgumentException("cannot combine notBefore/notAfter with recurrent");
throw new IllegalArgumentException("cannot combine notBefore/notAfter with autoRenewalOr");
}
this.recurrent = true;
this.autoRenewal = true;
return this;
}
@ -180,16 +180,16 @@ public class OrderBuilder {
* Sets the earliest date of validity of the first issued certificate. If not set,
* the start date is the earliest possible date.
* <p>
* Implies {@link #recurrent()}.
* Implies {@link #autoRenewal()}.
*
* @param start
* Start date of validity
* @return itself
* @since 2.3
*/
public OrderBuilder recurrentStart(Instant start) {
recurrent();
this.recurrentStart = requireNonNull(start, "start");
public OrderBuilder autoRenewalStart(Instant start) {
autoRenewal();
this.autoRenewalStart = requireNonNull(start, "start");
return this;
}
@ -197,17 +197,17 @@ public class OrderBuilder {
* Sets the latest date of validity of the last issued certificate. If not set, the
* CA's default is used.
* <p>
* Implies {@link #recurrent()}.
* Implies {@link #autoRenewal()}.
*
* @param end
* End date of validity
* @return itself
* @see Metadata#getStarMaxRenewal()
* @see Metadata#getAutoRenewalMaxDuration()
* @since 2.3
*/
public OrderBuilder recurrentEnd(Instant end) {
recurrent();
this.recurrentEnd = requireNonNull(end, "end");
public OrderBuilder autoRenewalEnd(Instant end) {
autoRenewal();
this.autoRenewalEnd = requireNonNull(end, "end");
return this;
}
@ -215,17 +215,17 @@ public class OrderBuilder {
* Sets the maximum validity period of each certificate. If not set, the CA's
* default is used.
* <p>
* Implies {@link #recurrent()}.
* Implies {@link #autoRenewal()}.
*
* @param duration
* Duration of validity of each certificate
* @return itself
* @see Metadata#getStarMinCertValidity()
* @see Metadata#getAutoRenewalMinLifetime()
* @since 2.3
*/
public OrderBuilder recurrentCertificateValidity(Duration duration) {
recurrent();
this.recurrentValidity = requireNonNull(duration, "duration");
public OrderBuilder autoRenewalLifetime(Duration duration) {
autoRenewal();
this.autoRenewalLifetime = requireNonNull(duration, "duration");
return this;
}
@ -233,36 +233,36 @@ public class OrderBuilder {
* Sets the amount of pre-dating each certificate. If not set, the CA's
* default (0) is used.
* <p>
* Implies {@link #recurrent()}.
* Implies {@link #autoRenewal()}.
*
* @param duration
* Duration of certificate pre-dating
* @return itself
* @since 2.7
*/
public OrderBuilder recurrentCertificatePredate(Duration duration) {
recurrent();
this.recurrentPredate = requireNonNull(duration, "duration");
public OrderBuilder autoRenewalLifetimeAdjust(Duration duration) {
autoRenewal();
this.autoRenewalLifetimeAdjust = requireNonNull(duration, "duration");
return this;
}
/**
* Announces that the client wishes to fetch the recurring certificate via GET
* Announces that the client wishes to fetch the auto-renewed certificate via GET
* request. If not used, the STAR certificate can only be fetched via POST-as-GET
* request. {@link Metadata#isStarCertificateGetAllowed()} must return {@code true} in
* request. {@link Metadata#isAutoRenewalGetAllowed()} must return {@code true} in
* order for this option to work.
* <p>
* This option is only needed if you plan to fetch the STAR certificate via other
* means than by using acme4j.
* <p>
* Implies {@link #recurrent()}.
* Implies {@link #autoRenewal()}.
*
* @return itself
* @since 2.6
*/
public OrderBuilder recurrentEnableGet() {
recurrent();
this.recurrentGet = true;
public OrderBuilder autoRenewalEnableGet() {
autoRenewal();
this.autoRenewalGet = true;
return this;
}
@ -278,7 +278,7 @@ public class OrderBuilder {
Session session = login.getSession();
if (recurrent && !session.getMetadata().isStarEnabled()) {
if (autoRenewal && !session.getMetadata().isAutoRenewalEnabled()) {
throw new AcmeException("CA does not support short-term automatic renewals");
}
@ -294,22 +294,22 @@ public class OrderBuilder {
claims.put("notAfter", notAfter);
}
if (recurrent) {
claims.put("recurrent", true);
if (recurrentStart != null) {
claims.put("recurrent-start-date", recurrentStart);
if (autoRenewal) {
JSONBuilder arClaims = claims.object("auto-renewal");
if (autoRenewalStart != null) {
arClaims.put("start-date", autoRenewalStart);
}
if (recurrentStart != null) {
claims.put("recurrent-end-date", recurrentEnd);
if (autoRenewalStart != null) {
arClaims.put("end-date", autoRenewalEnd);
}
if (recurrentValidity != null) {
claims.put("recurrent-certificate-validity", recurrentValidity);
if (autoRenewalLifetime != null) {
arClaims.put("lifetime", autoRenewalLifetime);
}
if (recurrentPredate != null) {
claims.put("recurrent-certificate-predate", recurrentPredate);
if (autoRenewalLifetimeAdjust != null) {
arClaims.put("lifetime-adjust", autoRenewalLifetimeAdjust);
}
if (recurrentGet) {
claims.put("recurrent-certificate-get", recurrentGet);
if (autoRenewalGet) {
arClaims.put("allow-certificate-get", autoRenewalGet);
}
}

View File

@ -68,7 +68,7 @@ public enum Status {
EXPIRED,
/**
* A recurrent {@link Order} is canceled.
* An auto-renewing {@link Order} is canceled.
*
* @since 2.3
*/

View File

@ -102,6 +102,12 @@ public class OrderBuilderTest {
assertThat(order.getNotAfter(), is(parseTimestamp("2016-01-08T00:10:00Z")));
assertThat(order.getExpires(), is(parseTimestamp("2016-01-10T00:00:00Z")));
assertThat(order.getStatus(), is(Status.PENDING));
assertThat(order.isAutoRenewing(), is(false));
assertThat(order.getAutoRenewalStartDate(), is(nullValue()));
assertThat(order.getAutoRenewalEndDate(), is(nullValue()));
assertThat(order.getAutoRenewalLifetime(), is(nullValue()));
assertThat(order.getAutoRenewalLifetimeAdjust(), is(nullValue()));
assertThat(order.isAutoRenewalGetEnabled(), is(false));
assertThat(order.getLocation(), is(locationUrl));
assertThat(order.getAuthorizations(), is(notNullValue()));
assertThat(order.getAuthorizations().size(), is(2));
@ -110,12 +116,12 @@ public class OrderBuilderTest {
}
/**
* Test that a new recurrent {@link Order} can be created.
* Test that a new auto-renewal {@link Order} can be created.
*/
@Test
public void testRecurrentOrderCertificate() throws Exception {
Instant recurrentStart = parseTimestamp("2018-01-01T00:00:00Z");
Instant recurrentEnd = parseTimestamp("2019-01-01T00:00:00Z");
public void testAutoRenewOrderCertificate() throws Exception {
Instant autoRenewStart = parseTimestamp("2018-01-01T00:00:00Z");
Instant autoRenewEnd = parseTimestamp("2019-01-01T00:00:00Z");
Duration validity = Duration.ofDays(7);
Duration predate = Duration.ofDays(6);
@ -123,14 +129,14 @@ public class OrderBuilderTest {
@Override
public int sendSignedRequest(URL url, JSONBuilder claims, Login login) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("requestRecurrentOrderRequest").toString()));
assertThat(claims.toString(), sameJSONAs(getJSON("requestAutoRenewOrderRequest").toString()));
assertThat(login, is(notNullValue()));
return HttpURLConnection.HTTP_CREATED;
}
@Override
public JSON readJsonResponse() {
return getJSON("requestRecurrentOrderResponse");
return getJSON("requestAutoRenewOrderResponse");
}
@Override
@ -141,39 +147,39 @@ public class OrderBuilderTest {
Login login = provider.createLogin();
provider.putMetadata("star-enabled", true);
provider.putMetadata("auto-renewal", JSON.empty());
provider.putTestResource(Resource.NEW_ORDER, resourceUrl);
Account account = new Account(login);
Order order = account.newOrder()
.domain("example.org")
.recurrent()
.recurrentStart(recurrentStart)
.recurrentEnd(recurrentEnd)
.recurrentCertificateValidity(validity)
.recurrentCertificatePredate(predate)
.recurrentEnableGet()
.autoRenewal()
.autoRenewalStart(autoRenewStart)
.autoRenewalEnd(autoRenewEnd)
.autoRenewalLifetime(validity)
.autoRenewalLifetimeAdjust(predate)
.autoRenewalEnableGet()
.create();
assertThat(order.getIdentifiers(), containsInAnyOrder(Identifier.dns("example.org")));
assertThat(order.getNotBefore(), is(nullValue()));
assertThat(order.getNotAfter(), is(nullValue()));
assertThat(order.isRecurrent(), is(true));
assertThat(order.getRecurrentStart(), is(recurrentStart));
assertThat(order.getRecurrentEnd(), is(recurrentEnd));
assertThat(order.getRecurrentCertificateValidity(), is(validity));
assertThat(order.getRecurrentCertificatePredate(), is(predate));
assertThat(order.isRecurrentGetEnabled(), is(true));
assertThat(order.isAutoRenewing(), is(true));
assertThat(order.getAutoRenewalStartDate(), is(autoRenewStart));
assertThat(order.getAutoRenewalEndDate(), is(autoRenewEnd));
assertThat(order.getAutoRenewalLifetime(), is(validity));
assertThat(order.getAutoRenewalLifetimeAdjust(), is(predate));
assertThat(order.isAutoRenewalGetEnabled(), is(true));
assertThat(order.getLocation(), is(locationUrl));
provider.close();
}
/**
* Test that a recurrent {@link Order} cannot be created if unsupported by the CA.
* Test that an auto-renewal {@link Order} cannot be created if unsupported by the CA.
*/
@Test(expected = AcmeException.class)
public void testRecurrentOrderCertificateFails() throws Exception {
public void testAutoRenewOrderCertificateFails() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider();
provider.putTestResource(Resource.NEW_ORDER, resourceUrl);
@ -182,17 +188,17 @@ public class OrderBuilderTest {
Account account = new Account(login);
account.newOrder()
.domain("example.org")
.recurrent()
.autoRenewal()
.create();
provider.close();
}
/**
* Test that recurrent and notBefore/notAfter cannot be mixed.
* Test that auto-renew and notBefore/notAfter cannot be mixed.
*/
@Test
public void testRecurrentNotMixed() throws Exception {
public void testAutoRenewNotMixed() throws Exception {
Instant someInstant = parseTimestamp("2018-01-01T00:00:00Z");
TestableConnectionProvider provider = new TestableConnectionProvider();
@ -201,7 +207,7 @@ public class OrderBuilderTest {
Account account = new Account(login);
try {
OrderBuilder ob = account.newOrder().recurrent();
OrderBuilder ob = account.newOrder().autoRenewal();
ob.notBefore(someInstant);
fail("accepted notBefore");
} catch (IllegalArgumentException ex) {
@ -209,7 +215,7 @@ public class OrderBuilderTest {
}
try {
OrderBuilder ob = account.newOrder().recurrent();
OrderBuilder ob = account.newOrder().autoRenewal();
ob.notAfter(someInstant);
fail("accepted notAfter");
} catch (IllegalArgumentException ex) {
@ -218,32 +224,32 @@ public class OrderBuilderTest {
try {
OrderBuilder ob = account.newOrder().notBefore(someInstant);
ob.recurrent();
fail("accepted recurrent");
ob.autoRenewal();
fail("accepted autoRenewal");
} catch (IllegalArgumentException ex) {
// expected
}
try {
OrderBuilder ob = account.newOrder().notBefore(someInstant);
ob.recurrentStart(someInstant);
fail("accepted recurrentStart");
ob.autoRenewalStart(someInstant);
fail("accepted autoRenewalStart");
} catch (IllegalArgumentException ex) {
// expected
}
try {
OrderBuilder ob = account.newOrder().notBefore(someInstant);
ob.recurrentEnd(someInstant);
fail("accepted recurrentEnd");
ob.autoRenewalEnd(someInstant);
fail("accepted autoRenewalEnd");
} catch (IllegalArgumentException ex) {
// expected
}
try {
OrderBuilder ob = account.newOrder().notBefore(someInstant);
ob.recurrentCertificateValidity(Duration.ofDays(7));
fail("accepted recurrentCertificateValidity");
ob.autoRenewalLifetime(Duration.ofDays(7));
fail("accepted autoRenewalLifetime");
} catch (IllegalArgumentException ex) {
// expected
}

View File

@ -81,12 +81,12 @@ public class OrderTest {
assertThat(order.getCertificate().getLocation(), is(url("https://example.com/acme/cert/1234")));
assertThat(order.getFinalizeLocation(), is(finalizeUrl));
assertThat(order.isRecurrent(), is(false));
assertThat(order.getRecurrentStart(), is(nullValue()));
assertThat(order.getRecurrentEnd(), is(nullValue()));
assertThat(order.getRecurrentCertificateValidity(), is(nullValue()));
assertThat(order.getRecurrentCertificatePredate(), is(nullValue()));
assertThat(order.isRecurrentGetEnabled(), is(false));
assertThat(order.isAutoRenewing(), is(false));
assertThat(order.getAutoRenewalStartDate(), is(nullValue()));
assertThat(order.getAutoRenewalEndDate(), is(nullValue()));
assertThat(order.getAutoRenewalLifetime(), is(nullValue()));
assertThat(order.getAutoRenewalLifetimeAdjust(), is(nullValue()));
assertThat(order.isAutoRenewalGetEnabled(), is(false));
assertThat(order.getError(), is(notNullValue()));
assertThat(order.getError().getType(), is(URI.create("urn:ietf:params:acme:error:connection")));
@ -198,7 +198,7 @@ public class OrderTest {
assertThat(order.getNotBefore(), is(parseTimestamp("2016-01-01T00:00:00Z")));
assertThat(order.getNotAfter(), is(parseTimestamp("2016-01-08T00:00:00Z")));
assertThat(order.getCertificate().getLocation(), is(url("https://example.com/acme/cert/1234")));
assertThat(order.getStarCertificate(), is(nullValue()));
assertThat(order.getAutoRenewalCertificate(), is(nullValue()));
assertThat(order.getFinalizeLocation(), is(finalizeUrl));
List<Authorization> auths = order.getAuthorizations();
@ -215,7 +215,7 @@ public class OrderTest {
* Test that order is properly updated.
*/
@Test
public void testRecurrentUpdate() throws Exception {
public void testAutoRenewUpdate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public int sendSignedPostAsGetRequest(URL url, Login login) {
@ -225,7 +225,7 @@ public class OrderTest {
@Override
public JSON readJsonResponse() {
return getJSON("updateRecurrentOrderResponse");
return getJSON("updateAutoRenewOrderResponse");
}
@Override
@ -234,30 +234,30 @@ public class OrderTest {
}
};
provider.putMetadata("star-enabled", true);
provider.putMetadata("auto-renewal", JSON.empty());
Login login = provider.createLogin();
Order order = new Order(login, locationUrl);
order.update();
assertThat(order.isRecurrent(), is(true));
assertThat(order.getRecurrentStart(), is(parseTimestamp("2016-01-01T00:00:00Z")));
assertThat(order.getRecurrentEnd(), is(parseTimestamp("2017-01-01T00:00:00Z")));
assertThat(order.getRecurrentCertificateValidity(), is(Duration.ofHours(168)));
assertThat(order.getRecurrentCertificatePredate(), is(Duration.ofDays(6)));
assertThat(order.isAutoRenewing(), is(true));
assertThat(order.getAutoRenewalStartDate(), is(parseTimestamp("2016-01-01T00:00:00Z")));
assertThat(order.getAutoRenewalEndDate(), is(parseTimestamp("2017-01-01T00:00:00Z")));
assertThat(order.getAutoRenewalLifetime(), is(Duration.ofHours(168)));
assertThat(order.getAutoRenewalLifetimeAdjust(), is(Duration.ofDays(6)));
assertThat(order.getNotBefore(), is(nullValue()));
assertThat(order.getNotAfter(), is(nullValue()));
assertThat(order.isRecurrentGetEnabled(), is(true));
assertThat(order.isAutoRenewalGetEnabled(), is(true));
provider.close();
}
/**
* Test that recurrent order is properly finalized.
* Test that auto-renew order is properly finalized.
*/
@Test
public void testRecurrentFinalize() throws Exception {
public void testAutoRenewFinalize() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public int sendSignedPostAsGetRequest(URL url, Login login) {
@ -267,7 +267,7 @@ public class OrderTest {
@Override
public JSON readJsonResponse() {
return getJSON("finalizeRecurrentResponse");
return getJSON("finalizeAutoRenewResponse");
}
@Override
@ -280,21 +280,21 @@ public class OrderTest {
Order order = login.bindOrder(locationUrl);
assertThat(order.getCertificate(), is(nullValue()));
assertThat(order.getStarCertificate().getLocation(), is(url("https://example.com/acme/cert/1234")));
assertThat(order.isRecurrent(), is(true));
assertThat(order.getRecurrentStart(), is(parseTimestamp("2018-01-01T00:00:00Z")));
assertThat(order.getRecurrentEnd(), is(parseTimestamp("2019-01-01T00:00:00Z")));
assertThat(order.getRecurrentCertificateValidity(), is(Duration.ofHours(168)));
assertThat(order.getRecurrentCertificatePredate(), is(Duration.ofDays(6)));
assertThat(order.getAutoRenewalCertificate().getLocation(), is(url("https://example.com/acme/cert/1234")));
assertThat(order.isAutoRenewing(), is(true));
assertThat(order.getAutoRenewalStartDate(), is(parseTimestamp("2018-01-01T00:00:00Z")));
assertThat(order.getAutoRenewalEndDate(), is(parseTimestamp("2019-01-01T00:00:00Z")));
assertThat(order.getAutoRenewalLifetime(), is(Duration.ofHours(168)));
assertThat(order.getAutoRenewalLifetimeAdjust(), is(Duration.ofDays(6)));
assertThat(order.getNotBefore(), is(nullValue()));
assertThat(order.getNotAfter(), is(nullValue()));
assertThat(order.isRecurrentGetEnabled(), is(true));
assertThat(order.isAutoRenewalGetEnabled(), is(true));
provider.close();
}
/**
* Test that recurrent order is properly canceled.
* Test that auto-renew order is properly canceled.
*/
@Test
public void testCancel() throws Exception {
@ -314,12 +314,12 @@ public class OrderTest {
}
};
provider.putMetadata("star-enabled", true);
provider.putMetadata("auto-renewal", JSON.empty());
Login login = provider.createLogin();
Order order = new Order(login, locationUrl);
order.cancelRecurrent();
order.cancelAutoRenewal();
assertThat(order.getStatus(), is(Status.CANCELED));

View File

@ -184,10 +184,10 @@ public class SessionTest {
assertThat(meta.getTermsOfService(), is(nullValue()));
assertThat(meta.getWebsite(), is(nullValue()));
assertThat(meta.getCaaIdentities(), is(empty()));
assertThat(meta.isStarEnabled(), is(false));
assertThat(meta.getStarMaxRenewal(), is(nullValue()));
assertThat(meta.getStarMinCertValidity(), is(nullValue()));
assertThat(meta.isStarCertificateGetAllowed(), is(false));
assertThat(meta.isAutoRenewalEnabled(), is(false));
assertThat(meta.getAutoRenewalMaxDuration(), is(nullValue()));
assertThat(meta.getAutoRenewalMinLifetime(), is(nullValue()));
assertThat(meta.isAutoRenewalGetAllowed(), is(false));
}
/**
@ -217,10 +217,10 @@ public class SessionTest {
assertThat(meta.getTermsOfService(), is(URI.create("https://example.com/acme/terms")));
assertThat(meta.getWebsite(), is(url("https://www.example.com/")));
assertThat(meta.getCaaIdentities(), containsInAnyOrder("example.com"));
assertThat(meta.isStarEnabled(), is(true));
assertThat(meta.getStarMaxRenewal(), is(Duration.ofDays(365)));
assertThat(meta.getStarMinCertValidity(), is(Duration.ofHours(24)));
assertThat(meta.isStarCertificateGetAllowed(), is(true));
assertThat(meta.isAutoRenewalEnabled(), is(true));
assertThat(meta.getAutoRenewalMaxDuration(), is(Duration.ofDays(365)));
assertThat(meta.getAutoRenewalMinLifetime(), is(Duration.ofHours(24)));
assertThat(meta.isAutoRenewalGetAllowed(), is(true));
assertThat(meta.isExternalAccountRequired(), is(true));
assertThat(meta.getJSON(), is(notNullValue()));
}

View File

@ -9,11 +9,12 @@
"caaIdentities": [
"example.com"
],
"auto-renewal": {
"min-lifetime": 86400,
"max-duration": 31536000,
"allow-certificate-get": true
},
"externalAccountRequired": true,
"star-enabled": true,
"star-min-cert-validity": 86400,
"star-max-renewal": 31536000,
"star-allow-certificate-get": true,
"xTestString": "foobar",
"xTestUri": "https://www.example.org",
"xTestArray": [

View File

@ -11,12 +11,13 @@
"value": "www.example.com"
}
],
"recurrent": true,
"recurrent-start-date": "2018-01-01T00:00:00Z",
"recurrent-end-date": "2019-01-01T00:00:00Z",
"recurrent-certificate-validity": 604800,
"recurrent-certificate-predate": 518400,
"recurrent-certificate-get": true,
"auto-renewal": {
"start-date": "2018-01-01T00:00:00Z",
"end-date": "2019-01-01T00:00:00Z",
"lifetime": 604800,
"lifetime-adjust": 518400,
"allow-certificate-get": true
},
"authorizations": [
"https://example.com/acme/authz/1234",
"https://example.com/acme/authz/2345"

View File

@ -0,0 +1,15 @@
{
"identifiers": [
{
"type": "dns",
"value": "example.org"
}
],
"auto-renewal": {
"start-date": "2018-01-01T00:00:00Z",
"end-date": "2019-01-01T00:00:00Z",
"lifetime": 604800,
"lifetime-adjust": 518400,
"allow-certificate-get": true
}
}

View File

@ -7,12 +7,13 @@
"value": "example.org"
}
],
"recurrent": true,
"recurrent-start-date": "2018-01-01T00:00:00Z",
"recurrent-end-date": "2019-01-01T00:00:00Z",
"recurrent-certificate-validity": 604800,
"recurrent-certificate-predate": 518400,
"recurrent-certificate-get": true,
"auto-renewal": {
"start-date": "2018-01-01T00:00:00Z",
"end-date": "2019-01-01T00:00:00Z",
"lifetime": 604800,
"lifetime-adjust": 518400,
"allow-certificate-get": true
},
"authorizations": [
"https://example.com/acme/authz/1234",
"https://example.com/acme/authz/2345"

View File

@ -1,14 +0,0 @@
{
"identifiers": [
{
"type": "dns",
"value": "example.org"
}
],
"recurrent": true,
"recurrent-start-date": "2018-01-01T00:00:00Z",
"recurrent-end-date": "2019-01-01T00:00:00Z",
"recurrent-certificate-validity": 604800,
"recurrent-certificate-predate": 518400,
"recurrent-certificate-get": true
}

View File

@ -0,0 +1,10 @@
{
"status": "valid",
"auto-renewal": {
"start-date": "2016-01-01T00:00:00Z",
"end-date": "2017-01-01T00:00:00Z",
"lifetime": 604800,
"lifetime-adjust": 518400,
"allow-certificate-get": true
}
}

View File

@ -1,9 +0,0 @@
{
"status": "valid",
"recurrent": true,
"recurrent-start-date": "2016-01-01T00:00:00Z",
"recurrent-end-date": "2017-01-01T00:00:00Z",
"recurrent-certificate-validity": 604800,
"recurrent-certificate-predate": 518400,
"recurrent-certificate-get": true
}

View File

@ -2,6 +2,10 @@
This document will help you migrate your code to the latest _acme4j_ version.
## Migration to Version 2.9
- In the ACME STAR draft 09, the term "recurring" has been changed to "auto-renewal". To reflect this change, all STAR related methods in the acme4j API have been renamed as well. If you are using the STAR extension, you are going to get a number of compile errors, but you will always find a corresponding new method. No functionality has been removed. I decided to do a hard API change because acme4j's STAR support is still experimental.
## Migration to Version 2.8
- Challenges can now be found by their class type instead of a type string, which makes finding a challenge type safe. I recommend to migrate your code to this new way. The classic way is not deprecated and will not be removed though. Example:

View File

@ -198,25 +198,25 @@ _acme4j_ supports the [ACME STAR](https://tools.ietf.org/html/draft-ietf-acme-st
To find out if the CA supports the STAR extension, check the metadata:
```java
if (session.getMetadata().isStarEnabled()) {
if (session.getMetadata().isAutoRenewalEnabled()) {
// CA supports STAR!
}
```
If STAR is supported, you can enable recurrent renewals by adding `recurrent()` to the order parameters:
If STAR is supported, you can enable automatic renewals by adding `autoRenewal()` to the order parameters:
```java
Order order = account.newOrder()
.domain("example.org")
.recurrent()
.autoRenewal()
.create();
```
You can use `recurrentStart()`, `recurrentEnd()`, `recurrentCertificateValidity()` and `recurrentCertificatePredate()` to change the time span and frequency of automatic renewals. You cannot use `notBefore()` and `notAfter()` in combination with `recurrent()` though.
You can use `autoRenewalStart()`, `autoRenewalEnd()`, `autoRenewalLifetime()` and `autoRenewalLifetimeAdjust()` to change the time span and frequency of automatic renewals. You cannot use `notBefore()` and `notAfter()` in combination with `autoRenewal()` though.
The `Metadata` object also holds the accepted renewal limits (see `Metadata.getStarMinCertValidity()` and `Metadata.getStarMaxRenewal()`).
The `Metadata` object also holds the accepted renewal limits (see `Metadata.getAutoRenewalMinLifetime()` and `Metadata.getAutoRenewalMaxDuration()`).
After the validation process is completed and the order is finalized, the STAR certificate is available via `Order.getStarCertificate()` (_not_ `Order.getCertificate()`)!
After the validation process is completed and the order is finalized, the STAR certificate is available via `Order.getAutoRenewalCertificate()` (_not_ `Order.getCertificate()`)!
Use `Certificate.getLocation()` to retrieve the URL of your certificate. It is renewed automatically, so you will always be able to download the latest issue of the certificate from this URL.
@ -233,6 +233,6 @@ X509Certificate latestCertificate = cert.getCertificate();
```
If supported by the CA, it is possible to negotiate that the certificate can also be downloaded via `GET` request. First use `Metadata.isStarCertificateGetAllowed()` to check if this option is supported by the CA. If it is, add `recurrentEnableGet()` to the order parameters to enable it. After the order was finalized, you can use any HTTP client to download the latest certificate from the certificate URL by a `GET` request.
If supported by the CA, it is possible to negotiate that the certificate can also be downloaded via `GET` request. First use `Metadata.isAutoRenewalGetAllowed()` to check if this option is supported by the CA. If it is, add `autoRenewalEnableGet()` to the order parameters to enable it. After the order was finalized, you can use any HTTP client to download the latest certificate from the certificate URL by a `GET` request.
Use `Order.cancelRecurrent()` to terminate automatical certificate renewals.
Use `Order.cancelAutoRenewal()` to terminate automatical certificate renewals.