mirror of https://github.com/shred/acme4j
Remove account recovery. Closes issue #1.
parent
19787f4c00
commit
92b3076031
|
@ -61,16 +61,6 @@ public interface AcmeClient {
|
||||||
void changeRegistrationKey(Registration registration, KeyPair newKeyPair)
|
void changeRegistrationKey(Registration registration, KeyPair newKeyPair)
|
||||||
throws AcmeException;
|
throws AcmeException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Recovers an account by contact-based recovery. The server starts an out-of-band
|
|
||||||
* recovery process by using one of the contact addresses given at account creation.
|
|
||||||
*
|
|
||||||
* @param registration
|
|
||||||
* {@link Registration}, with the new key pair and the account location URI
|
|
||||||
* set
|
|
||||||
*/
|
|
||||||
void recoverRegistration(Registration registration) throws AcmeException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an account. Related certificates may still be valid after account deletion,
|
* Deletes an account. Related certificates may still be valid after account deletion,
|
||||||
* and need to be revoked separately if neccessary.
|
* and need to be revoked separately if neccessary.
|
||||||
|
|
|
@ -23,8 +23,7 @@ public enum Resource {
|
||||||
NEW_REG("new-reg"),
|
NEW_REG("new-reg"),
|
||||||
NEW_AUTHZ("new-authz"),
|
NEW_AUTHZ("new-authz"),
|
||||||
NEW_CERT("new-cert"),
|
NEW_CERT("new-cert"),
|
||||||
REVOKE_CERT("revoke-cert"),
|
REVOKE_CERT("revoke-cert");
|
||||||
RECOVER_REG("recover-reg");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the string and returns a matching {@link Resource} instance.
|
* Parses the string and returns a matching {@link Resource} instance.
|
||||||
|
|
|
@ -223,41 +223,6 @@ public abstract class AbstractAcmeClient implements AcmeClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recoverRegistration(Registration registration) throws AcmeException {
|
|
||||||
if (registration == null) {
|
|
||||||
throw new NullPointerException("registration must not be null");
|
|
||||||
}
|
|
||||||
if (registration.getLocation() == null) {
|
|
||||||
throw new IllegalArgumentException("registration location must not be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.debug("recoverRegistration");
|
|
||||||
try (Connection conn = createConnection()) {
|
|
||||||
ClaimBuilder claims = new ClaimBuilder();
|
|
||||||
claims.putResource(Resource.RECOVER_REG);
|
|
||||||
claims.put("method", "contact");
|
|
||||||
claims.put("base", registration.getLocation());
|
|
||||||
if (!registration.getContacts().isEmpty()) {
|
|
||||||
claims.put("contact", registration.getContacts());
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = conn.sendSignedRequest(resourceUri(Resource.RECOVER_REG), claims, session, registration);
|
|
||||||
if (rc != HttpURLConnection.HTTP_CREATED) {
|
|
||||||
conn.throwAcmeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
registration.setLocation(conn.getLocation());
|
|
||||||
|
|
||||||
URI tos = conn.getLink("terms-of-service");
|
|
||||||
if (tos != null) {
|
|
||||||
registration.setAgreement(tos);
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new AcmeNetworkException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteRegistration(Registration registration) throws AcmeException {
|
public void deleteRegistration(Registration registration) throws AcmeException {
|
||||||
if (registration == null) {
|
if (registration == null) {
|
||||||
|
|
|
@ -34,10 +34,9 @@ public class ResourceTest {
|
||||||
assertThat(Resource.NEW_CERT.path(), is("new-cert"));
|
assertThat(Resource.NEW_CERT.path(), is("new-cert"));
|
||||||
assertThat(Resource.NEW_REG.path(), is("new-reg"));
|
assertThat(Resource.NEW_REG.path(), is("new-reg"));
|
||||||
assertThat(Resource.REVOKE_CERT.path(), is("revoke-cert"));
|
assertThat(Resource.REVOKE_CERT.path(), is("revoke-cert"));
|
||||||
assertThat(Resource.RECOVER_REG.path(), is("recover-reg"));
|
|
||||||
|
|
||||||
// fails if there are untested future Resource values
|
// fails if there are untested future Resource values
|
||||||
assertThat(Resource.values().length, is(5));
|
assertThat(Resource.values().length, is(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -56,7 +56,6 @@ public class AbstractAcmeClientTest {
|
||||||
|
|
||||||
private URI resourceUri;
|
private URI resourceUri;
|
||||||
private URI locationUri;
|
private URI locationUri;
|
||||||
private URI anotherLocationUri;
|
|
||||||
private URI agreementUri;
|
private URI agreementUri;
|
||||||
private KeyPair accountKeyPair;
|
private KeyPair accountKeyPair;
|
||||||
private Registration testRegistration;
|
private Registration testRegistration;
|
||||||
|
@ -65,7 +64,6 @@ public class AbstractAcmeClientTest {
|
||||||
public void setup() throws IOException, URISyntaxException {
|
public void setup() throws IOException, URISyntaxException {
|
||||||
resourceUri = new URI("https://example.com/acme/some-resource");
|
resourceUri = new URI("https://example.com/acme/some-resource");
|
||||||
locationUri = new URI("https://example.com/acme/some-location");
|
locationUri = new URI("https://example.com/acme/some-location");
|
||||||
anotherLocationUri = new URI("https://example.com/acme/another-location");
|
|
||||||
agreementUri = new URI("http://example.com/agreement.pdf");
|
agreementUri = new URI("http://example.com/agreement.pdf");
|
||||||
accountKeyPair = TestUtils.createKeyPair();
|
accountKeyPair = TestUtils.createKeyPair();
|
||||||
testRegistration = new Registration(accountKeyPair);
|
testRegistration = new Registration(accountKeyPair);
|
||||||
|
@ -220,46 +218,6 @@ public class AbstractAcmeClientTest {
|
||||||
client.changeRegistrationKey(registration, registration.getKeyPair());
|
client.changeRegistrationKey(registration, registration.getKeyPair());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that a {@link Registration} can be recovered by contact-based recovery.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testRecoverRegistration() throws AcmeException {
|
|
||||||
Registration registration = new Registration(accountKeyPair);
|
|
||||||
registration.addContact("mailto:foo@example.com");
|
|
||||||
registration.setLocation(locationUri);
|
|
||||||
|
|
||||||
Connection connection = new DummyConnection() {
|
|
||||||
@Override
|
|
||||||
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) {
|
|
||||||
assertThat(session, is(notNullValue()));
|
|
||||||
assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair)));
|
|
||||||
return HttpURLConnection.HTTP_CREATED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URI getLocation() {
|
|
||||||
return anotherLocationUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URI getLink(String relation) {
|
|
||||||
switch(relation) {
|
|
||||||
case "terms-of-service": return agreementUri;
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection);
|
|
||||||
client.putTestResource(Resource.RECOVER_REG, resourceUri);
|
|
||||||
|
|
||||||
client.recoverRegistration(registration);
|
|
||||||
|
|
||||||
assertThat(registration.getLocation(), is(anotherLocationUri));
|
|
||||||
assertThat(registration.getAgreement(), is(agreementUri));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that a {@link Registration} can be deleted.
|
* Test that a {@link Registration} can be deleted.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Account Recovery
|
|
||||||
|
|
||||||
The ACME server identifies your account by the public key that you provided on registration. If you lose your key pair, you will be unable to access your account.
|
|
||||||
|
|
||||||
ACME offers a contact-based way of recovering access to your authorizations and certificates in case you have lost your key pair. However, it involves creating a new account, and transfering your data to it. You will not be able to regain access to your old account.
|
|
||||||
|
|
||||||
Individual CAs may offer further ways of recovery, which are not part of this documentation.
|
|
||||||
|
|
||||||
## Contact-Based Recovery
|
|
||||||
|
|
||||||
> **CAUTION**: Contact-Based Recovery is [currently not supported by _Let's Encrypt_](https://github.com/letsencrypt/boulder/issues/432). If you should lose your key pair, you are stuck.
|
|
||||||
|
|
||||||
On this recovery method, the CA contacts the account owner via one of the contact addresses given on account creation. The owner is asked to take some action (e.g. clicking on a link in an email). If it was successful, the account data is transferred to the new account.
|
|
||||||
|
|
||||||
To initiate contact-based recovery, you first need to create a new account key pair. Then create a `Registration` object by passing the _new_ key pair and location URI of your _old_ account to the constructor. Finally, start the recovery process by invoking `recoverRegistration()`:
|
|
||||||
|
|
||||||
```java
|
|
||||||
KeyPair newKeyPair = ... // your new account KeyPair
|
|
||||||
URI oldAccountUri = ... // location of your old account
|
|
||||||
|
|
||||||
Registration reg = new Registration(newKeyPair, oldAccountUri);
|
|
||||||
client.recoverRegistration(reg);
|
|
||||||
|
|
||||||
URI newAccountUri = reg.getLocation();
|
|
||||||
```
|
|
||||||
|
|
||||||
`newAccountUri` is the location URI of your _new_ account. Store it and use it in connection with your new key pair.
|
|
||||||
|
|
||||||
The old location URI is now invalid and can be deleted.
|
|
|
@ -34,7 +34,6 @@
|
||||||
<item name="Registration" href="usage/register.html"/>
|
<item name="Registration" href="usage/register.html"/>
|
||||||
<item name="Authorization" href="usage/authorization.html"/>
|
<item name="Authorization" href="usage/authorization.html"/>
|
||||||
<item name="Certificate" href="usage/certificate.html"/>
|
<item name="Certificate" href="usage/certificate.html"/>
|
||||||
<item name="Recovery" href="usage/recovery.html"/>
|
|
||||||
</item>
|
</item>
|
||||||
<item name="Challenges" href="challenge/index.html">
|
<item name="Challenges" href="challenge/index.html">
|
||||||
<item name="http-01" href="challenge/http-01.html"/>
|
<item name="http-01" href="challenge/http-01.html"/>
|
||||||
|
|
Loading…
Reference in New Issue