Review and update documentation

pull/55/head
Richard Körber 2017-08-13 14:16:02 +02:00
parent 5310e25048
commit 0156907773
15 changed files with 215 additions and 292 deletions

View File

@ -31,7 +31,7 @@ URL website = meta.getWebsite();
## Available Providers
In _acme4j_ these providers are available:
The _acme4j_ package contains these providers:
* [Let's Encrypt](./letsencrypt.html)
* [Pebble](./pebble.html)

View File

@ -6,16 +6,11 @@ Web site: [Let's Encrypt](https://letsencrypt.org)
* `acme://letsencrypt.org` - Production server
* `acme://letsencrypt.org/staging` - Testing server
* `acme://letsencrypt.org/v01` - Production server, pinned to API v01
## Features
* Accepts the ACME server certificate of Let's Encrypt even on older Java versions
## Note
* _Let's Encrypt_ diverges from the ACME specifications for various reasons. For this reason, some parts of the _acme4j_ API may not behave as documented. [See here for more details.](https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md)
## Limits
* Registrations per IP: 10 per 3 hours

View File

@ -21,4 +21,4 @@ http://${domain}/.well-known/acme-challenge/${token}
The challenge is completed when the CA was able to download that file and found `content` in it.
Note that the request is sent to port 80 only. There is no way to choose a different port, for security reasons. This is a limitation of the ACME protocol, not of _acme4j_.
> __Note:__ The request is sent to port 80 only. If your domain has multiple IP addresses, the CA randomly selects one of them. There is no way to choose a different port or a fixed IP address.

View File

@ -4,7 +4,7 @@ Challenges are used to prove ownership of a domain.
There are different kind of challenges. The most simple is maybe the HTTP challenge, where a file must be made available at the domain that is to be validated. It is assumed that you control the domain if you are able to publish a given file under a given path.
The CA offers one or more sets of challenges. At least one set has to be completed in order to prove ownership.
The CA offers one or more challenges. One of the challenges must be completed in order to prove ownership.
The ACME specifications define these standard challenges:

View File

@ -2,8 +2,8 @@
The `oob-01` challenge is an "out of band" challenge that is used when there is no automatic way of validating ownership of a domain. The client is instead required to perform actions outside of the ACME protocol.
`OutOfBand01Challenge` implements this challenge. Its `getValidationUrl()` method returns a URL that refers to a web page with further instructions about the actions to be taken.
`OutOfBand01Challenge` implements this challenge. Its `getValidationUrl()` method returns a URL that refers to a web page with further instructions about the actions to be taken by the domain owner.
The challenge must be triggered before the URL is opened in a browser.
The challenge must be triggered _before_ the URL is presented to the domain owner.
Due to the nature of this challenge, it may take a considerable amount of time until its state changes to `VALID`.
> __Note:__ Due to the nature of this challenge, it may take hours or even days until the domain owner finishes the actions and the challenge state changes to `VALID`.

View File

@ -31,7 +31,7 @@ Now use `cert` and `sniKeyPair` to let your web server respond to SNI requests t
The challenge is completed when the CA was able to send the SNI request and get the correct certificate in return.
Note that the request is sent to port 443 only. There is no way to choose a different port, for security reasons. This is a limitation of the ACME protocol, not of _acme4j_.
> __Note:__ The request is sent to port 443 only. If your domain has multiple IP addresses, the CA randomly selects one of them. There is no way to choose a different port or a fixed IP address.
This shell command line may be helpful to test your web server configuration:

View File

@ -3,7 +3,7 @@
Basically, it is possible to connect to any kind of ACME server just by connecting to the URI of its directory resource:
```java
Session session = new Session("https://acme-v01.api.letsencrypt.org/directory", accountKeyPair);
Session session = new Session("https://acme-v02.api.letsencrypt.org/directory", accountKeyPair);
```
ACME providers are "plug-ins" to _acme4j_ that are specialized on a single CA. For example, the _Let's Encrypt_ provider offers URIs that are much easier to remember. The example above would look like this:
@ -27,13 +27,13 @@ The `AcmeProvider` implementation needs to be registered with Java's `ServiceLoa
When _acme4j_ tries to connect to an acme URI, it first invokes the `accepts(URI)` method of all registered `AcmeProvider`s. Only one of the providers must return `true` for a successful connection. _acme4j_ then invokes the `resolve(URI)` method of that provider, and connects to the directory URL that is returned.
The connection fails if none or more than one `AcmeProvider` implementations `accept` the acme URI.
The connection fails if no or more than one `AcmeProvider` implementations accept the acme URI.
## Certificate Pinning
Client providers may verify the HTTPS certificate provided by the ACME server.
To do so, override the `createHttpConnector()` method of `AbstractAcmeProvider` and return a subclassed `HttpConnector` class that modifies the `HttpURLConnection` as required.
To do so, override the `createHttpConnector()` method of `AbstractAcmeProvider` and return a subclassed `HttpConnector` class that modifies the `HttpURLConnection` as necessary.
## Individual Challenges
@ -43,6 +43,4 @@ In your `AcmeProvider` implementation, override the `createChallenge(Session, St
## No directory service
An ACME server may not provide a directory service, for example when fixed URIs are to be used.
In this case, override the `directory(Session, URI)` method, and return a `JSON` of all available resources and their respective URI.
To modify the directory of an ACME server, or use a static directory, override the `directory(Session, URI)` method, and return a `JSON` of all available resources and their respective URI.

View File

@ -14,6 +14,19 @@ Account account = builder.create(session);
URL accountLocationUrl = account.getLocation();
```
You should not invoke `agreeToTermsOfService()` automatically, but let the user confirm the terms of service. To get a link to the current terms of services, you can invoke `session.getMetadata().getTermsOfService()`.
## Find out your account's location URL
You can also use the `AccountBuilder` to find out the location URL of your existing account:
```java
Account account = new AccountBuilder().onlyExisting().create(session);
URL accountLocationUrl = account.getLocation();
```
If you do not have an account yet, an exception is raised instead, and no new account is created.
## Update your Account
At some point, you may want to update your account. For example your contact address might have changed. To do so, invoke `Account.modify()`, perform the changes, and invoke `commit()` to make them permanent.
@ -38,7 +51,7 @@ KeyPair newKeyPair = ... // new KeyPair to be used
account.changeKey(newKeyPair);
```
After a successful change, all subsequent calls related to this account must use the new key pair. The key is automatically updated on the `Session` that was bound to this `Account`.
After a successful change, all subsequent calls related to this account must use the new key pair. The key is automatically updated on the `Session` that was bound to this `Account` instance.
The old key pair can be disposed of after that. However, I recommend to keep a backup of the old key pair until the key change was proven to be successful, by making a subsequent call with the new key pair. Otherwise you might lock yourself out from your account if the key change should have failed silently, for whatever reason.

View File

@ -1,97 +0,0 @@
# Authorize your Domains
Once you have your account set up, you need to associate your domains with it. This is done by creating an `Authorization` object:
```java
Account account = ... // your Account object
Authorization auth = account.authorizeDomain("example.org");
```
The `Authorization` instance contains further details about how you can prove ownership of your domain. An ACME server offers combinations of different authorization methods, called `Challenge`s.
`Authorization` methods help you find the `Challenge` that fits best to your possibilities. Just pass all the challenge types that your software is able to accept to `findCombination()`, and it returns the shortest possible combination of `Challenge`s you have to perform.
In the following example, your software would be able to either perform a HTTP or DNS challenge, or both:
```java
Collection<Challenge> combination = auth.findCombination(
Http01Challenge.TYPE, Dns01Challenge.TYPE);
```
The returned `combination` contains a single combination of challenges you would have to perform. If the combination consists of more than one challenge, you will have to perform _all of them_ in order to successfully authorize your domain. If the returned collection is empty, it means that none of your offered challenge types are acceptable to the CA.
If your software only supports a single challenge type, `findChallenge()` may be a little easier to use:
```java
Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE);
```
It returns a properly casted `Challenge` object, or `null` if your challenge type was not acceptable.
The `Challenge` object provides the necessary data for a successful verification of your domain ownership. The kind of response depends on the challenge type (see the [documentation of challenges](../challenge/index.html)).
After you have performed the necessary steps to set up the response to the challenge (e.g. creating a file or modifying your DNS records), the ACME server is told to test your response:
```java
challenge.trigger();
```
Now you have to wait for the server to test your response and set the challenge status to `VALID`. The easiest way is to poll the status:
```java
while (challenge.getStatus() != Status.VALID) {
Thread.sleep(3000L);
challenge.update();
}
```
This is a very simple example. You should limit the number of loop iterations, and abort the loop when the status should turn to `INVALID`. If you know when the CA server actually requested your response (e.g. when you notice a HTTP request on the response file), you should start polling after that event.
`update()` may throw an `AcmeRetryAfterException`, giving an estimated time in `getRetryAfter()` for when the challenge is completed. You should then wait until that moment has been reached, before trying again. The challenge state is still updated when this exception is thrown.
As soon as all the necessary challenges are `VALID`, you have successfully associated the domain with your account.
If your final certificate will contain further domains or subdomains, repeat the authorization run with each of them.
## Update an Authorization
The server also provides an authorization URL. It can be retrieved from `Authorization.getLocation()`. You can recreate the `Authorization` object at a later time just by binding it to your `Session`:
```java
URL authUrl = ... // Authorization URL
Authorization auth = Authorization.bind(session, authUrl);
```
As soon as you invoke a getter, the `Authorization` object lazily loads the current server state of your authorization, including the domain name, the overall status, and an expiry date.
You can always invoke `update()` to read the current server state again. It may throw an `AcmeRetryAfterException`, giving an estimated time in `getRetryAfter()` for when all challenges are completed. The authorization state is still updated even when this exception is thrown. If you invoke `update()` for polling the authorization state, you should wait until the moment given in the exception has been reached before trying again.
## Deactivate an Authorization
It is possible to deactivate an `Authorization`, for example if you sell the associated domain.
```java
auth.deactivate();
```
## Restore a Challenge
Validating a challenge can take a considerable amount of time and is a candidate for asynchronous execution. This can be a problem if you need to keep the `Challenge` object for a later time or a different Java environment.
To recreate a `Challenge` object at a later time, all you need is to store the original object's `location` property:
```java
Challenge originalChallenge = ... // some Challenge instance
URL challengeUrl = originalChallenge.getLocation();
```
Later, you restore the `Challenge` object by invoking `Challenge.bind()`.
```java
URL challengeUrl = ... // challenge URL
Challenge restoredChallenge = Challenge.bind(session, challengeUri);
```
The `restoredChallenge` already reflects the current state of the challenge.

View File

@ -1,52 +1,36 @@
# Certificates
Once you completed all the previous steps, it's time to request the signed certificate.
## Request a Certificate
To do so, prepare a PKCS#10 CSR file. A single domain may be set as _Common Name_. Multiple domains must be provided as _Subject Alternative Name_. Other properties (_Organization_, _Organization Unit_ etc.) depend on the CA. Some may require these properties to be set, while others may ignore them when generating the certificate.
CSR files can be generated with command line tools like `openssl`. Unfortunately the standard Java does not offer classes for that, so you'd have to resort to [Bouncy Castle](http://www.bouncycastle.org/java.html) if you want to create a CSR programmatically. In the `acme4j-utils` module, there is a [`CSRBuilder`](../apidocs/org/shredzone/acme4j/util/CSRBuilder.html) for your convenience. You can also use [`KeyPairUtils`](../apidocs/org/shredzone/acme4j/util/KeyPairUtils.html) for generating the domain key pair.
Do not just use your account key pair as domain key pair, but always generate a separate pair of keys!
Once you completed all the previous steps, it's time to download the signed certificate.
```java
KeyPair domainKeyPair = ... // KeyPair to be used for HTTPS encryption
Order order = ... // your Order object from the previous step
CSRBuilder csrb = new CSRBuilder();
csrb.addDomain("example.org");
csrb.setOrganization("The Example Organization")
csrb.sign(domainKeyPair);
byte[] csr = csrb.getEncoded();
order.update(); // make sure we have the current state
Certificate cert = order.getCertificate();
```
It is a good idea to store the generated CSR somewhere, as you will need it again for renewal:
The `Certificate` object offers methods to get the certificate or the certificate chain.
```java
try (FileWriter fw = new FileWriter("example.csr")) {
csrb.write(fw);
}
X509Certificate cert = cert.getCertificate();
List<X509Certificate> chain = cert.getCertificateChain();
```
Now all you need to do is to pass in a binary representation of the CSR and request the certificate:
```java
Certificate cert = account.requestCertificate(csr);
```
`cert.getLocation()` returns an URL where the signed certificate can be downloaded from. Optionally (if delivered by the ACME server) `cert.getChainLocation()` returns the URL of the first part of the CA chain.
The `Certificate` object offers methods to download the certificate and the certificate chain.
```java
X509Certificate cert = cert.download();
X509Certificate[] chain = cert.downloadChain();
```
`cert` only contains the plain certificate. However, most servers require the certificate `chain` that also contains all intermediate certificates up to the root CA.
Congratulations! You have just created your first certificate via _acme4j_.
`download()` may throw an `AcmeRetryAfterException`, giving an estimated time in `getRetryAfter()` for when the certificate is ready for download. You should then wait until that moment has been reached, before trying again.
## Save the Certificate
The `Certificate` object provides a method to write a certificate file that can be used for most web servers, like _Apache_, _nginx_, but also other servers like _postfix_ or _dovecot_:
```java
try (FileWriter fw = new FileWriter("cert-chain.crt");) {
cert.writeCertificate(fw)
}
```
## Recreate a Certificate object
To recreate a `Certificate` object from the location, just bind it:
```java
@ -54,73 +38,11 @@ URL locationUrl = ... // location URL from cert.getLocation()
Certificate cert = Certificate.bind(session, locationUrl);
```
### Saving Certificates
Most web servers, like _Apache_, _nginx_, but also other servers like _postfix_ or _dovecot_, need a combined certificate file that contains the leaf certificate itself, and the certificate chain up to the root certificate. `acme4j-utils` offers a method that helps to write the necessary file:
```java
try (FileWriter fw = new FileWriter("cert-chain.crt")) {
CertificateUtils.writeX509CertificateChain(fw, cert, chain);
}
```
Some older servers may need the leaf certificate and the certificate chain in different files. Use this snippet to write both files:
```java
try (FileWriter fw = new FileWriter("cert.pem")) {
CertificateUtils.writeX509Certificate(cert, fw);
}
try (FileWriter fw = new FileWriter("chain.pem")) {
CertificateUtils.writeX509CertificateChain(fw, null, chain);
}
```
These utility methods should be sufficient for most use cases. If you need the certificate written in a different format, see the [source code of `CertificateUtils`](https://github.com/shred/acme4j/blob/master/acme4j-utils/src/main/java/org/shredzone/acme4j/util/CertificateUtils.java) to find out how certificates are written using _Bouncy Castle_.
### Multiple Domains
The example above generates a certificate per domain. However, you would usually prefer to use a single certificate for multiple domains (for example, the domain itself and the `www.` subdomain).
You first need to [authorize](./authorization.html) each (sub)domain separately.
After all the domains are authorized, generate a single CSR with all the domains provided as _Subject Alternative Name_ (SAN). If you use the `CSRBuilder`, just add all of the domains to the builder:
```java
KeyPair domainKeyPair = ... // KeyPair to be used for HTTPS encryption
CSRBuilder csrb = new CSRBuilder();
csrb.addDomain("example.org");
csrb.addDomain("www.example.org");
csrb.addDomain("m.example.org");
// add more domains if necessary...
csrb.sign(domainKeyPair);
byte[] csr = csrb.getEncoded();
```
The generated certificate will be valid for all of the domains.
Note that wildcard certificates are currently not supported by the ACME protocol.
The number of domains per certificate may also be limited. See your CA's documentation for the limits.
## Renewal
Certificates are only valid for a limited time, and need to be renewed before expiry. To find out the expiry date of a `X509Certificate`, invoke its `getNotAfter()` method.
For renewal, just request a new certificate using the original CSR:
```java
PKCS10CertificationRequest csr = CertificateUtils.readCSR(
new FileInputStream("example.csr"));
Certificate cert = account.requestCertificate(csr);
X509Certificate cert = cert.download();
```
Instead of loading the original CSR, you can also generate a new one. So renewing a certificate is basically the same as requesting a new certificate.
If `account.requestCertificate(csr)` throws an `AcmeUnauthorizedException`, the authorizations of some or all involved domains have expired. In this case, you need to go through the [authorization](./authorization.html) process again, before requesting the renewed certificate.
A certificate can be renewed a few days before its expiry. There is no explicit method for certificate renewal. To renew it, just [order](./order.html) the certificate again.
## Revocation
@ -140,15 +62,12 @@ cert.revoke(RevocationReason.KEY_COMPROMISE);
If you have lost your account key, you can still revoke a certificate as long as you still own the key pair that was used for signing the CSR. `Certificate` provides a special method for this case.
First, create a new `Session` object, but use _the key pair that was used for siging the CSR_. Now invoke the `revoke()` method and pass the `Session`, the certificate to be revoked, and (optionally) a revocation reason.
```java
URI acmeServerUri = ... // uri of the ACME server
KeyPair domainKeyPair = ... // the key pair that was used for signing the CSR
URI acmeServerUri = ... // uri of the ACME server
X509Certificate cert = ... // certificate to revoke
X509Certificate cert = ... // certificate to revoke
Session session = new Session(acmeServerUri, domainKeyPair);
Certificate.revoke(session, cert, RevocationReason.KEY_COMPROMISE);
Certificate.revoke(acmeServerUri, domainKeyPair, cert, RevocationReason.KEY_COMPROMISE);
```
Note that there is no way to revoke a certificate if you should lose both your account's key pair and your domain's key pair.
Note that there is no way to revoke a certificate if you have lost both your account's key pair and your domain's key pair.

View File

@ -16,7 +16,7 @@ You can also create an elliptic curve key pair:
KeyPair keyPair = KeyPairUtils.createECKeyPair("secp256r1");
```
> **CAUTION**: Your KeyPair is the only key to your account. If you should lose it, you will be locked out from your account and certificates. The API does currently not offer a way to recover access after a key loss. The only way is to contact the CA and ask for assistance. **It is strongly recommended to keep your key pair in a safe place!**
> **CAUTION**: Your KeyPair is the only key to your account. If you should lose it, you will be locked out from your account and certificates. The API does not offer a way to recover access after a key loss. The only way is to contact the CA and ask for assistance. **It is strongly recommended to keep your key pair in a safe place!**
To save a `KeyPair` (actually, the private key of the key pair) to a pem file, use this snippet:
@ -37,6 +37,6 @@ try (FileReader fr = New FileReader("keypair.pem")) {
Now that you have created (and saved) your account's key pair, you can start with registering an account and getting your first certificate. These steps need to be performed:
* [Create a Session object](./session.html)
* [Register and Create an Account](./register.html)
* [Authorize your Domains](./authorization.html)
* [Request and Download a Certificate](./certificate.html)
* [Register and Create an Account](./account.html)
* [Order a Certifiate](./order.html)
* [Download a Certificate](./certificate.html)

View File

@ -0,0 +1,161 @@
# Order a Certificate
Once you have your account set up, you are ready to order certificates.
## Create a Certificate Signing Request (CSR)
To do so, prepare a PKCS#10 CSR file. A single domain may be set as _Common Name_. Multiple domains must be provided as _Subject Alternative Name_. Other properties (_Organization_, _Organization Unit_ etc.) depend on the CA. Some may require these properties to be set, while others may ignore them when generating the certificate.
CSR files can be generated with command line tools like `openssl`. Unfortunately the standard Java does not offer classes for that, so you'd have to resort to [Bouncy Castle](http://www.bouncycastle.org/java.html) if you want to create a CSR programmatically. In the `acme4j-utils` module, there is a [`CSRBuilder`](../apidocs/org/shredzone/acme4j/util/CSRBuilder.html) for your convenience. You can also use [`KeyPairUtils`](../apidocs/org/shredzone/acme4j/util/KeyPairUtils.html) for generating a new key pair for your domain.
> __Important:__ Do not just use your account key pair as domain key pair, but always generate a separate pair of keys!
```java
KeyPair domainKeyPair = ... // KeyPair to be used for HTTPS encryption
CSRBuilder csrb = new CSRBuilder();
csrb.addDomain("example.org");
csrb.addDomain("www.example.org");
csrb.addDomain("m.example.org");
csrb.setOrganization("The Example Organization")
csrb.sign(domainKeyPair);
byte[] csr = csrb.getEncoded();
```
It is a good idea to store the generated CSR somewhere, as you will need it again for renewal:
```java
csrb.write(new FileWriter("example.csr"));
```
The generated certificate will be valid for all of the domains stored in the CSR.
> __Note:__ The number of domains per certificate may be limited. See your CA's documentation for the limits.
## Order a Certificate
The next step is to use your `Account` object to order the certificate, by using the `orderCertificate()` method. You can optionally give your desired `notBefore` and `notAfter` dates for the generated certificate, but it is at the discretion of the CA to use (or ignore) these values.
```java
Account account = ... // your Account object
byte[] csr = ... // your CSR (see above)
Order order = account.orderCertificate(csr, null, null);
```
The `Order` resource contains a collection of `Authorization`s that can be read from the `getAuthorizations()` method. You must process _all of them_ in order to get the certificate.
## Process an Authorization
The `Authorization` instance contains further details about how you can prove ownership of your domain. An ACME server offers combinations of different authorization methods, called `Challenge`s.
`getChallenges()` returns a collection of all `Challenge`s offered by the CA for domain ownership validation. You only need to use _one_ of them to successfully authorize your domain.
The simplest way is to invoke `findChallenge()`, stating the challenge type your system is able to provide:
```java
Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE);
```
It returns a properly casted `Challenge` object, or `null` if your challenge type was not acceptable. In this example, your system is able to respond to a [http-01](../challenge/http-01.html) challenge.
The returned `Challenge` resource provides all the data that is necessary for a successful verification of your domain ownership. Your response depends on the challenge type (see the [documentation of challenges](../challenge/index.html)).
After you have performed the necessary steps to set up the response to the challenge (e.g. configuring your web server or modifying your DNS records), the ACME server is told to test your response:
```java
challenge.trigger();
```
Now you have to wait for the server to test your response and set the challenge status to `VALID`. The easiest (but admittedly also the ugliest) way is to poll the status:
```java
while (challenge.getStatus() != Status.VALID) {
Thread.sleep(3000L);
challenge.update();
}
```
This is a very simple example. You should limit the number of loop iterations, and always abort the loop when the status should turn to `INVALID`. If you know when the CA server actually requested your response (e.g. when you notice a HTTP request on the response file), you should start polling after that event.
The CA server may start the validation immediately after `trigger()` is invoked, so make sure your server is ready to respond to requests before invoking `trigger()`. Otherwise the challenge might fail.
`update()` may throw an `AcmeRetryAfterException`, giving an estimated instant in `getRetryAfter()` when the challenge is completed. You should then wait until that moment has been reached, before trying again. The state of your `Challenge` instance is still updated when this exception is thrown.
When the challenge status is `VALID`, you have successfully authorized your domain.
## Deactivate an Authorization
It is possible to deactivate an `Authorization`, for example if you sell the associated domain.
```java
auth.deactivate();
```
## Pre-Authorize a Domain
It is possible to pro-actively authorize a domain. This can be useful to find out what challenges are requested by the CA to authorize a domain, before actually ordering a certificate. It may also help to speed up the ordering process, as already completed authorizations do not need to be completed again when ordering the certificate.
```java
Account account = ... // your Account object
String domain = ... // Domain name to authorize
Authorization auth = account.preAuthorizeDomain(String domain);
```
> __Note:__ Some CAs may not offer domain pre-authorization. `preAuthorizeDomain()` will then fail and throw an exception.
## Wildcard Certificates
You can also generate wildcard certificates that are valid for the domain itself, and all of its subdomains:
```java
KeyPair domainKeyPair = ... // KeyPair to be used for HTTPS encryption
CSRBuilder csrb = new CSRBuilder();
csrb.addDomain("*.example.org"); // Wildcard
csrb.sign(domainKeyPair);
byte[] csr = csrb.getEncoded();
```
> __Note:__ Some CAs may not accept wildcard certificate orders. Validating wildcard certificates may involve `Challenge`s that are not documented here. Refer to your CA's documentation to find out about the wildcard certificate policy.
## Restore a Challenge
Validating a challenge can take a considerable amount of time and is a candidate for asynchronous execution. This can be a problem if you need to keep the `Challenge` object for a later time or a different Java environment.
To recreate a `Challenge` object at a later time, all you need is to store the original object's `location` property:
```java
Challenge originalChallenge = ... // some Challenge instance
URL challengeUrl = originalChallenge.getLocation();
```
Later, you restore the `Challenge` object by invoking `Challenge.bind()`.
```java
URL challengeUrl = ... // challenge URL
Challenge restoredChallenge = Challenge.bind(session, challengeUrl);
```
The `restoredChallenge` already reflects the current state of the challenge.
You can also restore `Order` and `Authorization` objects at a later execution:
```java
// Get the location URL
Order originalOrder = ... // your Order instance
URL orderUrl = originalOrder.getLocation();
// Restore the order
Order restoredOrder = Order.bind(session, orderUrl);
```
```java
// Get the location URL
Authorization originalAuthorization = ... // your Authorization instance
URL authorizationUrl = originalAuthorization.getLocation();
// Restore the order
Authorization restoredAuthorization = Authorization.bind(session, authorizationUrl);
```

View File

@ -1,66 +0,0 @@
# Register an Account
If it is the first time you connect to the ACME server, you need to register your account key.
To do so, create an `AccountBuilder`, optionally add some contact information, agree to the terms of service, then invoke `create()`. If the account was successfully created, you will get an `Account` object in return. Invoking its `getLocation()` method will return the location URL of your account. You should store it somewhere, because you will need it later. Unlike your key pair, the location is a public information that does not need security precautions.
```java
AccountBuilder builder = new AccountBuilder();
builder.addContact("mailto:acme@example.com");
builder.agreeToTermsOfService();
Account account = builder.create(session);
URL accountLocationUrl = account.getLocation();
```
## Find out your account's location URL
You can also use the `AccountBuilder` to find out the location URL of your existing account:
```java
Account account = new AccountBuilder().onlyExisting().create(session);
URL accountLocationUrl = account.getLocation();
```
If you do not have an account yet, an exception is raised instead, and no new account is created.
## Update your Account
At some point, you may want to update your account. For example your contact address might have changed. To do so, invoke `Account.modify()`, perform the changes, and invoke `commit()` to make them permanent.
The following example adds another email address.
```java
account.modify()
.addContact("mailto:acme2@example.com")
.commit();
```
## Account Key Roll-Over
It is also possible to change the key pair that is associated with your account, for example if you suspect that your key has been compromised.
The following example changes the key pair:
```java
KeyPair newKeyPair = ... // new KeyPair to be used
account.changeKey(newKeyPair);
```
After a successful change, all subsequent calls related to this account must use the new key pair. The key is automatically updated on the `Session` that was bound to this `Account`.
The old key pair can be disposed of after that. However, I recommend to keep a backup of the old key pair until the key change was proven to be successful, by making a subsequent call with the new key pair. Otherwise you might lock yourself out from your account if the key change should have failed silently, for whatever reason.
## Deactivate an Account
You can deactivate your account if you don't need it any more:
```java
account.deactivate();
```
Depending on the CA, the related authorizations may be automatically deactivated as well. The certificates may still be valid until expiration or explicit revocation. If you want to make sure the certificates are invalidated as well, revoke them prior to deactivation of your account.
Be very careful: There is no way to reactivate the account once it is deactivated!

View File

@ -36,7 +36,7 @@ URL accountLocationUrl = ... // your account's URL, as returned by Account.getLo
Account account = Account.bind(session, accountLocationUrl);
```
You can create any of the resource objects `Account`, `Authorization`, `Challenge` and `Certificate` like that, as long as you know the corresponding resource URL. To get the resource URL, use the `getLocation()` method.
You can create any of the resource objects `Account`, `Authorization`, `Challenge`, `Certificate` and `Order` like that, as long as you know the corresponding resource URL. To get the resource URL, use the `getLocation()` method.
## Serialization

View File

@ -33,7 +33,7 @@
<item name="How to Use" href="usage/index.html">
<item name="Session" href="usage/session.html"/>
<item name="Account" href="usage/account.html"/>
<item name="Authorization" href="usage/authorization.html"/>
<item name="Order and Authorization" href="usage/order.html"/>
<item name="Certificate" href="usage/certificate.html"/>
</item>
<item name="Challenges" href="challenge/index.html">