mirror of https://github.com/shred/acme4j
Upgrade to Java 17
parent
1069bcc2ce
commit
1ed293c5bb
|
@ -18,7 +18,7 @@ This Java client helps to connect to an ACME server, and performing all necessar
|
||||||
* Supports [draft-ietf-acme-ari-07](https://www.ietf.org/archive/id/draft-ietf-acme-ari-07.html) for renewal information (experimental)
|
* Supports [draft-ietf-acme-ari-07](https://www.ietf.org/archive/id/draft-ietf-acme-ari-07.html) for renewal information (experimental)
|
||||||
* Supports [draft-aaron-acme-profiles-00](https://www.ietf.org/archive/id/draft-aaron-acme-profiles-00.html) for certificate profiles (experimental)
|
* Supports [draft-aaron-acme-profiles-00](https://www.ietf.org/archive/id/draft-aaron-acme-profiles-00.html) for certificate profiles (experimental)
|
||||||
* Easy to use Java API
|
* Easy to use Java API
|
||||||
* Requires JRE 11 or higher
|
* Requires JRE 17 or higher
|
||||||
* Supports [Buypass](https://buypass.com/), [Google Trust Services](https://pki.goog/), [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com/), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs.
|
* Supports [Buypass](https://buypass.com/), [Google Trust Services](https://pki.goog/), [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com/), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs.
|
||||||
* Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22)
|
* Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22)
|
||||||
* Extensive unit and integration tests
|
* Extensive unit and integration tests
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j;
|
package org.shredzone.acme4j;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toUnmodifiableList;
|
import java.io.Serial;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -42,6 +41,7 @@ import org.slf4j.LoggerFactory;
|
||||||
* A representation of an account at the ACME server.
|
* A representation of an account at the ACME server.
|
||||||
*/
|
*/
|
||||||
public class Account extends AcmeJsonResource {
|
public class Account extends AcmeJsonResource {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 7042863483428051319L;
|
private static final long serialVersionUID = 7042863483428051319L;
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Account.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Account.class);
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public class Account extends AcmeJsonResource {
|
||||||
.asArray()
|
.asArray()
|
||||||
.stream()
|
.stream()
|
||||||
.map(Value::asURI)
|
.map(Value::asURI)
|
||||||
.collect(toUnmodifiableList());
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -243,11 +243,9 @@ public class Identifier implements Serializable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof Identifier)) {
|
if (!(obj instanceof Identifier i)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = (Identifier) obj;
|
|
||||||
return content.equals(i.content);
|
return content.equals(i.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,9 @@ package org.shredzone.acme4j;
|
||||||
|
|
||||||
import static java.util.Collections.unmodifiableList;
|
import static java.util.Collections.unmodifiableList;
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
import static java.util.stream.Collectors.toUnmodifiableList;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serial;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory;
|
||||||
* A representation of a certificate order at the CA.
|
* A representation of a certificate order at the CA.
|
||||||
*/
|
*/
|
||||||
public class Order extends AcmeJsonResource implements PollableResource {
|
public class Order extends AcmeJsonResource implements PollableResource {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 5435808648658292177L;
|
private static final long serialVersionUID = 5435808648658292177L;
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Order.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Order.class);
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ public class Order extends AcmeJsonResource implements PollableResource {
|
||||||
.asArray()
|
.asArray()
|
||||||
.stream()
|
.stream()
|
||||||
.map(Value::asIdentifier)
|
.map(Value::asIdentifier)
|
||||||
.collect(toUnmodifiableList());
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j;
|
package org.shredzone.acme4j;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toUnmodifiableList;
|
import java.io.Serial;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
@ -33,6 +32,7 @@ import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc7807">RFC 7807</a>
|
* @see <a href="https://tools.ietf.org/html/rfc7807">RFC 7807</a>
|
||||||
*/
|
*/
|
||||||
public class Problem implements Serializable {
|
public class Problem implements Serializable {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -8418248862966754214L;
|
private static final long serialVersionUID = -8418248862966754214L;
|
||||||
|
|
||||||
private final URL baseUrl;
|
private final URL baseUrl;
|
||||||
|
@ -122,7 +122,7 @@ public class Problem implements Serializable {
|
||||||
.asArray()
|
.asArray()
|
||||||
.stream()
|
.stream()
|
||||||
.map(o -> o.asProblem(baseUrl))
|
.map(o -> o.asProblem(baseUrl))
|
||||||
.collect(toUnmodifiableList());
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,7 +33,7 @@ public enum Status {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server is processing the resource. The client should invoke
|
* The server is processing the resource. The client should invoke
|
||||||
* {@link AcmeJsonResource#update()} and re-check the status.
|
* {@link AcmeJsonResource#fetch()} and re-check the status.
|
||||||
*/
|
*/
|
||||||
PROCESSING,
|
PROCESSING,
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.challenge;
|
package org.shredzone.acme4j.challenge;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
@ -41,6 +42,7 @@ import org.slf4j.LoggerFactory;
|
||||||
* required data to the challenge response.
|
* required data to the challenge response.
|
||||||
*/
|
*/
|
||||||
public class Challenge extends AcmeJsonResource implements PollableResource {
|
public class Challenge extends AcmeJsonResource implements PollableResource {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 2338794776848388099L;
|
private static final long serialVersionUID = 2338794776848388099L;
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Challenge.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Challenge.class);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ package org.shredzone.acme4j.challenge;
|
||||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
|
import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
|
||||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash;
|
import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import org.shredzone.acme4j.Identifier;
|
import org.shredzone.acme4j.Identifier;
|
||||||
import org.shredzone.acme4j.Login;
|
import org.shredzone.acme4j.Login;
|
||||||
import org.shredzone.acme4j.toolbox.JSON;
|
import org.shredzone.acme4j.toolbox.JSON;
|
||||||
|
@ -25,6 +27,7 @@ import org.shredzone.acme4j.toolbox.JSON;
|
||||||
* validation. See the acme4j documentation for a detailed explanation.
|
* validation. See the acme4j documentation for a detailed explanation.
|
||||||
*/
|
*/
|
||||||
public class Dns01Challenge extends TokenChallenge {
|
public class Dns01Challenge extends TokenChallenge {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 6964687027713533075L;
|
private static final long serialVersionUID = 6964687027713533075L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.challenge;
|
package org.shredzone.acme4j.challenge;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import org.shredzone.acme4j.Login;
|
import org.shredzone.acme4j.Login;
|
||||||
import org.shredzone.acme4j.toolbox.JSON;
|
import org.shredzone.acme4j.toolbox.JSON;
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ import org.shredzone.acme4j.toolbox.JSON;
|
||||||
* detailed explanation.
|
* detailed explanation.
|
||||||
*/
|
*/
|
||||||
public class Http01Challenge extends TokenChallenge {
|
public class Http01Challenge extends TokenChallenge {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 3322211185872544605L;
|
private static final long serialVersionUID = 3322211185872544605L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@ package org.shredzone.acme4j.challenge;
|
||||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash;
|
import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serial;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ import org.shredzone.acme4j.util.CertificateUtils;
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
public class TlsAlpn01Challenge extends TokenChallenge {
|
public class TlsAlpn01Challenge extends TokenChallenge {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -5590351078176091228L;
|
private static final long serialVersionUID = -5590351078176091228L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,6 +15,8 @@ package org.shredzone.acme4j.challenge;
|
||||||
|
|
||||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
|
import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import org.shredzone.acme4j.Login;
|
import org.shredzone.acme4j.Login;
|
||||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
import org.shredzone.acme4j.toolbox.AcmeUtils;
|
import org.shredzone.acme4j.toolbox.AcmeUtils;
|
||||||
|
@ -26,6 +28,7 @@ import org.shredzone.acme4j.toolbox.JoseUtils;
|
||||||
* and {@code keyAuthorization}.
|
* and {@code keyAuthorization}.
|
||||||
*/
|
*/
|
||||||
public class TokenChallenge extends Challenge {
|
public class TokenChallenge extends Challenge {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 1634133407432681800L;
|
private static final long serialVersionUID = 1634133407432681800L;
|
||||||
|
|
||||||
protected static final String KEY_TOKEN = "token";
|
protected static final String KEY_TOKEN = "token";
|
||||||
|
|
|
@ -15,7 +15,6 @@ package org.shredzone.acme4j.connector;
|
||||||
|
|
||||||
import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
|
import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
|
||||||
import static java.util.function.Predicate.not;
|
import static java.util.function.Predicate.not;
|
||||||
import static java.util.stream.Collectors.toUnmodifiableList;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -137,7 +136,7 @@ public class DefaultConnection implements Connection {
|
||||||
var retryAfterInstant = getRetryAfter();
|
var retryAfterInstant = getRetryAfter();
|
||||||
if (retryAfterInstant.isPresent()) {
|
if (retryAfterInstant.isPresent()) {
|
||||||
throw new AcmeRetryAfterException(message, retryAfterInstant.get());
|
throw new AcmeRetryAfterException(message, retryAfterInstant.get());
|
||||||
};
|
}
|
||||||
throw new AcmeException(message);
|
throw new AcmeException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +227,7 @@ public class DefaultConnection implements Connection {
|
||||||
var cf = CertificateFactory.getInstance("X.509");
|
var cf = CertificateFactory.getInstance("X.509");
|
||||||
return cf.generateCertificates(in).stream()
|
return cf.generateCertificates(in).stream()
|
||||||
.map(X509Certificate.class::cast)
|
.map(X509Certificate.class::cast)
|
||||||
.collect(toUnmodifiableList());
|
.toList();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AcmeNetworkException(ex);
|
throw new AcmeNetworkException(ex);
|
||||||
} catch (CertificateException ex) {
|
} catch (CertificateException ex) {
|
||||||
|
@ -311,7 +310,7 @@ public class DefaultConnection implements Connection {
|
||||||
public Collection<URL> getLinks(String relation) {
|
public Collection<URL> getLinks(String relation) {
|
||||||
return collectLinks(relation).stream()
|
return collectLinks(relation).stream()
|
||||||
.map(this::resolveRelative)
|
.map(this::resolveRelative)
|
||||||
.collect(toUnmodifiableList());
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -620,7 +619,7 @@ public class DefaultConnection implements Connection {
|
||||||
.filter(Matcher::matches)
|
.filter(Matcher::matches)
|
||||||
.map(m -> m.group(1))
|
.map(m -> m.group(1))
|
||||||
.peek(location -> LOG.debug("Link: {} -> {}", relation, location))
|
.peek(location -> LOG.debug("Link: {} -> {}", relation, location))
|
||||||
.collect(toUnmodifiableList());
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,10 +13,13 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root class of all checked acme4j exceptions.
|
* The root class of all checked acme4j exceptions.
|
||||||
*/
|
*/
|
||||||
public class AcmeException extends Exception {
|
public class AcmeException extends Exception {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -2935088954705632025L;
|
private static final long serialVersionUID = -2935088954705632025L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,6 +15,7 @@ package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import org.shredzone.acme4j.AcmeResource;
|
import org.shredzone.acme4j.AcmeResource;
|
||||||
|
@ -26,6 +27,7 @@ import org.shredzone.acme4j.AcmeResource;
|
||||||
* thrown by getter methods, so the API is not polluted with checked exceptions.
|
* thrown by getter methods, so the API is not polluted with checked exceptions.
|
||||||
*/
|
*/
|
||||||
public class AcmeLazyLoadingException extends RuntimeException {
|
public class AcmeLazyLoadingException extends RuntimeException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 1000353433913721901L;
|
private static final long serialVersionUID = 1000353433913721901L;
|
||||||
|
|
||||||
private final Class<? extends AcmeResource> type;
|
private final Class<? extends AcmeResource> type;
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A general network error has occured while communicating with the server (e.g. network
|
* A general network error has occured while communicating with the server (e.g. network
|
||||||
* timeout).
|
* timeout).
|
||||||
*/
|
*/
|
||||||
public class AcmeNetworkException extends AcmeException {
|
public class AcmeNetworkException extends AcmeException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 2054398693543329179L;
|
private static final long serialVersionUID = 2054398693543329179L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,12 +13,15 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A runtime exception that is thrown if the ACME server does not support a certain
|
* A runtime exception that is thrown if the ACME server does not support a certain
|
||||||
* feature. It might be either because that feature is optional, or because the server
|
* feature. It might be either because that feature is optional, or because the server
|
||||||
* is not fully RFC compliant.
|
* is not fully RFC compliant.
|
||||||
*/
|
*/
|
||||||
public class AcmeNotSupportedException extends AcmeProtocolException {
|
public class AcmeNotSupportedException extends AcmeProtocolException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 3434074002226584731L;
|
private static final long serialVersionUID = 3434074002226584731L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,12 +13,15 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A runtime exception that is thrown when the response of the server is violating the
|
* A runtime exception that is thrown when the response of the server is violating the
|
||||||
* RFC, and could not be handled or parsed for that reason. It is an indicator that the CA
|
* RFC, and could not be handled or parsed for that reason. It is an indicator that the CA
|
||||||
* does not fully comply with the RFC, and is usually not expected to be thrown.
|
* does not fully comply with the RFC, and is usually not expected to be thrown.
|
||||||
*/
|
*/
|
||||||
public class AcmeProtocolException extends RuntimeException {
|
public class AcmeProtocolException extends RuntimeException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 2031203835755725193L;
|
private static final long serialVersionUID = 2031203835755725193L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -28,6 +29,7 @@ import org.shredzone.acme4j.Problem;
|
||||||
* further explains the rate limit that was exceeded.
|
* further explains the rate limit that was exceeded.
|
||||||
*/
|
*/
|
||||||
public class AcmeRateLimitedException extends AcmeServerException {
|
public class AcmeRateLimitedException extends AcmeServerException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 4150484059796413069L;
|
private static final long serialVersionUID = 4150484059796413069L;
|
||||||
|
|
||||||
private final @Nullable Instant retryAfter;
|
private final @Nullable Instant retryAfter;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ import org.shredzone.acme4j.Problem;
|
||||||
* individually.
|
* individually.
|
||||||
*/
|
*/
|
||||||
public class AcmeServerException extends AcmeException {
|
public class AcmeServerException extends AcmeException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 5971622508467042792L;
|
private static final long serialVersionUID = 5971622508467042792L;
|
||||||
|
|
||||||
private final Problem problem;
|
private final Problem problem;
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import org.shredzone.acme4j.Problem;
|
import org.shredzone.acme4j.Problem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,6 +22,7 @@ import org.shredzone.acme4j.Problem;
|
||||||
* will give further details (e.g. "client IP is blocked").
|
* will give further details (e.g. "client IP is blocked").
|
||||||
*/
|
*/
|
||||||
public class AcmeUnauthorizedException extends AcmeServerException {
|
public class AcmeUnauthorizedException extends AcmeServerException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 9064697508262919366L;
|
private static final long serialVersionUID = 9064697508262919366L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.exception;
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
@ -28,6 +29,7 @@ import org.shredzone.acme4j.Problem;
|
||||||
* requires an agreement to the new terms before proceeding.
|
* requires an agreement to the new terms before proceeding.
|
||||||
*/
|
*/
|
||||||
public class AcmeUserActionRequiredException extends AcmeServerException {
|
public class AcmeUserActionRequiredException extends AcmeServerException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 7719055447283858352L;
|
private static final long serialVersionUID = 7719055447283858352L;
|
||||||
|
|
||||||
private final @Nullable URI tosUri;
|
private final @Nullable URI tosUri;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -54,6 +55,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
* A model containing a JSON result. The content is immutable.
|
* A model containing a JSON result. The content is immutable.
|
||||||
*/
|
*/
|
||||||
public final class JSON implements Serializable {
|
public final class JSON implements Serializable {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 418332625174149030L;
|
private static final long serialVersionUID = 418332625174149030L;
|
||||||
|
|
||||||
private static final JSON EMPTY_JSON = new JSON(new HashMap<>());
|
private static final JSON EMPTY_JSON = new JSON(new HashMap<>());
|
||||||
|
|
|
@ -203,23 +203,13 @@ public final class JoseUtils {
|
||||||
* there is no corresponding algorithm identifier for the key
|
* there is no corresponding algorithm identifier for the key
|
||||||
*/
|
*/
|
||||||
public static String keyAlgorithm(JsonWebKey jwk) {
|
public static String keyAlgorithm(JsonWebKey jwk) {
|
||||||
if (jwk instanceof EllipticCurveJsonWebKey) {
|
if (jwk instanceof EllipticCurveJsonWebKey ecjwk) {
|
||||||
var ecjwk = (EllipticCurveJsonWebKey) jwk;
|
return switch (ecjwk.getCurveName()) {
|
||||||
|
case "P-256" -> AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256;
|
||||||
switch (ecjwk.getCurveName()) {
|
case "P-384" -> AlgorithmIdentifiers.ECDSA_USING_P384_CURVE_AND_SHA384;
|
||||||
case "P-256":
|
case "P-521" -> AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512;
|
||||||
return AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256;
|
default -> throw new IllegalArgumentException("Unknown EC name " + ecjwk.getCurveName());
|
||||||
|
};
|
||||||
case "P-384":
|
|
||||||
return AlgorithmIdentifiers.ECDSA_USING_P384_CURVE_AND_SHA384;
|
|
||||||
|
|
||||||
case "P-521":
|
|
||||||
return AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown EC name "
|
|
||||||
+ ecjwk.getCurveName());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (jwk instanceof RsaJsonWebKey) {
|
} else if (jwk instanceof RsaJsonWebKey) {
|
||||||
return AlgorithmIdentifiers.RSA_USING_SHA256;
|
return AlgorithmIdentifiers.RSA_USING_SHA256;
|
||||||
|
|
|
@ -126,18 +126,11 @@ public final class CertificateUtils {
|
||||||
|
|
||||||
var gns = new GeneralName[1];
|
var gns = new GeneralName[1];
|
||||||
|
|
||||||
switch (id.getType()) {
|
gns[0] = switch (id.getType()) {
|
||||||
case Identifier.TYPE_DNS:
|
case Identifier.TYPE_DNS -> new GeneralName(GeneralName.dNSName, id.getDomain());
|
||||||
gns[0] = new GeneralName(GeneralName.dNSName, id.getDomain());
|
case Identifier.TYPE_IP -> new GeneralName(GeneralName.iPAddress, id.getIP().getHostAddress());
|
||||||
break;
|
default -> throw new IllegalArgumentException("Unsupported Identifier type " + id.getType());
|
||||||
|
};
|
||||||
case Identifier.TYPE_IP:
|
|
||||||
gns[0] = new GeneralName(GeneralName.iPAddress, id.getIP().getHostAddress());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unsupported Identifier type " + id.getType());
|
|
||||||
}
|
|
||||||
certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(gns));
|
certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(gns));
|
||||||
certBuilder.addExtension(ACME_VALIDATION, true, new DEROctetString(acmeValidation));
|
certBuilder.addExtension(ACME_VALIDATION, true, new DEROctetString(acmeValidation));
|
||||||
|
|
||||||
|
@ -268,8 +261,8 @@ public final class CertificateUtils {
|
||||||
var attr = csr.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
|
var attr = csr.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
|
||||||
if (attr.length > 0) {
|
if (attr.length > 0) {
|
||||||
var extensions = attr[0].getAttrValues().toArray();
|
var extensions = attr[0].getAttrValues().toArray();
|
||||||
if (extensions.length > 0 && extensions[0] instanceof Extensions) {
|
if (extensions.length > 0 && extensions[0] instanceof Extensions extension0) {
|
||||||
var san = GeneralNames.fromExtensions((Extensions) extensions[0], Extension.subjectAlternativeName);
|
var san = GeneralNames.fromExtensions(extension0, Extension.subjectAlternativeName);
|
||||||
var critical = csr.getSubject().getRDNs().length == 0;
|
var critical = csr.getSubject().getRDNs().length == 0;
|
||||||
certBuilder.addExtension(Extension.subjectAlternativeName, critical, san);
|
certBuilder.addExtension(Extension.subjectAlternativeName, critical, san);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,10 +146,10 @@ public class AccountTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<URL> getLinks(String relation) {
|
public Collection<URL> getLinks(String relation) {
|
||||||
switch(relation) {
|
return switch (relation) {
|
||||||
case "termsOfService": return singletonList(agreementUrl);
|
case "termsOfService" -> singletonList(agreementUrl);
|
||||||
default: return emptyList();
|
default -> emptyList();
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -81,10 +81,10 @@ public class ClientTest {
|
||||||
private static final String EAB_HMAC = null;
|
private static final String EAB_HMAC = null;
|
||||||
|
|
||||||
// A supplier for a new account KeyPair. The default creates a new EC key pair.
|
// A supplier for a new account KeyPair. The default creates a new EC key pair.
|
||||||
private static Supplier<KeyPair> ACCOUNT_KEY_SUPPLIER = () -> KeyPairUtils.createKeyPair();
|
private static final Supplier<KeyPair> ACCOUNT_KEY_SUPPLIER = KeyPairUtils::createKeyPair;
|
||||||
|
|
||||||
// A supplier for a new domain KeyPair. The default creates a RSA key pair.
|
// A supplier for a new domain KeyPair. The default creates a RSA key pair.
|
||||||
private static Supplier<KeyPair> DOMAIN_KEY_SUPPLIER = () -> KeyPairUtils.createKeyPair(4096);
|
private static final Supplier<KeyPair> DOMAIN_KEY_SUPPLIER = () -> KeyPairUtils.createKeyPair(4096);
|
||||||
|
|
||||||
// File name of the User Key Pair
|
// File name of the User Key Pair
|
||||||
private static final File USER_KEY_FILE = new File("user.key");
|
private static final File USER_KEY_FILE = new File("user.key");
|
||||||
|
@ -267,16 +267,10 @@ public class ClientTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the desired challenge and prepare it.
|
// Find the desired challenge and prepare it.
|
||||||
Challenge challenge = null;
|
Challenge challenge = switch (CHALLENGE_TYPE) {
|
||||||
switch (CHALLENGE_TYPE) {
|
case HTTP -> httpChallenge(auth);
|
||||||
case HTTP:
|
case DNS -> dnsChallenge(auth);
|
||||||
challenge = httpChallenge(auth);
|
};
|
||||||
break;
|
|
||||||
|
|
||||||
case DNS:
|
|
||||||
challenge = dnsChallenge(auth);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (challenge == null) {
|
if (challenge == null) {
|
||||||
throw new AcmeException("No challenge found");
|
throw new AcmeException("No challenge found");
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.smime;
|
package org.shredzone.acme4j.smime;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import jakarta.mail.internet.AddressException;
|
import jakarta.mail.internet.AddressException;
|
||||||
import jakarta.mail.internet.InternetAddress;
|
import jakarta.mail.internet.InternetAddress;
|
||||||
import org.shredzone.acme4j.Identifier;
|
import org.shredzone.acme4j.Identifier;
|
||||||
|
@ -24,6 +26,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
* @since 2.12
|
* @since 2.12
|
||||||
*/
|
*/
|
||||||
public class EmailIdentifier extends Identifier {
|
public class EmailIdentifier extends Identifier {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -1473014167038845395L;
|
private static final long serialVersionUID = -1473014167038845395L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,8 @@ package org.shredzone.acme4j.smime.challenge;
|
||||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
|
import static org.shredzone.acme4j.toolbox.AcmeUtils.base64UrlEncode;
|
||||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash;
|
import static org.shredzone.acme4j.toolbox.AcmeUtils.sha256hash;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
import jakarta.mail.internet.AddressException;
|
import jakarta.mail.internet.AddressException;
|
||||||
import jakarta.mail.internet.InternetAddress;
|
import jakarta.mail.internet.InternetAddress;
|
||||||
import org.shredzone.acme4j.Login;
|
import org.shredzone.acme4j.Login;
|
||||||
|
@ -30,6 +32,7 @@ import org.shredzone.acme4j.toolbox.JSON;
|
||||||
* @since 2.12
|
* @since 2.12
|
||||||
*/
|
*/
|
||||||
public class EmailReply00Challenge extends TokenChallenge {
|
public class EmailReply00Challenge extends TokenChallenge {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 2502329538019544794L;
|
private static final long serialVersionUID = 2502329538019544794L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,6 +15,7 @@ package org.shredzone.acme4j.smime.exception;
|
||||||
|
|
||||||
import static java.util.Collections.unmodifiableList;
|
import static java.util.Collections.unmodifiableList;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -40,6 +41,7 @@ import org.shredzone.acme4j.exception.AcmeException;
|
||||||
* @since 2.15
|
* @since 2.15
|
||||||
*/
|
*/
|
||||||
public class AcmeInvalidMessageException extends AcmeException {
|
public class AcmeInvalidMessageException extends AcmeException {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 5607857024718309330L;
|
private static final long serialVersionUID = 5607857024718309330L;
|
||||||
|
|
||||||
private final List<ErrorBundle> errors;
|
private final List<ErrorBundle> errors;
|
||||||
|
|
|
@ -149,24 +149,19 @@ public class SignedMail implements Mail {
|
||||||
|
|
||||||
var relaxed = false;
|
var relaxed = false;
|
||||||
for (var element : (ASN1Set) attr.getAttributeValues()[0]) {
|
for (var element : (ASN1Set) attr.getAttributeValues()[0]) {
|
||||||
if (element instanceof ASN1Enumerated) {
|
if (element instanceof ASN1Enumerated asn1element) {
|
||||||
var algorithm = ((ASN1Enumerated) element).intValueExact();
|
var algorithm = asn1element.intValueExact();
|
||||||
switch (algorithm) {
|
relaxed = switch (algorithm) {
|
||||||
case 0:
|
case 0 -> false;
|
||||||
relaxed = false;
|
case 1 -> true;
|
||||||
break;
|
default -> throw new AcmeInvalidMessageException("Unknown algorithm: " + algorithm);
|
||||||
case 1:
|
};
|
||||||
relaxed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new AcmeInvalidMessageException("Unknown algorithm: " + algorithm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var element : (ASN1Set) attr.getAttributeValues()[0]) {
|
for (var element : (ASN1Set) attr.getAttributeValues()[0]) {
|
||||||
if (element instanceof ASN1Sequence) {
|
if (element instanceof ASN1Sequence asn1sequence) {
|
||||||
for (var sequenceElement : (ASN1Sequence) element) {
|
for (var sequenceElement : asn1sequence) {
|
||||||
var headerField = (ASN1Sequence) sequenceElement;
|
var headerField = (ASN1Sequence) sequenceElement;
|
||||||
var fieldName = ((ASN1String) headerField.getObjectAt(0)).getString();
|
var fieldName = ((ASN1String) headerField.getObjectAt(0)).getString();
|
||||||
var fieldValue = ((ASN1String) headerField.getObjectAt(1)).getString();
|
var fieldValue = ((ASN1String) headerField.getObjectAt(1)).getString();
|
||||||
|
|
|
@ -163,12 +163,11 @@ public class SignedMailBuilder {
|
||||||
requireNonNull(message, "message");
|
requireNonNull(message, "message");
|
||||||
try {
|
try {
|
||||||
// Check all parameters
|
// Check all parameters
|
||||||
if (!(message instanceof MimeMessage)) {
|
if (!(message instanceof MimeMessage mimeMessage)) {
|
||||||
throw new IllegalArgumentException("Message must be a MimeMessage");
|
throw new IllegalArgumentException("Message must be a MimeMessage");
|
||||||
}
|
}
|
||||||
MimeMessage mimeMessage = (MimeMessage) message;
|
|
||||||
|
|
||||||
if (!(mimeMessage.getContent() instanceof MimeMultipart)) {
|
if (!(mimeMessage.getContent() instanceof MimeMultipart contentMultipart)) {
|
||||||
throw new AcmeProtocolException("S/MIME signed message must contain MimeMultipart");
|
throw new AcmeProtocolException("S/MIME signed message must contain MimeMultipart");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +176,7 @@ public class SignedMailBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the signed message
|
// Get the signed message
|
||||||
SMIMESigned signed = new SMIMESigned((MimeMultipart) mimeMessage.getContent());
|
SMIMESigned signed = new SMIMESigned(contentMultipart);
|
||||||
|
|
||||||
// Validate the signature
|
// Validate the signature
|
||||||
SignerInformation si = validateSignature(mimeMessage, pkixParameters);
|
SignerInformation si = validateSignature(mimeMessage, pkixParameters);
|
||||||
|
|
|
@ -55,10 +55,10 @@ public class SimpleMail implements Mail {
|
||||||
if (from.length != 1) {
|
if (from.length != 1) {
|
||||||
throw new AcmeInvalidMessageException("Message must have exactly one sender, but has " + from.length);
|
throw new AcmeInvalidMessageException("Message must have exactly one sender, but has " + from.length);
|
||||||
}
|
}
|
||||||
if (!(from[0] instanceof InternetAddress)) {
|
if (!(from[0] instanceof InternetAddress from0)) {
|
||||||
throw new AcmeInvalidMessageException("Invalid sender message type: " + from[0].getClass().getName());
|
throw new AcmeInvalidMessageException("Invalid sender message type: " + from[0].getClass().getName());
|
||||||
}
|
}
|
||||||
return (InternetAddress) from[0];
|
return from0;
|
||||||
} catch (MessagingException ex) {
|
} catch (MessagingException ex) {
|
||||||
throw new AcmeInvalidMessageException("Could not read 'From' header", ex);
|
throw new AcmeInvalidMessageException("Could not read 'From' header", ex);
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,10 @@ public class SimpleMail implements Mail {
|
||||||
if (to.length != 1) {
|
if (to.length != 1) {
|
||||||
throw new AcmeInvalidMessageException("Message must have exactly one recipient, but has " + to.length);
|
throw new AcmeInvalidMessageException("Message must have exactly one recipient, but has " + to.length);
|
||||||
}
|
}
|
||||||
if (!(to[0] instanceof InternetAddress)) {
|
if (!(to[0] instanceof InternetAddress to0)) {
|
||||||
throw new AcmeInvalidMessageException("Invalid recipient message type: " + to[0].getClass().getName());
|
throw new AcmeInvalidMessageException("Invalid recipient message type: " + to[0].getClass().getName());
|
||||||
}
|
}
|
||||||
return (InternetAddress) to[0];
|
return to0;
|
||||||
} catch (MessagingException ex) {
|
} catch (MessagingException ex) {
|
||||||
throw new AcmeInvalidMessageException("Could not read 'To' header", ex);
|
throw new AcmeInvalidMessageException("Could not read 'To' header", ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ public class EmailIdentifierTest {
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("provideTestEmails")
|
@MethodSource("provideTestEmails")
|
||||||
public void testEmail(Object input, String expected) {
|
public void testEmail(Object input, String expected) {
|
||||||
var id = input instanceof InternetAddress
|
var id = input instanceof InternetAddress internetAddress
|
||||||
? EmailIdentifier.email((InternetAddress) input)
|
? EmailIdentifier.email(internetAddress)
|
||||||
: EmailIdentifier.email(input.toString());
|
: EmailIdentifier.email(input.toString());
|
||||||
|
|
||||||
assertThat(id.getType()).isEqualTo(EmailIdentifier.TYPE_EMAIL);
|
assertThat(id.getType()).isEqualTo(EmailIdentifier.TYPE_EMAIL);
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -75,7 +75,7 @@
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.8.1</version>
|
<version>3.8.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<release>11</release>
|
<release>17</release>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
|
@ -22,7 +22,7 @@ Latest version:  for renewal information (experimental)
|
* Supports [draft-ietf-acme-ari-07](https://www.ietf.org/archive/id/draft-ietf-acme-ari-07.html) for renewal information (experimental)
|
||||||
* Supports [draft-aaron-acme-profiles-00](https://www.ietf.org/archive/id/draft-aaron-acme-profiles-00.html) for certificate profiles (experimental)
|
* Supports [draft-aaron-acme-profiles-00](https://www.ietf.org/archive/id/draft-aaron-acme-profiles-00.html) for certificate profiles (experimental)
|
||||||
* Easy to use Java API
|
* Easy to use Java API
|
||||||
* Requires JRE 11 or higher
|
* Requires JRE 17 or higher
|
||||||
* Supports [Buypass](https://buypass.com/), [Google Trust Services](https://pki.goog/), [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com/), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs.
|
* Supports [Buypass](https://buypass.com/), [Google Trust Services](https://pki.goog/), [Let's Encrypt](https://letsencrypt.org/), [SSL.com](https://www.ssl.com/), [ZeroSSL](https://zerossl.com/), and all other CAs that comply with the ACME protocol (RFC 8555). Note that _acme4j_ is an independent project that is not supported or endorsed by any of the CAs.
|
||||||
* Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22)
|
* Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22)
|
||||||
* Extensive unit and integration tests
|
* Extensive unit and integration tests
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
This document will help you migrate your code to the latest _acme4j_ version.
|
This document will help you migrate your code to the latest _acme4j_ version.
|
||||||
|
|
||||||
|
## Migration to Version 3.6.0
|
||||||
|
|
||||||
|
- _acme4j_ requires JRE 17 or higher now.
|
||||||
|
|
||||||
## Migration to Version 3.5.0
|
## Migration to Version 3.5.0
|
||||||
|
|
||||||
- If you use STAR auto-renewal certificates, you can now use `Order.getCertificate()` instead of `Order.getAutoRenewalCertificate()` to retrieve the STAR certificate. `Order.getAutoRenewalCertificate()` is marked as deprecated, but still functional. The new method `Order.isAutoRenewalCertificate()` can be used to check if the order resulted in a standard or auto-renewing certificate.
|
- If you use STAR auto-renewal certificates, you can now use `Order.getCertificate()` instead of `Order.getAutoRenewalCertificate()` to retrieve the STAR certificate. `Order.getAutoRenewalCertificate()` is marked as deprecated, but still functional. The new method `Order.isAutoRenewalCertificate()` can be used to check if the order resulted in a standard or auto-renewing certificate.
|
||||||
|
|
Loading…
Reference in New Issue