diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java index e2547827..39a89c98 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java @@ -48,17 +48,17 @@ public class Registration extends AcmeResource { private static final long serialVersionUID = -8177333806740391140L; private static final Logger LOG = LoggerFactory.getLogger(Registration.class); - private static final String KEY_AGREEMENT = "agreement"; + private static final String KEY_TOS_AGREED = "terms-of-service-agreed"; private static final String KEY_AUTHORIZATIONS = "authorizations"; private static final String KEY_CERTIFICATES = "certificates"; private static final String KEY_CONTACT = "contact"; private static final String KEY_STATUS = "status"; private final List contacts = new ArrayList<>(); - private URI agreement; + private Status status; + private Boolean termsOfServiceAgreed; private URI authorizations; private URI certificates; - private Status status; private boolean loaded = false; protected Registration(Session session, URI location) { @@ -66,12 +66,6 @@ public class Registration extends AcmeResource { setLocation(location); } - protected Registration(Session session, URI location, URI agreement) { - super(session); - setLocation(location); - this.agreement = agreement; - } - /** * Creates a new instance of {@link Registration} and binds it to the {@link Session}. * @@ -86,13 +80,14 @@ public class Registration extends AcmeResource { } /** - * Returns the URI of the agreement document the user is required to accept. + * Returns if the user agreed to the terms of service. + * + * @return {@code true} if the user agreed to the terms of service. May be + * {@code null} if the server did not provide such an information. */ - public URI getAgreement() { - if (agreement == null) { - load(); - } - return agreement; + public Boolean getTermsOfServiceAgreed() { + load(); + return termsOfServiceAgreed; } /** @@ -346,8 +341,8 @@ public class Registration extends AcmeResource { * {@link Connection} with headers to be evaluated */ private void unmarshal(JSON json, Connection conn) { - if (json.contains(KEY_AGREEMENT)) { - this.agreement = json.get(KEY_AGREEMENT).asURI(); + if (json.contains(KEY_TOS_AGREED)) { + this.termsOfServiceAgreed = json.get(KEY_TOS_AGREED).asBoolean(); } if (json.contains(KEY_CONTACT)) { @@ -369,11 +364,6 @@ public class Registration extends AcmeResource { setLocation(location); } - URI tos = conn.getLink("terms-of-service"); - if (tos != null) { - this.agreement = tos; - } - loaded = true; } @@ -391,11 +381,9 @@ public class Registration extends AcmeResource { */ public class EditableRegistration { private final List editContacts = new ArrayList<>(); - private URI editAgreement; private EditableRegistration() { editContacts.addAll(Registration.this.contacts); - editAgreement = Registration.this.agreement; } /** @@ -432,18 +420,6 @@ public class Registration extends AcmeResource { return this; } - /** - * Sets a new agreement URI. - * - * @param agreement - * New agreement URI - * @return itself - */ - public EditableRegistration setAgreement(URI agreement) { - this.editAgreement = agreement; - return this; - } - /** * Commits the changes and updates the account. */ @@ -455,9 +431,6 @@ public class Registration extends AcmeResource { if (!editContacts.isEmpty()) { claims.put(KEY_CONTACT, editContacts); } - if (editAgreement != null) { - claims.put(KEY_AGREEMENT, editAgreement); - } conn.sendSignedRequest(getLocation(), claims, getSession()); conn.accept(HttpURLConnection.HTTP_ACCEPTED); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/RegistrationBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/RegistrationBuilder.java index 1acf1171..4edaed6c 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/RegistrationBuilder.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/RegistrationBuilder.java @@ -33,6 +33,7 @@ public class RegistrationBuilder { private static final Logger LOG = LoggerFactory.getLogger(RegistrationBuilder.class); private List contacts = new ArrayList<>(); + private Boolean termsOfServiceAgreed; /** * Add a contact URI to the list of contacts. @@ -62,6 +63,16 @@ public class RegistrationBuilder { return this; } + /** + * Signals that the user agrees to the terms of service. + * + * @return itself + */ + public RegistrationBuilder agreeToTermsOfService() { + this.termsOfServiceAgreed = true; + return this; + } + /** * Creates a new account. * @@ -82,14 +93,16 @@ public class RegistrationBuilder { if (!contacts.isEmpty()) { claims.put("contact", contacts); } + if (termsOfServiceAgreed != null) { + claims.put("terms-of-service-agreed", termsOfServiceAgreed); + } conn.sendSignedRequest(session.resourceUri(Resource.NEW_REG), claims, session); conn.accept(HttpURLConnection.HTTP_CREATED); URI location = conn.getLocation(); - URI tos = conn.getLink("terms-of-service"); - return new Registration(session, location, tos); + return new Registration(session, location); } } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationBuilderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationBuilderTest.java index ddc841cc..5456c985 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationBuilderTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationBuilderTest.java @@ -14,7 +14,7 @@ package org.shredzone.acme4j; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import static org.shredzone.acme4j.util.TestUtils.*; import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; @@ -25,6 +25,7 @@ import org.junit.Test; import org.shredzone.acme4j.connector.Resource; import org.shredzone.acme4j.exception.AcmeException; import org.shredzone.acme4j.provider.TestableConnectionProvider; +import org.shredzone.acme4j.util.JSON; import org.shredzone.acme4j.util.JSONBuilder; /** @@ -34,7 +35,6 @@ public class RegistrationBuilderTest { private URI resourceUri = URI.create("http://example.com/acme/resource");; private URI locationUri = URI.create("http://example.com/acme/registration");; - private URI agreementUri = URI.create("http://example.com/agreement.pdf");; /** * Test if a new registration can be created. @@ -42,17 +42,30 @@ public class RegistrationBuilderTest { @Test public void testRegistration() throws Exception { TestableConnectionProvider provider = new TestableConnectionProvider() { + private boolean isUpdate; + @Override public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { - assertThat(uri, is(resourceUri)); - assertThat(claims.toString(), sameJSONAs(getJson("newRegistration"))); assertThat(session, is(notNullValue())); + if (resourceUri.equals(uri)) { + isUpdate = false; + assertThat(claims.toString(), sameJSONAs(getJson("newRegistration"))); + } else if (locationUri.equals(uri)) { + isUpdate = true; + } else { + fail("bad URI"); + } } @Override public int accept(int... httpStatus) throws AcmeException { - assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_CREATED)); - return HttpURLConnection.HTTP_CREATED; + if (isUpdate) { + assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_ACCEPTED)); + return HttpURLConnection.HTTP_ACCEPTED; + } else { + assertThat(httpStatus, isIntArrayContainingInAnyOrder(HttpURLConnection.HTTP_CREATED)); + return HttpURLConnection.HTTP_CREATED; + } } @Override @@ -61,11 +74,9 @@ public class RegistrationBuilderTest { } @Override - public URI getLink(String relation) { - switch(relation) { - case "terms-of-service": return agreementUri; - default: return null; - } + public JSON readJsonResponse() { + assertThat(isUpdate, is(true)); + return getJsonAsObject("newRegistrationResponse"); } }; @@ -73,11 +84,12 @@ public class RegistrationBuilderTest { RegistrationBuilder builder = new RegistrationBuilder(); builder.addContact("mailto:foo@example.com"); + builder.agreeToTermsOfService(); Registration registration = builder.create(provider.createSession()); assertThat(registration.getLocation(), is(locationUri)); - assertThat(registration.getAgreement(), is(agreementUri)); + assertThat(registration.getTermsOfServiceAgreed(), is(true)); provider.close(); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java index a0624eb0..e8545acf 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/RegistrationTest.java @@ -124,7 +124,7 @@ public class RegistrationTest { registration.update(); assertThat(registration.getLocation(), is(locationUri)); - assertThat(registration.getAgreement(), is(agreementUri)); + assertThat(registration.getTermsOfServiceAgreed(), is(true)); assertThat(registration.getContacts(), hasSize(1)); assertThat(registration.getContacts().get(0), is(URI.create("mailto:foo2@example.com"))); assertThat(registration.getStatus(), is(Status.GOOD)); @@ -188,12 +188,12 @@ public class RegistrationTest { // Lazy loading assertThat(requestWasSent.get(), is(false)); - assertThat(registration.getAgreement(), is(agreementUri)); + assertThat(registration.getTermsOfServiceAgreed(), is(true)); assertThat(requestWasSent.get(), is(true)); // Subsequent queries do not trigger another load requestWasSent.set(false); - assertThat(registration.getAgreement(), is(agreementUri)); + assertThat(registration.getTermsOfServiceAgreed(), is(true)); assertThat(registration.getStatus(), is(Status.GOOD)); assertThat(requestWasSent.get(), is(false)); @@ -519,8 +519,6 @@ public class RegistrationTest { */ @Test public void testModify() throws Exception { - final URI agreementUri = URI.create("http://example.com/agreement.pdf"); - TestableConnectionProvider provider = new TestableConnectionProvider() { @Override public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { @@ -544,14 +542,6 @@ public class RegistrationTest { public URI getLocation() { return locationUri; } - - @Override - public URI getLink(String relation) { - switch(relation) { - case "terms-of-service": return agreementUri; - default: return null; - } - } }; Registration registration = new Registration(provider.createSession(), locationUri); @@ -559,13 +549,11 @@ public class RegistrationTest { EditableRegistration editable = registration.modify(); assertThat(editable, notNullValue()); - editable.setAgreement(agreementUri); editable.addContact("mailto:foo2@example.com"); editable.getContacts().add(URI.create("mailto:foo3@example.com")); editable.commit(); assertThat(registration.getLocation(), is(locationUri)); - assertThat(registration.getAgreement(), is(agreementUri)); assertThat(registration.getContacts().size(), is(2)); assertThat(registration.getContacts().get(0), is(URI.create("mailto:foo2@example.com"))); assertThat(registration.getContacts().get(1), is(URI.create("mailto:foo3@example.com"))); diff --git a/acme4j-client/src/test/resources/json.properties b/acme4j-client/src/test/resources/json.properties index 7e1a7ce1..b9ab56ed 100644 --- a/acme4j-client/src/test/resources/json.properties +++ b/acme4j-client/src/test/resources/json.properties @@ -39,6 +39,7 @@ json = \ {\ "text": "lorem ipsum",\ "number": 123,\ + "boolean": true,\ "uri": "mailto:foo@example.com",\ "url": "http://example.com",\ "date": "2016-01-08T00:00:00Z",\ @@ -48,24 +49,28 @@ json = \ newRegistration = \ {"resource":"new-reg",\ + "terms-of-service-agreed":true,\ + "contact":["mailto:foo@example.com"]} + +newRegistrationResponse = \ + {"terms-of-service-agreed":true,\ "contact":["mailto:foo@example.com"]} modifyRegistration = \ {"resource":"reg",\ - "agreement":"http://example.com/agreement.pdf",\ "contact":["mailto:foo2@example.com","mailto:foo3@example.com"]} modifyRegistrationResponse = \ - {"agreement":"http://example.com/agreement.pdf",\ + {"terms-of-service-agreed":true,\ "contact":["mailto:foo2@example.com","mailto:foo3@example.com"]} updateRegistration = \ {"resource":"reg"} updateRegistrationResponse = \ - {"agreement":"http://example.com/agreement.pdf",\ - "contact":["mailto:foo2@example.com"],\ + {"contact":["mailto:foo2@example.com"],\ "status":"good",\ + "terms-of-service-agreed":true,\ "authorizations":"https://example.com/acme/reg/1/authz",\ "certificates":"https://example.com/acme/reg/1/cert"} diff --git a/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java b/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java index 2978f194..7bea5d69 100644 --- a/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java +++ b/acme4j-example/src/main/java/org/shredzone/acme4j/ClientTest.java @@ -185,19 +185,19 @@ public class ClientTest { * @return {@link Registration} connected to your account */ private Registration findOrRegisterAccount(Session session) throws AcmeException { + // Ask the user to accept the TOS, if server provides us with a link. + URI tos = session.getMetadata().getTermsOfService(); + if (tos != null) { + acceptAgreement(tos); + } + Registration reg; try { // Try to create a new Registration. - reg = new RegistrationBuilder().create(session); + reg = new RegistrationBuilder().agreeToTermsOfService().create(session); LOG.info("Registered a new user, URI: " + reg.getLocation()); - // This is a new account. Let the user accept the Terms of Service. - // We won't be able to authorize domains until the ToS is accepted. - URI agreement = reg.getAgreement(); - LOG.info("Terms of Service: " + agreement); - acceptAgreement(reg, agreement); - } catch (AcmeConflictException ex) { // The Key Pair is already registered. getLocation() contains the // URL of the existing registration's location. Bind it to the session. @@ -433,12 +433,10 @@ public class ClientTest { * Presents the user a link to the Terms of Service, and asks for confirmation. If the * user denies confirmation, an exception is thrown. * - * @param reg - * {@link Registration} User's registration * @param agreement * {@link URI} of the Terms of Service */ - public void acceptAgreement(Registration reg, URI agreement) throws AcmeException { + public void acceptAgreement(URI agreement) throws AcmeException { int option = JOptionPane.showConfirmDialog(null, "Do you accept the Terms of Service?\n\n" + agreement, "Accept ToS", @@ -446,10 +444,6 @@ public class ClientTest { if (option == JOptionPane.NO_OPTION) { throw new AcmeException("User did not accept Terms of Service"); } - - // Motify the Registration and accept the agreement - reg.modify().setAgreement(agreement).commit(); - LOG.info("Updated user's ToS"); } /** diff --git a/src/site/markdown/usage/register.md b/src/site/markdown/usage/register.md index 3f3ba1dd..ec4affc9 100644 --- a/src/site/markdown/usage/register.md +++ b/src/site/markdown/usage/register.md @@ -2,11 +2,12 @@ If it is the first time you connect to the ACME server, you need to register your account key. -To do so, create a `RegistrationBuilder`, optionally add some contact information, then invoke `create()`. If the account was successfully created, you will get a `Registration` object in return. Invoking its `getLocation()` method will return the location URI 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. +To do so, create a `RegistrationBuilder`, optionally add some contact information, agree to the terms of service, then invoke `create()`. If the account was successfully created, you will get a `Registration` object in return. Invoking its `getLocation()` method will return the location URI 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 RegistrationBuilder builder = new RegistrationBuilder(); builder.addContact("mailto:acme@example.com"); +builder.agreeToTermsOfService(); Registration registration = builder.create(session); @@ -20,7 +21,7 @@ The following example will create a new `Registration` and restore an existing ` ```java Registration registration; try { - registration = new RegistrationBuilder().create(session); + registration = new RegistrationBuilder().agreeToTermsOfService().create(session); } catch (AcmeConflictException ex) { registration = Registration.bind(session, ex.getLocation()); } @@ -28,15 +29,15 @@ try { ## Update your Registration -At some point, you may want to update your registration. For example your contact address might have changed, or you were asked by the CA to accept the latest terms of service. To do so, invoke `Registration.modify()`, perform the changes, and invoke `commit()` to make them permanent. +At some point, you may want to update your registration. For example your contact address might have changed. To do so, invoke `Registration.modify()`, perform the changes, and invoke `commit()` to make them permanent. -The following example accepts the terms of service by explicitly setting the URL to the agreement document. +The following example adds another email address. ```java URI agreementUri = ... // TAC link provided by the CA registration.modify() - .setAgreement(agreementUri) + .addContact("mailto:acme2@example.com") .commit(); ```