Add pre-authorization support

pull/55/head
Richard Körber 2017-05-02 18:09:01 +02:00
parent 4e1ad652b0
commit 7d83ef0e80
3 changed files with 77 additions and 12 deletions

View File

@ -37,6 +37,7 @@ import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeLazyLoadingException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
import org.shredzone.acme4j.exception.AcmeServerException;
import org.shredzone.acme4j.provider.pebble.Pebble;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
@ -176,28 +177,40 @@ public class Registration extends AcmeResource {
}
/**
* Authorizes a domain. The domain is associated with this registration.
* Pre-authorizes a domain. The CA will check if it accepts the domain for
* certification, and returns the necessary challenges.
* <p>
* IDN domain names will be ACE encoded automatically.
* Some servers may not allow pre-authorization.
*
* @param domain
* Domain name to be authorized
* Domain name to be pre-authorized. IDN names are accepted and will be ACE
* encoded automatically.
* @return {@link Authorization} object for this domain
* @throws AcmeException
* if the server does not allow pre-authorization
* @throws AcmeServerException
* if the server allows pre-authorization, but will refuse to issue a
* certificate for this domain
*/
public Authorization authorizeDomain(String domain) throws AcmeException {
public Authorization preAuthorizeDomain(String domain) throws AcmeException {
Objects.requireNonNull(domain, "domain");
if (domain.isEmpty()) {
throw new IllegalArgumentException("domain must not be empty");
}
LOG.debug("authorizeDomain {}", domain);
URL newAuthzUrl = getSession().resourceUrl(Resource.NEW_AUTHZ);
if (newAuthzUrl == null) {
throw new AcmeException("Server does not allow pre-authorization");
}
LOG.debug("preAuthorizeDomain {}", domain);
try (Connection conn = getSession().provider().connect()) {
JSONBuilder claims = new JSONBuilder();
claims.object("identifier")
.put("type", "dns")
.put("value", toAce(domain));
conn.sendSignedRequest(getSession().resourceUrl(Resource.NEW_AUTHZ), claims, getSession());
conn.sendSignedRequest(newAuthzUrl, claims, getSession());
conn.accept(HttpURLConnection.HTTP_CREATED);
JSON json = conn.readJsonResponse();

View File

@ -41,6 +41,7 @@ import org.shredzone.acme4j.challenge.Dns01Challenge;
import org.shredzone.acme4j.challenge.Http01Challenge;
import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeServerException;
import org.shredzone.acme4j.provider.AcmeProvider;
import org.shredzone.acme4j.provider.TestableConnectionProvider;
import org.shredzone.acme4j.util.JSON;
@ -251,10 +252,10 @@ public class RegistrationTest {
}
/**
* Test that a new {@link Authorization} can be created.
* Test that a domain can be pre-authorized.
*/
@Test
public void testAuthorizeDomain() throws Exception {
public void testPreAuthorizeDomain() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
@ -292,7 +293,7 @@ public class RegistrationTest {
String domainName = "example.org";
Registration registration = new Registration(session, locationUrl);
Authorization auth = registration.authorizeDomain(domainName);
Authorization auth = registration.preAuthorizeDomain(domainName);
assertThat(auth.getDomain(), is(domainName));
assertThat(auth.getStatus(), is(Status.PENDING));
@ -305,29 +306,80 @@ public class RegistrationTest {
provider.close();
}
/**
* Test that a domain pre-authorization can fail.
*/
@Test
public void testNoPreAuthorizeDomain() throws Exception {
URI problemType = URI.create("urn:ietf:params:acme:error:rejectedIdentifier");
String problemDetail = "example.org is blacklisted";
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJSON("newAuthorizationRequest").toString()));
assertThat(session, is(notNullValue()));
}
@Override
public int accept(int... httpStatus) throws AcmeException {
Problem problem = TestUtils.createProblem(problemType, problemDetail, resourceUrl);
throw new AcmeServerException(problem);
}
};
Session session = provider.createSession();
provider.putTestResource(Resource.NEW_AUTHZ, resourceUrl);
Registration registration = new Registration(session, locationUrl);
try {
registration.preAuthorizeDomain("example.org");
fail("preauthorization was accepted");
} catch (AcmeServerException ex) {
assertThat(ex.getType(), is(problemType));
assertThat(ex.getMessage(), is(problemDetail));
}
provider.close();
}
/**
* Test that a bad domain parameter is not accepted.
*/
@Test
public void testAuthorizeBadDomain() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider();
// just provide a resource record so the provider returns a directory
provider.putTestResource(Resource.NEW_NONCE, resourceUrl);
Session session = provider.createSession();
Registration registration = Registration.bind(session, locationUrl);
try {
registration.authorizeDomain(null);
registration.preAuthorizeDomain(null);
fail("null domain was accepted");
} catch (NullPointerException ex) {
// expected
}
try {
registration.authorizeDomain("");
registration.preAuthorizeDomain("");
fail("empty domain string was accepted");
} catch (IllegalArgumentException ex) {
// expected
}
try {
registration.preAuthorizeDomain("example.com");
fail("preauthorization was accepted");
} catch (AcmeException ex) {
// expected
assertThat(ex.getMessage(), is("Server does not allow pre-authorization"));
}
provider.close();
}

View File

@ -209,7 +209,7 @@ public class ClientTest {
*/
private void authorize(Registration reg, String domain) throws AcmeException {
// Authorize the domain.
Authorization auth = reg.authorizeDomain(domain);
Authorization auth = reg.preAuthorizeDomain(domain);
LOG.info("Authorization for domain " + domain);
// Find the desired challenge and prepare it.