Review and extend JavaDocs

pull/140/head
Richard Körber 2023-04-29 14:48:56 +02:00
parent 41bc574f75
commit 09a72d606b
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
56 changed files with 429 additions and 182 deletions

View File

@ -12,6 +12,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This is the main module of the acme4j client.
*/
module org.shredzone.acme4j { module org.shredzone.acme4j {
requires static com.github.spotbugs.annotations; requires static com.github.spotbugs.annotations;
requires java.net.http; requires java.net.http;

View File

@ -37,7 +37,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Represents 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 {
private static final long serialVersionUID = 7042863483428051319L; private static final long serialVersionUID = 7042863483428051319L;
@ -65,7 +65,9 @@ public class Account extends AcmeJsonResource {
} }
/** /**
* List of contact addresses (emails, phone numbers etc). * List of registered contact addresses (emails, phone numbers etc).
* <p>
* This list is unmodifiable. Use {@link #modify()} to change the contacts.
*/ */
public List<URI> getContacts() { public List<URI> getContacts() {
return getJSON().get(KEY_CONTACT) return getJSON().get(KEY_CONTACT)
@ -110,20 +112,20 @@ public class Account extends AcmeJsonResource {
} }
/** /**
* Returns an {@link Iterator} of all {@link Order} belonging to this {@link Account}. * Returns an {@link Iterator} of all {@link Order} belonging to this
* {@link Account}.
* <p> * <p>
* Using the iterator will initiate one or more requests to the ACME server. * Using the iterator will initiate one or more requests to the ACME server.
* *
* @return {@link Iterator} instance that returns {@link Order} objects in no specific * @return {@link Iterator} instance that returns {@link Order} objects in no specific
* order. {@link Iterator#hasNext()} and {@link Iterator#next()} may throw * sorting order. {@link Iterator#hasNext()} and {@link Iterator#next()} may throw
* {@link AcmeProtocolException} if a batch of authorization URIs could not be * {@link AcmeProtocolException} if a batch of authorization URIs could not be fetched
* fetched from the server. Each {@link Iterator} instance may provide the * from the server.
* {@link Order} objects in a different order.
*/ */
public Iterator<Order> getOrders() { public Iterator<Order> getOrders() {
var ordersUrl = getJSON().get(KEY_ORDERS).optional().map(Value::asURL); var ordersUrl = getJSON().get(KEY_ORDERS).optional().map(Value::asURL);
if (ordersUrl.isEmpty()) { if (ordersUrl.isEmpty()) {
// Let's Encrypt does not provide this field at the moment although it's required. // Let's Encrypt does not provide this field at the moment, although it's required.
// See https://github.com/letsencrypt/boulder/issues/3335 // See https://github.com/letsencrypt/boulder/issues/3335
throw new AcmeProtocolException("This ACME server does not support getOrders()"); throw new AcmeProtocolException("This ACME server does not support getOrders()");
} }
@ -209,8 +211,8 @@ public class Account extends AcmeJsonResource {
/** /**
* Changes the {@link KeyPair} associated with the account. * Changes the {@link KeyPair} associated with the account.
* <p> * <p>
* After a successful call, the new key pair is used in the bound {@link Session}, * After a successful call, the new key pair is already set in the associated
* and the old key pair can be disposed of. * {@link Login}. The old key pair can be discarded.
* *
* @param newKeyPair * @param newKeyPair
* new {@link KeyPair} to be used for identifying this account * new {@link KeyPair} to be used for identifying this account
@ -267,7 +269,7 @@ public class Account extends AcmeJsonResource {
} }
/** /**
* Editable {@link Account}. * Provides editable properties of an {@link Account}.
*/ */
public class EditableAccount { public class EditableAccount {
private final List<URI> editContacts = new ArrayList<>(); private final List<URI> editContacts = new ArrayList<>();
@ -279,6 +281,10 @@ public class Account extends AcmeJsonResource {
/** /**
* Returns the list of all contact URIs for modification. Use the {@link List} * Returns the list of all contact URIs for modification. Use the {@link List}
* methods to modify the contact list. * methods to modify the contact list.
* <p>
* The modified list is not validated. If you change entries, you have to make
* sure that they are valid according to the RFC. It is recommended to use
* the {@code addContact()} methods below to add new contacts to the list.
*/ */
public List<URI> getContacts() { public List<URI> getContacts() {
return editContacts; return editContacts;
@ -314,8 +320,8 @@ public class Account extends AcmeJsonResource {
/** /**
* Adds a new Contact email to the account. * Adds a new Contact email to the account.
* <p> * <p>
* This is a convenience call for {@link #addContact(String)} hat doesn't * This is a convenience call for {@link #addContact(String)} that doesn't
* require from you attach "mailto" scheme before email address. * require to prepend the email address with the "mailto" scheme.
* *
* @param email * @param email
* Contact email without "mailto" scheme (e.g. test@gmail.com) * Contact email without "mailto" scheme (e.g. test@gmail.com)

View File

@ -34,7 +34,21 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A builder for registering a new account. * A builder for registering a new account with the CA.
* <p>
* You need to create a new key pair and set it via {@link #useKeyPair(KeyPair)}. Your
* account will be identified by the public part of that key pair, so make sure to store
* it safely! There is no automatic way to regain access to your account if the key pair
* is lost.
* <p>
* Depending on the CA you register with, you might need to give additional information.
* <ul>
* <li>You might need to agree to the terms of service via
* {@link #agreeToTermsOfService()}.</li>
* <li>You might need to give at least one contact URI.</li>
* <li>You might need to provide a key identifier (e.g. your customer number) and
* a shared secret via {@link #withKeyIdentifier(String, SecretKey)}.</li>
* </ul>
*/ */
public class AccountBuilder { public class AccountBuilder {
private static final Logger LOG = LoggerFactory.getLogger(AccountBuilder.class); private static final Logger LOG = LoggerFactory.getLogger(AccountBuilder.class);
@ -48,6 +62,9 @@ public class AccountBuilder {
/** /**
* Add a contact URI to the list of contacts. * Add a contact URI to the list of contacts.
* <p>
* A contact URI may be e.g. an email address or a phone number. It depends on the CA
* what kind of contact URIs are accepted, and how many must be provided as minimum.
* *
* @param contact * @param contact
* Contact URI * Contact URI
@ -66,9 +83,9 @@ public class AccountBuilder {
* *
* @param contact * @param contact
* Contact URI as string * Contact URI as string
* @return itself
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if there is a syntax error in the URI string * if there is a syntax error in the URI string
* @return itself
*/ */
public AccountBuilder addContact(String contact) { public AccountBuilder addContact(String contact) {
addContact(URI.create(contact)); addContact(URI.create(contact));
@ -76,16 +93,16 @@ public class AccountBuilder {
} }
/** /**
* Add a email address to the list of contacts. * Add an email address to the list of contacts.
* <p> * <p>
* This is a convenience call for {@link #addContact(String)} that doesn't * This is a convenience call for {@link #addContact(String)} that doesn't require
* require from you attach "mailto" scheme before email address. * to prepend the "mailto" scheme to an email address.
* *
* @param email * @param email
* Contact email without "mailto" scheme (e.g. test@gmail.com) * Contact email without "mailto" scheme (e.g. test@gmail.com)
* @return itself
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if there is a syntax error in the URI string * if there is a syntax error in the URI string
* @return itself
*/ */
public AccountBuilder addEmail(String email) { public AccountBuilder addEmail(String email) {
addContact("mailto:" + email); addContact("mailto:" + email);
@ -93,7 +110,12 @@ public class AccountBuilder {
} }
/** /**
* Signals that the user agrees to the terms of service. * Documents that the user has agreed to the terms of service.
* <p>
* If the CA requires the user to agree to the terms of service, it is your
* responsibility to present them to the user, and actively ask for their agreement. A
* link to the terms of service is provided via
* {@code session.getMetadata().getTermsOfService()}.
* *
* @return itself * @return itself
*/ */
@ -104,8 +126,13 @@ public class AccountBuilder {
/** /**
* Signals that only an existing account should be returned. The server will not * Signals that only an existing account should be returned. The server will not
* create a new account if the key is not known. This is useful if you only have your * create a new account if the key is not known.
* account's key pair available, but not your account's location URL. * <p>
* If you have lost your account's location URL, but still have your account's key
* pair, you can register your account again with the same key, and use
* {@link #onlyExisting()} to make sure that your existing account is returned. If
* your key is unknown to the server, an error is thrown once the account is to be
* created.
* *
* @return itself * @return itself
*/ */
@ -116,6 +143,12 @@ public class AccountBuilder {
/** /**
* Sets the {@link KeyPair} to be used for this account. * Sets the {@link KeyPair} to be used for this account.
* <p>
* Only the public key of the pair is sent to the server for registration. acme4j will
* never send the private key part.
* <p>
* Make sure to store your key pair safely after registration! There is no automatic
* way to regain access to your account if the key pair is lost.
* *
* @param keyPair * @param keyPair
* Account's {@link KeyPair} * Account's {@link KeyPair}
@ -128,13 +161,16 @@ public class AccountBuilder {
/** /**
* Sets a Key Identifier and MAC key provided by the CA. Use this if your CA requires * Sets a Key Identifier and MAC key provided by the CA. Use this if your CA requires
* an individual account identification, e.g. your customer number. * an individual account identification (e.g. your customer number) and a shared
* secret for registration. See the documentation of your CA about how to retrieve the
* key identifier and MAC key.
* *
* @param kid * @param kid
* Key Identifier * Key Identifier
* @param macKey * @param macKey
* MAC key * MAC key
* @return itself * @return itself
* @see #withKeyIdentifier(String, String)
*/ */
public AccountBuilder withKeyIdentifier(String kid, SecretKey macKey) { public AccountBuilder withKeyIdentifier(String kid, SecretKey macKey) {
if (kid != null && kid.isEmpty()) { if (kid != null && kid.isEmpty()) {
@ -147,13 +183,20 @@ public class AccountBuilder {
/** /**
* Sets a Key Identifier and MAC key provided by the CA. Use this if your CA requires * Sets a Key Identifier and MAC key provided by the CA. Use this if your CA requires
* an individual account identification, e.g. your customer number. * an individual account identification (e.g. your customer number) and a shared
* secret for registration. See the documentation of your CA about how to retrieve the
* key identifier and MAC key.
* <p>
* This is a convenience call of {@link #withKeyIdentifier(String, SecretKey)} that
* accepts a base64url encoded MAC key, so both parameters can be passed in as
* strings.
* *
* @param kid * @param kid
* Key Identifier * Key Identifier
* @param encodedMacKey * @param encodedMacKey
* Base64url encoded MAC key. It will be decoded for your convenience. * Base64url encoded MAC key.
* @return itself * @return itself
* @see #withKeyIdentifier(String, SecretKey)
*/ */
public AccountBuilder withKeyIdentifier(String kid, String encodedMacKey) { public AccountBuilder withKeyIdentifier(String kid, String encodedMacKey) {
var encodedKey = AcmeUtils.base64UrlDecode(requireNonNull(encodedMacKey, "encodedMacKey")); var encodedKey = AcmeUtils.base64UrlDecode(requireNonNull(encodedMacKey, "encodedMacKey"));
@ -162,10 +205,14 @@ public class AccountBuilder {
/** /**
* Creates a new account. * Creates a new account.
* <p>
* Use this method to finally create your account with the given parameters. Do not
* use the {@link AccountBuilder} after invoking this method.
* *
* @param session * @param session
* {@link Session} to be used for registration * {@link Session} to be used for registration
* @return {@link Account} referring to the new account * @return {@link Account} referring to the new account
* @see #createLogin(Session)
*/ */
public Account create(Session session) throws AcmeException { public Account create(Session session) throws AcmeException {
return createLogin(session).getAccount(); return createLogin(session).getAccount();
@ -174,7 +221,8 @@ public class AccountBuilder {
/** /**
* Creates a new account. * Creates a new account.
* <p> * <p>
* This method returns a ready to use {@link Login} for the new {@link Account}. * This method is identical to {@link #create(Session)}, but returns a {@link Login}
* that is ready to be used.
* *
* @param session * @param session
* {@link Session} to be used for registration * {@link Session} to be used for registration

View File

@ -25,7 +25,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* An ACME resource that stores its state in a JSON structure. * An extension of {@link AcmeResource} that also contains the current state of a resource
* as JSON document. If the current state is not present, this class takes care of
* fetching it from the server if necessary.
*/ */
public abstract class AcmeJsonResource extends AcmeResource { public abstract class AcmeJsonResource extends AcmeResource {
private static final long serialVersionUID = -5060364275766082345L; private static final long serialVersionUID = -5060364275766082345L;
@ -53,6 +55,9 @@ public abstract class AcmeJsonResource extends AcmeResource {
* This method can be used to read proprietary data from the resources. * This method can be used to read proprietary data from the resources.
* *
* @return Resource data, as {@link JSON}. * @return Resource data, as {@link JSON}.
* @throws AcmeLazyLoadingException
* if an {@link AcmeException} occured while fetching the current state from
* the server.
*/ */
public JSON getJSON() { public JSON getJSON() {
if (data == null) { if (data == null) {

View File

@ -20,7 +20,12 @@ import java.util.Objects;
import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.Nullable;
/** /**
* A generic ACME resource. * This is the root class of all ACME resources (like accounts, orders, certificates).
* Every resource is identified by its location URL.
* <p>
* This class also takes care for proper serialization and de-serialization of the
* resource. After de-serialization, the resource must be bound to a {@link Login} again,
* using {@link #rebind(Login)}.
*/ */
public abstract class AcmeResource implements Serializable { public abstract class AcmeResource implements Serializable {
private static final long serialVersionUID = -7930580802257379731L; private static final long serialVersionUID = -7930580802257379731L;

View File

@ -37,10 +37,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Represents a certificate and its certificate chain. * Represents an issued certificate and its certificate chain.
* <p> * <p>
* Note that a certificate is immutable once it is issued. For renewal, a new certificate * A certificate is immutable once it is issued. For renewal, a new certificate must be
* must be ordered. * ordered.
*/ */
public class Certificate extends AcmeResource { public class Certificate extends AcmeResource {
private static final long serialVersionUID = 7381527770159084201L; private static final long serialVersionUID = 7381527770159084201L;
@ -56,9 +56,9 @@ public class Certificate extends AcmeResource {
/** /**
* Downloads the certificate chain. * Downloads the certificate chain.
* <p> * <p>
* The certificate is downloaded lazily by the other methods. So usually there is no * The certificate is downloaded lazily by the other methods. Usually there is no need
* need to invoke this method, unless the download is to be enforced. If the * to invoke this method, unless the download is to be enforced. If the certificate
* certificate has been downloaded already, nothing will happen. * has been downloaded already, nothing will happen.
* *
* @throws AcmeException * @throws AcmeException
* if the certificate could not be downloaded * if the certificate could not be downloaded
@ -125,7 +125,7 @@ public class Certificate extends AcmeResource {
/** /**
* Writes the certificate to the given writer. It is written in PEM format, with the * Writes the certificate to the given writer. It is written in PEM format, with the
* end-entity cert coming first, followed by the intermediate ceritificates. * end-entity cert coming first, followed by the intermediate certificates.
* *
* @param out * @param out
* {@link Writer} to write to. The writer is not closed after use. * {@link Writer} to write to. The writer is not closed after use.
@ -154,23 +154,28 @@ public class Certificate extends AcmeResource {
* {@link RevocationReason} stating the reason of the revocation that is * {@link RevocationReason} stating the reason of the revocation that is
* used when generating OCSP responses and CRLs. {@code null} to give no * used when generating OCSP responses and CRLs. {@code null} to give no
* reason. * reason.
* @see #revoke(Login, X509Certificate, RevocationReason)
* @see #revoke(Session, KeyPair, X509Certificate, RevocationReason)
*/ */
public void revoke(@Nullable RevocationReason reason) throws AcmeException { public void revoke(@Nullable RevocationReason reason) throws AcmeException {
revoke(getLogin(), getCertificate(), reason); revoke(getLogin(), getCertificate(), reason);
} }
/** /**
* Revoke a certificate. This call is meant to be used for revoking certificates if * Revoke a certificate.
* only the account's key pair and the certificate itself is available. * <p>
* Use this method if the certificate's location is unknown, so you cannot regenerate
* a {@link Certificate} instance. This method requires a {@link Login} to your
* account and the issued certificate.
* *
* @param login * @param login
* {@link Login} to the account * {@link Login} to the account
* @param cert * @param cert
* The {@link X509Certificate} to be revoked * The {@link X509Certificate} to be revoked
* @param reason * @param reason
* {@link RevocationReason} stating the reason of the revocation that is * {@link RevocationReason} stating the reason of the revocation that is used
* used when generating OCSP responses and CRLs. {@code null} to give no * when generating OCSP responses and CRLs. {@code null} to give no reason.
* reason. * @see #revoke(Session, KeyPair, X509Certificate, RevocationReason)
* @since 2.6 * @since 2.6
*/ */
public static void revoke(Login login, X509Certificate cert, @Nullable RevocationReason reason) public static void revoke(Login login, X509Certificate cert, @Nullable RevocationReason reason)
@ -195,8 +200,11 @@ public class Certificate extends AcmeResource {
} }
/** /**
* Revoke a certificate. This call is meant to be used for revoking certificates if * Revoke a certificate.
* the account's key pair was lost. * <p>
* Use this method if the key pair of your account was lost (so you are unable to
* login into your account), but you still have the key pair of the affected domain
* and the issued certificate.
* *
* @param session * @param session
* {@link Session} connected to the ACME server * {@link Session} connected to the ACME server
@ -205,9 +213,9 @@ public class Certificate extends AcmeResource {
* @param cert * @param cert
* The {@link X509Certificate} to be revoked * The {@link X509Certificate} to be revoked
* @param reason * @param reason
* {@link RevocationReason} stating the reason of the revocation that is * {@link RevocationReason} stating the reason of the revocation that is used
* used when generating OCSP responses and CRLs. {@code null} to give no * when generating OCSP responses and CRLs. {@code null} to give no reason.
* reason. * @see #revoke(Login, X509Certificate, RevocationReason)
*/ */
public static void revoke(Session session, KeyPair domainKeyPair, X509Certificate cert, public static void revoke(Session session, KeyPair domainKeyPair, X509Certificate cert,
@Nullable RevocationReason reason) throws AcmeException { @Nullable RevocationReason reason) throws AcmeException {

View File

@ -31,7 +31,7 @@ import org.shredzone.acme4j.toolbox.JSONBuilder;
* The ACME protocol only defines the DNS identifier, which identifies a domain name. * The ACME protocol only defines the DNS identifier, which identifies a domain name.
* acme4j also supports IP identifiers. * acme4j also supports IP identifiers.
* <p> * <p>
* CAs may define further, proprietary identifier types. * CAs, and other acme4j modules, may define further, proprietary identifier types.
* *
* @since 2.3 * @since 2.3
*/ */

View File

@ -26,12 +26,22 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON;
/** /**
* A {@link Login} is a {@link Session} that is connected to an {@link Account} at the * A {@link Login} into an account.
* ACME server. It contains the account's {@link KeyPair} and the {@link URL} of the
* account.
* <p> * <p>
* Note that {@link Login} objects are not serializable, as they contain a keypair and * A login is bound to a {@link Session}. However, a {@link Session} can handle multiple
* volatile data. * logins in parallel.
* <p>
* To create a login, you need to specify the location URI of the {@link Account}, and
* need to provide the {@link KeyPair} the account was created with. If the account's
* location URL is unknown, the account can be re-registered with the
* {@link AccountBuilder}, using {@link AccountBuilder#onlyExisting()} to make sure that
* no new account will be created. If the key pair was lost though, there is no automatic
* way to regain access to your account, and you have to contact your CA's support hotline
* for assistance.
* <p>
* Note that {@link Login} objects are intentionally not serializable, as they contain a
* keypair and volatile data. On distributed systems, you can create a {@link Login} to
* the same account for every service instance.
*/ */
public class Login { public class Login {
@ -88,7 +98,8 @@ public class Login {
} }
/** /**
* Creates a new instance of {@link Authorization} and binds it to this login. * Creates a new instance of an existing {@link Authorization} and binds it to this
* login.
* *
* @param location * @param location
* Location of the Authorization * Location of the Authorization
@ -99,7 +110,8 @@ public class Login {
} }
/** /**
* Creates a new instance of {@link Certificate} and binds it to this login. * Creates a new instance of an existing {@link Certificate} and binds it to this
* login.
* *
* @param location * @param location
* Location of the Certificate * Location of the Certificate
@ -110,7 +122,7 @@ public class Login {
} }
/** /**
* Creates a new instance of {@link Order} and binds it to this login. * Creates a new instance of an existing {@link Order} and binds it to this login.
* *
* @param location * @param location
* Location URL of the order * Location URL of the order
@ -121,12 +133,14 @@ public class Login {
} }
/** /**
* Creates a new instance of {@link Challenge} and binds it to this login. * Creates a new instance of an existing {@link Challenge} and binds it to this
* login. Use this method only if the resulting challenge type is unknown.
* *
* @param location * @param location
* Location URL of the challenge * Location URL of the challenge
* @return {@link Challenge} bound to the login * @return {@link Challenge} bound to the login
* @since 2.8 * @since 2.8
* @see #bindChallenge(URL, Class)
*/ */
public Challenge bindChallenge(URL location) { public Challenge bindChallenge(URL location) {
try (var connect = session.connect()) { try (var connect = session.connect()) {
@ -138,7 +152,8 @@ public class Login {
} }
/** /**
* Creates a new instance of a challenge and binds it to this login. * Creates a new instance of an existing {@link Challenge} and binds it to this
* login. Use this method if the resulting challenge type is known.
* *
* @param location * @param location
* Location URL of the challenge * Location URL of the challenge
@ -175,7 +190,8 @@ public class Login {
} }
/** /**
* Sets a different {@link KeyPair}. * Sets a different {@link KeyPair}. The new key pair is only used locally in this
* instance, but is not set on server side!
*/ */
protected void setKeyPair(KeyPair keyPair) { protected void setKeyPair(KeyPair keyPair) {
this.keyPair = Objects.requireNonNull(keyPair, "keyPair"); this.keyPair = Objects.requireNonNull(keyPair, "keyPair");

View File

@ -25,7 +25,7 @@ import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSON.Value; import org.shredzone.acme4j.toolbox.JSON.Value;
/** /**
* Contains metadata related to the provider. * A collection of metadata related to the CA provider.
*/ */
public class Metadata { public class Metadata {
@ -42,7 +42,7 @@ public class Metadata {
} }
/** /**
* Returns an {@link URI} to the current terms of service, or {@code null} if not * Returns an {@link URI} of the current terms of service, or {@code null} if not
* available. * available.
*/ */
@Nullable @Nullable
@ -51,7 +51,7 @@ public class Metadata {
} }
/** /**
* Returns an {@link URL} to a website providing more information about the ACME * Returns an {@link URL} of a website providing more information about the ACME
* server. {@code null} if not available. * server. {@code null} if not available.
*/ */
@Nullable @Nullable
@ -79,7 +79,7 @@ public class Metadata {
} }
/** /**
* Returns whether the CA supports short-term auto renewal of certificates. * Returns whether the CA supports short-term auto-renewal of certificates.
* *
* @since 2.3 * @since 2.3
*/ */
@ -89,8 +89,8 @@ public class Metadata {
/** /**
* Returns the minimum acceptable value for the maximum validity of a certificate * Returns the minimum acceptable value for the maximum validity of a certificate
* before auto renewal. {@code null} if the CA does not support short-term auto * before auto-renewal. {@code null} if the CA does not support short-term
* renewal. * auto-renewal.
* *
* @since 2.3 * @since 2.3
*/ */
@ -105,7 +105,7 @@ public class Metadata {
/** /**
* Returns the maximum delta between auto-renewal end date and auto-renewal start * 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. * date. {@code null} if the CA does not support short-term auto-renewal.
* *
* @since 2.3 * @since 2.3
*/ */

View File

@ -29,7 +29,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Represents a certificate order. * A representation of a certificate order at the CA.
*/ */
public class Order extends AcmeJsonResource { public class Order extends AcmeJsonResource {
private static final long serialVersionUID = 5435808648658292177L; private static final long serialVersionUID = 5435808648658292177L;
@ -50,7 +50,7 @@ public class Order extends AcmeJsonResource {
} }
/** /**
* Returns a {@link Problem} document if the order failed. * Returns a {@link Problem} document with the reason if the order has failed.
*/ */
@Nullable @Nullable
public Problem getError() { public Problem getError() {
@ -58,7 +58,8 @@ public class Order extends AcmeJsonResource {
} }
/** /**
* Gets the expiry date of the authorization, if set by the server. * Gets the expiry date of the authorization, if set by the server, {@code null}
* otherwise.
*/ */
@Nullable @Nullable
public Instant getExpires() { public Instant getExpires() {
@ -66,7 +67,7 @@ public class Order extends AcmeJsonResource {
} }
/** /**
* Gets the list of {@link Identifier} to be ordered. * Gets a list of {@link Identifier} that are connected to this order.
* *
* @since 2.3 * @since 2.3
*/ */
@ -95,7 +96,8 @@ public class Order extends AcmeJsonResource {
} }
/** /**
* Gets the {@link Authorization} required for this order, in no specific order. * Gets the {@link Authorization} that are required to fulfil this order, in no
* specific order.
*/ */
public List<Authorization> getAuthorizations() { public List<Authorization> getAuthorizations() {
var login = getLogin(); var login = getLogin();
@ -148,12 +150,12 @@ public class Order extends AcmeJsonResource {
* {@link #getCertificate()}. * {@link #getCertificate()}.
* <p> * <p>
* Even though the ACME protocol uses the term "finalize an order", this method is * Even though the ACME protocol uses the term "finalize an order", this method is
* called {@link #execute(byte[])} to avoid confusion with the general * called {@link #execute(byte[])} to avoid confusion with the problematic
* {@link Object#finalize()} method. * {@link Object#finalize()} method.
* *
* @param csr * @param csr
* CSR containing the parameters for the certificate being requested, in * CSR containing the parameters for the certificate being requested, in DER
* DER format * format
*/ */
public void execute(byte[] csr) throws AcmeException { public void execute(byte[] csr) throws AcmeException {
LOG.debug("finalize"); LOG.debug("finalize");
@ -231,7 +233,7 @@ public class Order extends AcmeJsonResource {
} }
/** /**
* Returns the predate period of each certificate, or {@code null}. * Returns the pre-date period of each certificate, or {@code null}.
* *
* @since 2.7 * @since 2.7
*/ */

View File

@ -31,7 +31,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A builder for a new {@link Order} object. * Start a new certificate {@link Order}.
* <p>
* Use {@link Account#newOrder()} to create a new {@link OrderBuilder} instance.
*/ */
public class OrderBuilder { public class OrderBuilder {
private static final Logger LOG = LoggerFactory.getLogger(OrderBuilder.class); private static final Logger LOG = LoggerFactory.getLogger(OrderBuilder.class);
@ -155,18 +157,17 @@ public class OrderBuilder {
} }
/** /**
* Enables short-term automatic renewal of the certificate. Must be supported by the * Enables short-term automatic renewal of the certificate, if supported by the CA.
* CA.
* <p> * <p>
* Automatic renewals cannot be combined with {@link #notBefore(Instant)} or {@link * Automatic renewals cannot be combined with {@link #notBefore(Instant)} or
* #notAfter(Instant)}. * {@link #notAfter(Instant)}.
* *
* @return itself * @return itself
* @since 2.3 * @since 2.3
*/ */
public OrderBuilder autoRenewal() { public OrderBuilder autoRenewal() {
if (notBefore != null || notAfter != null) { if (notBefore != null || notAfter != null) {
throw new IllegalArgumentException("cannot combine notBefore/notAfter with autoRenewalOr"); throw new IllegalArgumentException("cannot combine notBefore/notAfter with autoRenewal");
} }
this.autoRenewal = true; this.autoRenewal = true;
return this; return this;
@ -249,7 +250,8 @@ public class OrderBuilder {
* order for this option to work. * order for this option to work.
* <p> * <p>
* This option is only needed if you plan to fetch the STAR certificate via other * This option is only needed if you plan to fetch the STAR certificate via other
* means than by using acme4j. * means than by using acme4j. acme4j is fetching certificates via POST-as-GET
* request.
* <p> * <p>
* Implies {@link #autoRenewal()}. * Implies {@link #autoRenewal()}.
* *

View File

@ -27,7 +27,8 @@ import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSON.Value; import org.shredzone.acme4j.toolbox.JSON.Value;
/** /**
* Represents a JSON Problem. * A JSON problem. It contains further, machine- and human-readable details about the
* reason of an error or failure.
* *
* @see <a href="https://tools.ietf.org/html/rfc7807">RFC 7807</a> * @see <a href="https://tools.ietf.org/html/rfc7807">RFC 7807</a>
*/ */
@ -89,7 +90,7 @@ public class Problem implements Serializable {
} }
/** /**
* Returns an URI that identifies the specific occurence of the problem. It is always * Returns a URI that identifies the specific occurence of the problem. It is always
* an absolute URI. * an absolute URI.
*/ */
@Nullable @Nullable
@ -131,7 +132,7 @@ public class Problem implements Serializable {
} }
/** /**
* Returns the problem as {@link JSON} object, to access other fields. * Returns the problem as {@link JSON} object, to access other, non-standard fields.
* *
* @return Problem as {@link JSON} object * @return Problem as {@link JSON} object
*/ */

View File

@ -18,7 +18,7 @@ import java.util.Arrays;
import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.Nullable;
/** /**
* Enumeration of revocation reasons. * An enumeration of revocation reasons.
* *
* @see <a href="https://tools.ietf.org/html/rfc5280#section-5.3.1">RFC 5280 Section * @see <a href="https://tools.ietf.org/html/rfc5280#section-5.3.1">RFC 5280 Section
* 5.3.1</a> * 5.3.1</a>

View File

@ -37,7 +37,12 @@ import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSON.Value; import org.shredzone.acme4j.toolbox.JSON.Value;
/** /**
* A session stores the ACME server URI. It also tracks communication parameters. * A {@link Session} tracks the entire communication with a CA.
* <p>
* To create a session instance, use its constructor. It requires the URI of the ACME
* server to connect to. This can be the location of the CA's directory (via {@code http}
* or {@code https} protocol), or a special URI (via {@code acme} protocol). See the
* documentation about valid URIs.
*/ */
public class Session { public class Session {
@ -59,7 +64,11 @@ public class Session {
* Creates a new {@link Session}. * Creates a new {@link Session}.
* *
* @param serverUri * @param serverUri
* URI string of the ACME server * URI string of the ACME server to connect to. This is either the location of
* the CA's ACME directory (using {@code http} or {@code https} protocol), or
* a special URI (using the {@code acme} protocol).
* @throws IllegalArgumentException
* if no ACME provider was found for the server URI.
*/ */
public Session(String serverUri) { public Session(String serverUri) {
this(URI.create(serverUri)); this(URI.create(serverUri));
@ -69,7 +78,9 @@ public class Session {
* Creates a new {@link Session}. * Creates a new {@link Session}.
* *
* @param serverUri * @param serverUri
* {@link URI} of the ACME server * {@link URI} of the ACME server to connect to. This is either the location
* of the CA's ACME directory (using {@code http} or {@code https} protocol),
* or a special URI (using the {@code acme} protocol).
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if no ACME provider was found for the server URI. * if no ACME provider was found for the server URI.
*/ */
@ -96,7 +107,7 @@ public class Session {
/** /**
* Creates a new {@link Session} using the given {@link AcmeProvider}. * Creates a new {@link Session} using the given {@link AcmeProvider}.
* <p> * <p>
* This constructor should only be used for testing purposes. * This constructor is only to be used for testing purposes.
* *
* @param serverUri * @param serverUri
* {@link URI} of the ACME server * {@link URI} of the ACME server
@ -134,7 +145,8 @@ public class Session {
} }
/** /**
* Gets the last base64 encoded nonce, or {@code null} if the session is new. * Gets the last base64 encoded nonce, or {@code null} if the session is new. This
* method is mainly for internal use.
*/ */
@Nullable @Nullable
public String getNonce() { public String getNonce() {
@ -142,7 +154,8 @@ public class Session {
} }
/** /**
* Sets the base64 encoded nonce received by the server. * Sets the base64 encoded nonce received by the server. This method is mainly for
* internal use.
*/ */
public void setNonce(@Nullable String nonce) { public void setNonce(@Nullable String nonce) {
this.nonce = nonce; this.nonce = nonce;
@ -160,8 +173,8 @@ public class Session {
/** /**
* Sets the locale used in this session. The locale is passed to the server as * Sets the locale used in this session. The locale is passed to the server as
* Accept-Language header. The server <em>may</em> respond with localized messages. * Accept-Language header. The server <em>may</em> respond with localized messages.
* The default is the system's language. If set to {@code null}, no special language * The default is the system's language. If set to {@code null}, any language will be
* is selected. * accepted.
*/ */
public void setLocale(@Nullable Locale locale) { public void setLocale(@Nullable Locale locale) {
this.locale = locale; this.locale = locale;
@ -169,7 +182,8 @@ public class Session {
} }
/** /**
* Gets an Accept-Language header value that matches the current locale. * Gets an Accept-Language header value that matches the current locale. This method
* is mainly for internal use.
* *
* @since 3.0.0 * @since 3.0.0
*/ */
@ -207,7 +221,7 @@ public class Session {
/** /**
* Gets the {@link URL} of the given {@link Resource}. This may involve connecting to * Gets the {@link URL} of the given {@link Resource}. This may involve connecting to
* the server and getting a directory. The result is cached. * the server and fetching the directory. The result is cached.
* *
* @param resource * @param resource
* {@link Resource} to get the {@link URL} of * {@link Resource} to get the {@link URL} of
@ -226,7 +240,7 @@ public class Session {
/** /**
* Gets the metadata of the provider's directory. This may involve connecting to the * Gets the metadata of the provider's directory. This may involve connecting to the
* server and getting a directory. The result is cached. * server and fetching the directory. The result is cached.
* *
* @return {@link Metadata}. May contain no data, but is never {@code null}. * @return {@link Metadata}. May contain no data, but is never {@code null}.
*/ */
@ -287,8 +301,8 @@ public class Session {
} }
/** /**
* Returns {@code true} if a directory is available. Should only be invoked by {@link * Returns {@code true} if a copy of the directory is present in a local cache. It is
* AcmeProvider} implementations. * not evaluated if the cached copy has expired though.
* *
* @return {@code true} if a directory is available. * @return {@code true} if a directory is available.
* @since 2.10 * @since 2.10

View File

@ -16,7 +16,7 @@ package org.shredzone.acme4j;
import java.util.Arrays; import java.util.Arrays;
/** /**
* Status codes of challenges and authorizations. * An enumeration of status codes of challenges and authorizations.
*/ */
public enum Status { public enum Status {

View File

@ -33,9 +33,9 @@ import org.slf4j.LoggerFactory;
* implementations, but it is also used if the ACME server offers a proprietary challenge * implementations, but it is also used if the ACME server offers a proprietary challenge
* that is unknown to acme4j. * that is unknown to acme4j.
* <p> * <p>
* Subclasses must override {@link Challenge#acceptable(String)} so it only accepts the * Subclasses must override {@link Challenge#acceptable(String)} so it only accepts its
* own type. {@link Challenge#prepareResponse(JSONBuilder)} should be overridden to put * own type. {@link Challenge#prepareResponse(JSONBuilder)} can be overridden to put all
* all required data to the response. * required data to the challenge response.
*/ */
public class Challenge extends AcmeJsonResource { public class Challenge extends AcmeJsonResource {
private static final long serialVersionUID = 2338794776848388099L; private static final long serialVersionUID = 2338794776848388099L;
@ -72,6 +72,9 @@ public class Challenge extends AcmeJsonResource {
* <p> * <p>
* Possible values are: {@link Status#PENDING}, {@link Status#PROCESSING}, * Possible values are: {@link Status#PENDING}, {@link Status#PROCESSING},
* {@link Status#VALID}, {@link Status#INVALID}. * {@link Status#VALID}, {@link Status#INVALID}.
* <p>
* A challenge is only completed when it reaches either status {@link Status#VALID} or
* {@link Status#INVALID}.
*/ */
public Status getStatus() { public Status getStatus() {
return getJSON().get(KEY_STATUS).asStatus(); return getJSON().get(KEY_STATUS).asStatus();
@ -98,7 +101,10 @@ public class Challenge extends AcmeJsonResource {
} }
/** /**
* Exports the response state, as preparation for triggering the challenge. * Prepares the response message for triggering the challenge. Subclasses can add
* fields to the {@link JSONBuilder} as required by the challenge. Implementations of
* subclasses should make sure that {@link #prepareResponse(JSONBuilder)} of the
* superclass is invoked.
* *
* @param response * @param response
* {@link JSONBuilder} to write the response to * {@link JSONBuilder} to write the response to
@ -108,7 +114,9 @@ public class Challenge extends AcmeJsonResource {
} }
/** /**
* Checks if the type is acceptable to this challenge. * Checks if the type is acceptable to this challenge. This generic class only checks
* if the type is not blank. Subclasses should instead check if the given type matches
* expected challenge type.
* *
* @param type * @param type
* Type to check * Type to check
@ -138,6 +146,16 @@ public class Challenge extends AcmeJsonResource {
* Triggers this {@link Challenge}. The ACME server is requested to validate the * Triggers this {@link Challenge}. The ACME server is requested to validate the
* response. Note that the validation is performed asynchronously by the ACME server. * response. Note that the validation is performed asynchronously by the ACME server.
* <p> * <p>
* After a challenge is triggered, it changes to {@link Status#PENDING}. As soon as
* validation takes place, it changes to {@link Status#PROCESSING}. After validation
* the status changes to {@link Status#VALID} or {@link Status#INVALID}, depending on
* the outcome of the validation.
* <p>
* If the challenge requires a resource to be set on your side (e.g. a DNS record or
* an HTTP file), it <em>must</em> be reachable from public before {@link #trigger()}
* is invoked, and <em>must not</em> be taken down until the challenge has reached
* {@link Status#VALID} or {@link Status#INVALID}.
* <p>
* If this method is invoked a second time, the ACME server is requested to retry the * If this method is invoked a second time, the ACME server is requested to retry the
* validation. This can be useful if the client state has changed, for example after a * validation. This can be useful if the client state has changed, for example after a
* firewall rule has been updated. * firewall rule has been updated.

View File

@ -21,7 +21,8 @@ import org.shredzone.acme4j.Login;
import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON;
/** /**
* Implements the {@value TYPE} challenge. * Implements the {@value TYPE} challenge. It requires a specific DNS record for domain
* validation. See the acme4j documentation for a detailed explanation.
*/ */
public class Dns01Challenge extends TokenChallenge { public class Dns01Challenge extends TokenChallenge {
private static final long serialVersionUID = 6964687027713533075L; private static final long serialVersionUID = 6964687027713533075L;

View File

@ -17,7 +17,9 @@ import org.shredzone.acme4j.Login;
import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON;
/** /**
* Implements the {@value TYPE} challenge. * Implements the {@value TYPE} challenge. For domain validation, it requires a specific
* file that can be retrieved from the domain via HTTP. See the acme4j documentation for a
* detailed explanation.
*/ */
public class Http01Challenge extends TokenChallenge { public class Http01Challenge extends TokenChallenge {
private static final long serialVersionUID = 3322211185872544605L; private static final long serialVersionUID = 3322211185872544605L;

View File

@ -19,7 +19,9 @@ import org.shredzone.acme4j.Login;
import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON;
/** /**
* Implements the {@value TYPE} challenge. * Implements the {@value TYPE} challenge. It requires a specific certificate that can be
* retrieved from the domain via HTTPS request. See the acme4j documentation for a
* detailed explanation.
* *
* @since 2.1 * @since 2.1
*/ */

View File

@ -22,8 +22,8 @@ import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JoseUtils; import org.shredzone.acme4j.toolbox.JoseUtils;
/** /**
* An extension of {@link Challenge} that handles challenges with a {@code token} and * A generic extension of {@link Challenge} that handles challenges with a {@code token}
* {@code keyAuthorization}. * and {@code keyAuthorization}.
*/ */
public class TokenChallenge extends Challenge { public class TokenChallenge extends Challenge {
private static final long serialVersionUID = 1634133407432681800L; private static final long serialVersionUID = 1634133407432681800L;

View File

@ -12,6 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains all standard challenges, as well as base classes for challenges
* that are proprietary to a CA.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -32,6 +32,10 @@ import org.shredzone.acme4j.toolbox.JSONBuilder;
/** /**
* Connects to the ACME server and offers different methods for invoking the API. * Connects to the ACME server and offers different methods for invoking the API.
* <p>
* The actual way of communicating with the ACME server is intentionally left open.
* Implementations could use other means than HTTP, or could mock the communication for
* unit testing.
*/ */
public interface Connection extends AutoCloseable { public interface Connection extends AutoCloseable {
@ -132,16 +136,14 @@ public interface Connection extends AutoCloseable {
throws AcmeException; throws AcmeException;
/** /**
* Reads a server response as JSON data. * Reads a server response as JSON object.
* *
* @return The JSON response. * @return The JSON response.
* @throws AcmeProtocolException
* if the JSON response was empty.
*/ */
JSON readJsonResponse() throws AcmeException; JSON readJsonResponse() throws AcmeException;
/** /**
* Reads a certificate and its issuers. * Reads a certificate and its chain of issuers.
* *
* @return List of X.509 certificate and chain that was read. * @return List of X.509 certificate and chain that was read.
*/ */
@ -193,7 +195,8 @@ public interface Connection extends AutoCloseable {
Optional<ZonedDateTime> getExpiration(); Optional<ZonedDateTime> getExpiration();
/** /**
* Gets one or more relation links from the header. The result is expected to be an URL. * Gets one or more relation links from the header. The result is expected to be a
* URL.
* <p> * <p>
* Relative links are resolved against the last request's URL. * Relative links are resolved against the last request's URL.
* *

View File

@ -63,7 +63,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Default implementation of {@link Connection}. * Default implementation of {@link Connection}. It communicates with the ACME server via
* HTTP, with a client that is provided by the given {@link HttpConnector}.
*/ */
public class DefaultConnection implements Connection { public class DefaultConnection implements Connection {
private static final Logger LOG = LoggerFactory.getLogger(DefaultConnection.class); private static final Logger LOG = LoggerFactory.getLogger(DefaultConnection.class);

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j.connector; package org.shredzone.acme4j.connector;
/** /**
* Enumeration of resources. * Enumeration of standard resources, and their key name in the CA's directory.
*/ */
public enum Resource { public enum Resource {
@ -32,9 +32,9 @@ public enum Resource {
} }
/** /**
* Returns the resource path. * Returns the key name in the directory.
* *
* @return resource path * @return key name
*/ */
public String path() { public String path() {
return path; return path;

View File

@ -12,6 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains internal classes for connection to the CA, and for handling the
* requests and responses.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j.exception; package org.shredzone.acme4j.exception;
/** /**
* A generic ACME exception. * The root class of all checked acme4j exceptions.
*/ */
public class AcmeException extends Exception { public class AcmeException extends Exception {
private static final long serialVersionUID = -2935088954705632025L; private static final long serialVersionUID = -2935088954705632025L;

View File

@ -20,8 +20,10 @@ import java.net.URL;
import org.shredzone.acme4j.AcmeResource; import org.shredzone.acme4j.AcmeResource;
/** /**
* This runtime exception is thrown when an {@link AcmeException} occured while trying to * A runtime exception that is thrown when an {@link AcmeException} occured while trying
* lazy-load a resource from the ACME server. * to lazy-load a resource from the ACME server. It contains the original cause of the
* exception and a reference to the resource that could not be lazy-loaded. It is usually
* thrown by getter methods, so the API is not polluted with checked exceptions.
*/ */
public class AcmeLazyLoadingException extends RuntimeException { public class AcmeLazyLoadingException extends RuntimeException {
private static final long serialVersionUID = 1000353433913721901L; private static final long serialVersionUID = 1000353433913721901L;
@ -43,6 +45,8 @@ public class AcmeLazyLoadingException extends RuntimeException {
/** /**
* Creates a new {@link AcmeLazyLoadingException}. * Creates a new {@link AcmeLazyLoadingException}.
* <p>
* This constructor is used if there is no actual instance of the resource.
* *
* @param type * @param type
* {@link AcmeResource} type to be loaded * {@link AcmeResource} type to be loaded

View File

@ -16,8 +16,8 @@ package org.shredzone.acme4j.exception;
import java.io.IOException; import java.io.IOException;
/** /**
* This exception is thrown when a network error occured while communicating with the * A general network error has occured while communicating with the server (e.g. network
* server. * timeout).
*/ */
public class AcmeNetworkException extends AcmeException { public class AcmeNetworkException extends AcmeException {
private static final long serialVersionUID = 2054398693543329179L; private static final long serialVersionUID = 2054398693543329179L;

View File

@ -14,8 +14,9 @@
package org.shredzone.acme4j.exception; package org.shredzone.acme4j.exception;
/** /**
* This runtime exception is thrown on ACME protocol errors that should not occur. For * A runtime exception that is thrown when the response of the server is violating the
* example, this exception is thrown when a server response could not be parsed. * 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.
*/ */
public class AcmeProtocolException extends RuntimeException { public class AcmeProtocolException extends RuntimeException {
private static final long serialVersionUID = 2031203835755725193L; private static final long serialVersionUID = 2031203835755725193L;

View File

@ -22,7 +22,9 @@ import edu.umd.cs.findbugs.annotations.Nullable;
import org.shredzone.acme4j.Problem; import org.shredzone.acme4j.Problem;
/** /**
* An exception that is thrown when a rate limit was exceeded. * A rate limit was exceeded. If provided by the server, it also includes the earliest
* time at which a new attempt will be accepted, and a reference to a document that
* further explains the rate limit that was exceeded.
*/ */
public class AcmeRateLimitedException extends AcmeServerException { public class AcmeRateLimitedException extends AcmeServerException {
private static final long serialVersionUID = 4150484059796413069L; private static final long serialVersionUID = 4150484059796413069L;
@ -36,10 +38,11 @@ public class AcmeRateLimitedException extends AcmeServerException {
* @param problem * @param problem
* {@link Problem} that caused the exception * {@link Problem} that caused the exception
* @param retryAfter * @param retryAfter
* The moment the request is expected to succeed again, may be {@code null} * The instant of time that the request is expected to succeed again, may be
* if not known * {@code null} if not known
* @param documents * @param documents
* URLs pointing to documents about the rate limit that was hit * URLs pointing to documents about the rate limit that was hit, may be
* {@code null} if not known
*/ */
public AcmeRateLimitedException(Problem problem, @Nullable Instant retryAfter, public AcmeRateLimitedException(Problem problem, @Nullable Instant retryAfter,
@Nullable Collection<URL> documents) { @Nullable Collection<URL> documents) {
@ -50,8 +53,8 @@ public class AcmeRateLimitedException extends AcmeServerException {
} }
/** /**
* Returns the moment the request is expected to succeed again. {@code null} if this * Returns the instant of time the request is expected to succeed again. {@code null}
* moment is not known. * if this moment is not known.
*/ */
@Nullable @Nullable
public Instant getRetryAfter() { public Instant getRetryAfter() {

View File

@ -17,8 +17,8 @@ import java.time.Instant;
import java.util.Objects; import java.util.Objects;
/** /**
* This exception is thrown when a server side process has not been completed yet, and the * A server side process has not been completed yet. The server also provides an estimate
* server returned an estimated retry date. * of when the process is expected to complete.
*/ */
public class AcmeRetryAfterException extends AcmeException { public class AcmeRetryAfterException extends AcmeException {
private static final long serialVersionUID = 4461979121063649905L; private static final long serialVersionUID = 4461979121063649905L;
@ -39,7 +39,8 @@ public class AcmeRetryAfterException extends AcmeException {
} }
/** /**
* Returns the retry-after date returned by the server. * Returns the retry-after instant returned by the server. This is only an estimate
* of when a retry attempt might succeed.
*/ */
public Instant getRetryAfter() { public Instant getRetryAfter() {
return retryAfter; return retryAfter;

View File

@ -19,8 +19,11 @@ import java.util.Objects;
import org.shredzone.acme4j.Problem; import org.shredzone.acme4j.Problem;
/** /**
* An exception that is thrown when the ACME server returned an error. It contains * The ACME server returned an error. The exception contains a {@link Problem} document
* further details of the cause. * containing the exact cause of the error.
* <p>
* For some special cases, subclasses of this exception are thrown, so they can be handled
* individually.
*/ */
public class AcmeServerException extends AcmeException { public class AcmeServerException extends AcmeException {
private static final long serialVersionUID = 5971622508467042792L; private static final long serialVersionUID = 5971622508467042792L;

View File

@ -16,8 +16,8 @@ package org.shredzone.acme4j.exception;
import org.shredzone.acme4j.Problem; import org.shredzone.acme4j.Problem;
/** /**
* An exception that is thrown when the client is not authorized. The details will give * The client is not authorized to perform the operation. The {@link Problem} document
* an explanation for the reasons (e.g. "client not on a whitelist"). * will give further details (e.g. "client IP is blocked").
*/ */
public class AcmeUnauthorizedException extends AcmeServerException { public class AcmeUnauthorizedException extends AcmeServerException {
private static final long serialVersionUID = 9064697508262919366L; private static final long serialVersionUID = 9064697508262919366L;

View File

@ -21,7 +21,7 @@ import edu.umd.cs.findbugs.annotations.Nullable;
import org.shredzone.acme4j.Problem; import org.shredzone.acme4j.Problem;
/** /**
* An exception that is thrown when the user is required to take action as indicated. * The user is required to take manual action as indicated.
* <p> * <p>
* Usually this exception is thrown when the terms of service have changed, and the CA * Usually this exception is thrown when the terms of service have changed, and the CA
* requires an agreement to the new terms before proceeding. * requires an agreement to the new terms before proceeding.
@ -37,7 +37,8 @@ public class AcmeUserActionRequiredException extends AcmeServerException {
* @param problem * @param problem
* {@link Problem} that caused the exception * {@link Problem} that caused the exception
* @param tosUri * @param tosUri
* {@link URI} of the terms-of-service document to accept * {@link URI} of the terms-of-service document to accept, may be
* {@code null}
*/ */
public AcmeUserActionRequiredException(Problem problem, @Nullable URI tosUri) { public AcmeUserActionRequiredException(Problem problem, @Nullable URI tosUri) {
super(problem); super(problem);
@ -54,8 +55,8 @@ public class AcmeUserActionRequiredException extends AcmeServerException {
} }
/** /**
* Returns the {@link URL} of a document that gives instructions on the actions to * Returns the {@link URL} of a document that gives instructions on the actions to be
* be taken by a human. * taken by a human.
*/ */
public URL getInstance() { public URL getInstance() {
var instance = getProblem().getInstance(); var instance = getProblem().getInstance();

View File

@ -12,6 +12,16 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains all exceptions that can be thrown by acme4j.
* <p>
* {@link org.shredzone.acme4j.exception.AcmeException} is the root exception, and other
* exceptions are derived from it.
* <p>
* Some methods that do lazy-loading of remote resources may throw a runtime
* {@link org.shredzone.acme4j.exception.AcmeLazyLoadingException} instead, so the API is
* not polluted with checked exceptions on every getter.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,11 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* acme4j is a Java client for the ACME protocol.
* <p>
* See the documentation and the example for how to use this client in your own projects.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -121,7 +121,7 @@ public abstract class AbstractAcmeProvider implements AcmeProvider {
* generic {@link Challenge} or {@link TokenChallenge} instances are created. * generic {@link Challenge} or {@link TokenChallenge} instances are created.
* <p> * <p>
* Custom provider implementations may override this method to provide challenges that * Custom provider implementations may override this method to provide challenges that
* are unique to the provider. * are proprietary to the provider.
*/ */
@Override @Override
public Challenge createChallenge(Login login, JSON data) { public Challenge createChallenge(Login login, JSON data) {

View File

@ -12,6 +12,12 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains the Let's Encrypt
* {@link org.shredzone.acme4j.provider.AcmeProvider}.
*
* @see <a href="https://letsencrypt.org/">Let's Encrypt</a>
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,18 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* Acme Providers are the link between acme4j and the ACME server. They know how to
* connect to their server, and how to set up HTTP connections.
* <p>
* {@link org.shredzone.acme4j.provider.AcmeProvider} is the root interface.
* {@link org.shredzone.acme4j.provider.AbstractAcmeProvider} is an abstract
* implementation of the most elementary methods. Most HTTP based providers will extend
* from {@link org.shredzone.acme4j.provider.GenericAcmeProvider} though.
* <p>
* Provider implementations must be registered with Java's
* {@link java.util.ServiceLoader}.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,12 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains an {@link org.shredzone.acme4j.provider.AcmeProvider} for the
* Pebble test server.
*
* @see <a href="https://github.com/letsencrypt/pebble">Pebble project page</a>
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -33,6 +33,9 @@ import org.slf4j.LoggerFactory;
/** /**
* Utility class that takes care of all the JOSE stuff. * Utility class that takes care of all the JOSE stuff.
* <p>
* Internal class, do not use in your project! The API may change anytime, in a breaking
* manner, and without prior notice.
* *
* @since 2.7 * @since 2.7
*/ */

View File

@ -12,6 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* Internal toolbox. The API of these classes may change anytime, in a breaking manner,
* and without prior notice. It is better not to use them in your project.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This module is an add-on that provides S/MIME certificate features.
*/
module org.shredzone.acme4j.smime { module org.shredzone.acme4j.smime {
requires org.shredzone.acme4j; requires org.shredzone.acme4j;
requires org.shredzone.acme4j.utils; requires org.shredzone.acme4j.utils;

View File

@ -20,7 +20,8 @@ import org.shredzone.acme4j.provider.ChallengeType;
import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON;
/** /**
* Generates {@link EmailReply00Challenge}. * A provider that generates {@link EmailReply00Challenge}. It is registered as Java
* service.
* *
* @since 2.12 * @since 2.12
*/ */

View File

@ -12,6 +12,15 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains the
* {@link org.shredzone.acme4j.smime.challenge.EmailReply00Challenge#TYPE} related acme4j
* {@link org.shredzone.acme4j.challenge.Challenge} implementation.
* <p>
* The {@link org.shredzone.acme4j.smime.challenge.EmailReply00ChallengeProvider} is
* registered as Java service, so acme4j is able to automatically generate
* {@link org.shredzone.acme4j.smime.challenge.EmailReply00Challenge} instances.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains S/MIME CSR related utility classes.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This package contains classes for processing incoming validation emails, and for
* generating outgoing response emails.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -25,12 +25,12 @@ import org.bouncycastle.i18n.LocalizedException;
import org.shredzone.acme4j.exception.AcmeException; import org.shredzone.acme4j.exception.AcmeException;
/** /**
* This exception is thrown when the challenge message is invalid. * This exception is thrown when the challenge email message is invalid.
* <p> * <p>
* If this exception is thrown, the challenge message does not match the actual challenge, * If this exception is thrown, the challenge message does not match the actual challenge
* and <em>must</em> be rejected. * or has other issues. It <em>must</em> be rejected.
* <p> * <p>
* Reasons may be: * Reasons may be (for example):
* <ul> * <ul>
* <li>Unexpected sender address</li> * <li>Unexpected sender address</li>
* <li>Bad S/MIME signature</li> * <li>Bad S/MIME signature</li>

View File

@ -12,6 +12,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* Exceptions that are related to S/MIME signatures.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* An acme4j extension that provides S/MIME certificate features.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,14 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* {@link org.shredzone.acme4j.smime.wrapper.Mail} is a wrapper interface which provides
* access to all relevant headers of the validation email. Usually
* {@link org.shredzone.acme4j.smime.wrapper.SignedMailBuilder} is used for parsing the
* email and validating the signature.
* {@link org.shredzone.acme4j.smime.wrapper.SimpleMail} is a simple implementation that
* should only be used for testing purposes or after an external validation.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)

View File

@ -12,6 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* This module contains a collection of utility classes. All of them require Bouncy Castle
* to be added as security provider.
*/
module org.shredzone.acme4j.utils { module org.shredzone.acme4j.utils {
requires org.shredzone.acme4j; requires org.shredzone.acme4j;

View File

@ -52,8 +52,9 @@ import org.shredzone.acme4j.Identifier;
/** /**
* Generator for a CSR (Certificate Signing Request) suitable for ACME servers. * Generator for a CSR (Certificate Signing Request) suitable for ACME servers.
* <p> * <p>
* Requires {@code Bouncy Castle}. The {@link org.bouncycastle.jce.provider.BouncyCastleProvider} * Requires {@code Bouncy Castle}. The
* must also be added as security provider. * {@link org.bouncycastle.jce.provider.BouncyCastleProvider} must be added as security
* provider.
*/ */
public class CSRBuilder { public class CSRBuilder {
private static final String SIGNATURE_ALG = "SHA256withRSA"; private static final String SIGNATURE_ALG = "SHA256withRSA";

View File

@ -57,7 +57,7 @@ import org.shredzone.acme4j.challenge.TlsAlpn01Challenge;
/** /**
* Utility class offering convenience methods for certificates. * Utility class offering convenience methods for certificates.
* <p> * <p>
* Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module. * Requires {@code Bouncy Castle}.
*/ */
public final class CertificateUtils { public final class CertificateUtils {

View File

@ -33,7 +33,7 @@ import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
/** /**
* Utility class offering convenience methods for {@link KeyPair}. * Utility class offering convenience methods for {@link KeyPair}.
* <p> * <p>
* Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module. * Requires {@code Bouncy Castle}.
*/ */
public class KeyPairUtils { public class KeyPairUtils {

View File

@ -12,6 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/ */
/**
* A collection of utility classes. All of them require Bouncy Castle to be added as
* * security provider.
*/
@ReturnValuesAreNonnullByDefault @ReturnValuesAreNonnullByDefault
@DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForParameters(NonNull.class)
@DefaultAnnotationForFields(NonNull.class) @DefaultAnnotationForFields(NonNull.class)