Use URL instead of URI for accessible resources

pull/55/head
Richard Körber 2017-04-18 01:17:58 +02:00
parent d1b313a149
commit f38002ca06
51 changed files with 557 additions and 486 deletions

View File

@ -14,9 +14,12 @@
package org.shredzone.acme4j; package org.shredzone.acme4j;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI; import java.net.URISyntaxException;
import java.net.URL;
import java.util.Objects; import java.util.Objects;
import org.shredzone.acme4j.exception.AcmeProtocolException;
/** /**
* A generic ACME resource. * A generic ACME resource.
*/ */
@ -24,7 +27,7 @@ public abstract class AcmeResource implements Serializable {
private static final long serialVersionUID = -7930580802257379731L; private static final long serialVersionUID = -7930580802257379731L;
private transient Session session; private transient Session session;
private URI location; private URL location;
/** /**
* Create a new {@link AcmeResource}. * Create a new {@link AcmeResource}.
@ -57,9 +60,13 @@ public abstract class AcmeResource implements Serializable {
/** /**
* Sets the resource's location. * Sets the resource's location.
*/ */
protected void setLocation(URI location) { protected void setLocation(URL location) {
this.location = Objects.requireNonNull(location, "location"); this.location = Objects.requireNonNull(location, "location");
session.setKeyIdentifier(this.location); try {
session.setKeyIdentifier(this.location.toURI());
} catch (URISyntaxException ex) {
throw new AcmeProtocolException("Location cannot be used as key identifier", ex);
}
} }
/** /**
@ -82,7 +89,7 @@ public abstract class AcmeResource implements Serializable {
/** /**
* Gets the resource's location. * Gets the resource's location.
*/ */
public URI getLocation() { public URL getLocation() {
return location; return location;
} }

View File

@ -17,7 +17,7 @@ import static java.util.stream.Collectors.toList;
import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp; import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -49,7 +49,7 @@ public class Authorization extends AcmeResource {
private List<List<Challenge>> combinations; private List<List<Challenge>> combinations;
private boolean loaded = false; private boolean loaded = false;
protected Authorization(Session session, URI location) { protected Authorization(Session session, URL location) {
super(session); super(session);
setLocation(location); setLocation(location);
} }
@ -64,7 +64,7 @@ public class Authorization extends AcmeResource {
* Location of the Authorization * Location of the Authorization
* @return {@link Authorization} bound to the session and location * @return {@link Authorization} bound to the session and location
*/ */
public static Authorization bind(Session session, URI location) { public static Authorization bind(Session session, URL location) {
return new Authorization(session, location); return new Authorization(session, location);
} }

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j; package org.shredzone.acme4j;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
@ -37,19 +37,19 @@ public class Certificate extends AcmeResource {
private static final Logger LOG = LoggerFactory.getLogger(Certificate.class); private static final Logger LOG = LoggerFactory.getLogger(Certificate.class);
private static final int MAX_CHAIN_LENGTH = 10; private static final int MAX_CHAIN_LENGTH = 10;
private URI chainCertUri; private URL chainCertUrl;
private X509Certificate cert = null; private X509Certificate cert = null;
private X509Certificate[] chain = null; private X509Certificate[] chain = null;
protected Certificate(Session session, URI certUri) { protected Certificate(Session session, URL certUrl) {
super(session); super(session);
setLocation(certUri); setLocation(certUrl);
} }
protected Certificate(Session session, URI certUri, URI chainUri, X509Certificate cert) { protected Certificate(Session session, URL certUrl, URL chainUrl, X509Certificate cert) {
super(session); super(session);
setLocation(certUri); setLocation(certUrl);
this.chainCertUri = chainUri; this.chainCertUrl = chainUrl;
this.cert = cert; this.cert = cert;
} }
@ -62,16 +62,16 @@ public class Certificate extends AcmeResource {
* Location of the Certificate * Location of the Certificate
* @return {@link Certificate} bound to the session and location * @return {@link Certificate} bound to the session and location
*/ */
public static Certificate bind(Session session, URI location) { public static Certificate bind(Session session, URL location) {
return new Certificate(session, location); return new Certificate(session, location);
} }
/** /**
* Returns the URI of the certificate chain. {@code null} if not known or not * Returns the URL of the certificate chain. {@code null} if not known or not
* available. * available.
*/ */
public URI getChainLocation() { public URL getChainLocation() {
return chainCertUri; return chainCertUrl;
} }
/** /**
@ -92,7 +92,7 @@ public class Certificate extends AcmeResource {
conn.accept(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED); conn.accept(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED);
conn.handleRetryAfter("certificate is not available for download yet"); conn.handleRetryAfter("certificate is not available for download yet");
chainCertUri = conn.getLink("up"); chainCertUrl = conn.getLink("up");
cert = conn.readCertificate(); cert = conn.readCertificate();
} }
} }
@ -111,21 +111,21 @@ public class Certificate extends AcmeResource {
*/ */
public X509Certificate[] downloadChain() throws AcmeException { public X509Certificate[] downloadChain() throws AcmeException {
if (chain == null) { if (chain == null) {
if (chainCertUri == null) { if (chainCertUrl == null) {
download(); download();
} }
if (chainCertUri == null) { if (chainCertUrl == null) {
throw new AcmeProtocolException("No certificate chain provided"); throw new AcmeProtocolException("No certificate chain provided");
} }
LOG.debug("downloadChain"); LOG.debug("downloadChain");
List<X509Certificate> certChain = new ArrayList<>(); List<X509Certificate> certChain = new ArrayList<>();
URI link = chainCertUri; URL link = chainCertUrl;
while (link != null && certChain.size() < MAX_CHAIN_LENGTH) { while (link != null && certChain.size() < MAX_CHAIN_LENGTH) {
try (Connection conn = getSession().provider().connect()) { try (Connection conn = getSession().provider().connect()) {
conn.sendRequest(chainCertUri, getSession()); conn.sendRequest(chainCertUrl, getSession());
conn.accept(HttpURLConnection.HTTP_OK); conn.accept(HttpURLConnection.HTTP_OK);
certChain.add(conn.readCertificate()); certChain.add(conn.readCertificate());
@ -159,8 +159,8 @@ public class Certificate extends AcmeResource {
*/ */
public void revoke(RevocationReason reason) throws AcmeException { public void revoke(RevocationReason reason) throws AcmeException {
LOG.debug("revoke"); LOG.debug("revoke");
URI resUri = getSession().resourceUri(Resource.REVOKE_CERT); URL resUrl = getSession().resourceUrl(Resource.REVOKE_CERT);
if (resUri == null) { if (resUrl == null) {
throw new AcmeProtocolException("CA does not support certificate revocation"); throw new AcmeProtocolException("CA does not support certificate revocation");
} }
@ -176,7 +176,7 @@ public class Certificate extends AcmeResource {
claims.put("reason", reason.getReasonCode()); claims.put("reason", reason.getReasonCode());
} }
conn.sendSignedRequest(resUri, claims, getSession()); conn.sendSignedRequest(resUrl, claims, getSession());
conn.accept(HttpURLConnection.HTTP_OK); conn.accept(HttpURLConnection.HTTP_OK);
} catch (CertificateEncodingException ex) { } catch (CertificateEncodingException ex) {
throw new AcmeProtocolException("Invalid certificate", ex); throw new AcmeProtocolException("Invalid certificate", ex);

View File

@ -16,6 +16,7 @@ package org.shredzone.acme4j;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.Collection; import java.util.Collection;
import org.shredzone.acme4j.util.JSON; import org.shredzone.acme4j.util.JSON;
@ -47,11 +48,11 @@ public class Metadata {
} }
/** /**
* Returns an {@link URI} to a website providing more information about the ACME * Returns an {@link URL} to a website providing more information about the ACME
* server. {@code null} if not available. * server. {@code null} if not available.
*/ */
public URI getWebsite() { public URL getWebsite() {
return meta.get("website").asURI(); return meta.get("website").asURL();
} }
/** /**

View File

@ -17,6 +17,7 @@ import static org.shredzone.acme4j.util.AcmeUtils.*;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.time.Instant; import java.time.Instant;
@ -57,11 +58,11 @@ public class Registration extends AcmeResource {
private final List<URI> contacts = new ArrayList<>(); private final List<URI> contacts = new ArrayList<>();
private Status status; private Status status;
private Boolean termsOfServiceAgreed; private Boolean termsOfServiceAgreed;
private URI authorizations; private URL authorizations;
private URI certificates; private URL certificates;
private boolean loaded = false; private boolean loaded = false;
protected Registration(Session session, URI location) { protected Registration(Session session, URL location) {
super(session); super(session);
setLocation(location); setLocation(location);
} }
@ -75,7 +76,7 @@ public class Registration extends AcmeResource {
* Location URI of the registration * Location URI of the registration
* @return {@link Registration} bound to the session and location * @return {@link Registration} bound to the session and location
*/ */
public static Registration bind(Session session, URI location) { public static Registration bind(Session session, URL location) {
return new Registration(session, location); return new Registration(session, location);
} }
@ -180,7 +181,7 @@ public class Registration extends AcmeResource {
.put("type", "dns") .put("type", "dns")
.put("value", toAce(domain)); .put("value", toAce(domain));
conn.sendSignedRequest(getSession().resourceUri(Resource.NEW_AUTHZ), claims, getSession()); conn.sendSignedRequest(getSession().resourceUrl(Resource.NEW_AUTHZ), claims, getSession());
conn.accept(HttpURLConnection.HTTP_CREATED); conn.accept(HttpURLConnection.HTTP_CREATED);
JSON json = conn.readJsonResponse(); JSON json = conn.readJsonResponse();
@ -235,7 +236,7 @@ public class Registration extends AcmeResource {
claims.put("notAfter", notAfter); claims.put("notAfter", notAfter);
} }
conn.sendSignedRequest(getSession().resourceUri(Resource.NEW_CERT), claims, getSession()); conn.sendSignedRequest(getSession().resourceUrl(Resource.NEW_CERT), claims, getSession());
int rc = conn.accept(HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_ACCEPTED); int rc = conn.accept(HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_ACCEPTED);
X509Certificate cert = null; X509Certificate cert = null;
@ -247,9 +248,9 @@ public class Registration extends AcmeResource {
} }
} }
URI chainCertUri = conn.getLink("up"); URL chainCertUrl = conn.getLink("up");
return new Certificate(getSession(), conn.getLocation(), chainCertUri, cert); return new Certificate(getSession(), conn.getLocation(), chainCertUrl, cert);
} }
} }
@ -272,7 +273,7 @@ public class Registration extends AcmeResource {
LOG.debug("key-change"); LOG.debug("key-change");
try (Connection conn = getSession().provider().connect()) { try (Connection conn = getSession().provider().connect()) {
URI keyChangeUri = getSession().resourceUri(Resource.KEY_CHANGE); URL keyChangeUrl = getSession().resourceUrl(Resource.KEY_CHANGE);
PublicJsonWebKey newKeyJwk = PublicJsonWebKey.Factory.newPublicJwk(newKeyPair.getPublic()); PublicJsonWebKey newKeyJwk = PublicJsonWebKey.Factory.newPublicJwk(newKeyPair.getPublic());
JSONBuilder payloadClaim = new JSONBuilder(); JSONBuilder payloadClaim = new JSONBuilder();
@ -281,7 +282,7 @@ public class Registration extends AcmeResource {
JsonWebSignature innerJws = new JsonWebSignature(); JsonWebSignature innerJws = new JsonWebSignature();
innerJws.setPayload(payloadClaim.toString()); innerJws.setPayload(payloadClaim.toString());
innerJws.getHeaders().setObjectHeaderValue("url", keyChangeUri); innerJws.getHeaders().setObjectHeaderValue("url", keyChangeUrl);
innerJws.getHeaders().setJwkHeaderValue("jwk", newKeyJwk); innerJws.getHeaders().setJwkHeaderValue("jwk", newKeyJwk);
innerJws.setAlgorithmHeaderValue(keyAlgorithm(newKeyJwk)); innerJws.setAlgorithmHeaderValue(keyAlgorithm(newKeyJwk));
innerJws.setKey(newKeyPair.getPrivate()); innerJws.setKey(newKeyPair.getPrivate());
@ -293,7 +294,7 @@ public class Registration extends AcmeResource {
outerClaim.put("signature", innerJws.getEncodedSignature()); outerClaim.put("signature", innerJws.getEncodedSignature());
outerClaim.put("payload", innerJws.getEncodedPayload()); outerClaim.put("payload", innerJws.getEncodedPayload());
conn.sendSignedRequest(keyChangeUri, outerClaim, getSession()); conn.sendSignedRequest(keyChangeUrl, outerClaim, getSession());
conn.accept(HttpURLConnection.HTTP_OK); conn.accept(HttpURLConnection.HTTP_OK);
getSession().setKeyPair(newKeyPair); getSession().setKeyPair(newKeyPair);
@ -356,14 +357,14 @@ public class Registration extends AcmeResource {
.forEach(contacts::add); .forEach(contacts::add);
} }
this.authorizations = json.get(KEY_AUTHORIZATIONS).asURI(); this.authorizations = json.get(KEY_AUTHORIZATIONS).asURL();
this.certificates = json.get(KEY_CERTIFICATES).asURI(); this.certificates = json.get(KEY_CERTIFICATES).asURL();
if (json.contains(KEY_STATUS)) { if (json.contains(KEY_STATUS)) {
this.status = Status.parse(json.get(KEY_STATUS).asString()); this.status = Status.parse(json.get(KEY_STATUS).asString());
} }
URI location = conn.getLocation(); URL location = conn.getLocation();
if (location != null) { if (location != null) {
setLocation(location); setLocation(location);
} }

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -101,10 +102,10 @@ public class RegistrationBuilder {
claims.put("terms-of-service-agreed", termsOfServiceAgreed); claims.put("terms-of-service-agreed", termsOfServiceAgreed);
} }
conn.sendJwkSignedRequest(session.resourceUri(Resource.NEW_REG), claims, session); conn.sendJwkSignedRequest(session.resourceUrl(Resource.NEW_REG), claims, session);
conn.accept(HttpURLConnection.HTTP_CREATED); conn.accept(HttpURLConnection.HTTP_CREATED);
URI location = conn.getLocation(); URL location = conn.getLocation();
return new Registration(session, location); return new Registration(session, location);
} }

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j; package org.shredzone.acme4j;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@ -40,7 +41,7 @@ import org.shredzone.acme4j.util.JSON;
* volatile data. * volatile data.
*/ */
public class Session { public class Session {
private final AtomicReference<Map<Resource, URI>> resourceMap = new AtomicReference<>(); private final AtomicReference<Map<Resource, URL>> resourceMap = new AtomicReference<>();
private final AtomicReference<Metadata> metadata = new AtomicReference<>(); private final AtomicReference<Metadata> metadata = new AtomicReference<>();
private final URI serverUri; private final URI serverUri;
private final AcmeProvider provider; private final AcmeProvider provider;
@ -190,14 +191,14 @@ public class Session {
} }
/** /**
* Gets the {@link URI} 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 getting a directory. The result is cached.
* *
* @param resource * @param resource
* {@link Resource} to get the {@link URI} of * {@link Resource} to get the {@link URL} of
* @return {@link URI}, or {@code null} if the server does not offer that resource * @return {@link URL}, or {@code null} if the server does not offer that resource
*/ */
public URI resourceUri(Resource resource) throws AcmeException { public URL resourceUrl(Resource resource) throws AcmeException {
readDirectory(); readDirectory();
return resourceMap.get().get(Objects.requireNonNull(resource, "resource")); return resourceMap.get().get(Objects.requireNonNull(resource, "resource"));
} }
@ -234,11 +235,11 @@ public class Session {
metadata.set(new Metadata(JSON.empty())); metadata.set(new Metadata(JSON.empty()));
} }
Map<Resource, URI> map = new EnumMap<>(Resource.class); Map<Resource, URL> map = new EnumMap<>(Resource.class);
for (Resource res : Resource.values()) { for (Resource res : Resource.values()) {
URI uri = directoryJson.get(res.path()).asURI(); URL url = directoryJson.get(res.path()).asURL();
if (uri != null) { if (url != null) {
map.put(res, uri); map.put(res, url);
} }
} }
resourceMap.set(map); resourceMap.set(map);

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j.challenge; package org.shredzone.acme4j.challenge;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.time.Instant; import java.time.Instant;
import java.util.Objects; import java.util.Objects;
@ -70,7 +70,7 @@ public class Challenge extends AcmeResource {
* @return {@link Challenge} bound to this session and location * @return {@link Challenge} bound to this session and location
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends Challenge> T bind(Session session, URI location) throws AcmeException { public static <T extends Challenge> T bind(Session session, URL location) throws AcmeException {
Objects.requireNonNull(session, "session"); Objects.requireNonNull(session, "session");
Objects.requireNonNull(location, "location"); Objects.requireNonNull(location, "location");
@ -103,11 +103,11 @@ public class Challenge extends AcmeResource {
} }
/** /**
* Returns the location {@link URI} of the challenge. * Returns the location {@link URL} of the challenge.
*/ */
@Override @Override
public URI getLocation() { public URL getLocation() {
return data.get(KEY_URI).asURI(); return data.get(KEY_URI).asURL();
} }
/** /**

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.connector; package org.shredzone.acme4j.connector;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Collection; import java.util.Collection;
@ -39,38 +40,38 @@ public interface Connection extends AutoCloseable {
/** /**
* Sends a simple GET request. * Sends a simple GET request.
* *
* @param uri * @param url
* {@link URI} to send the request to. * {@link URL} to send the request to.
* @param session * @param session
* {@link Session} instance to be used for tracking * {@link Session} instance to be used for tracking
*/ */
void sendRequest(URI uri, Session session) throws AcmeException; void sendRequest(URL url, Session session) throws AcmeException;
/** /**
* Sends a signed POST request. Ensures that the session has a KeyIdentifier set that * Sends a signed POST request. Ensures that the session has a KeyIdentifier set that
* is used in the "kid" protected header. * is used in the "kid" protected header.
* *
* @param uri * @param url
* {@link URI} to send the request to. * {@link URL} to send the request to.
* @param claims * @param claims
* {@link JSONBuilder} containing claims. Must not be {@code null}. * {@link JSONBuilder} containing claims. Must not be {@code null}.
* @param session * @param session
* {@link Session} instance to be used for signing and tracking * {@link Session} instance to be used for signing and tracking
*/ */
void sendSignedRequest(URI uri, JSONBuilder claims, Session session) throws AcmeException; void sendSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException;
/** /**
* Sends a signed POST request. If the session's KeyIdentifier is set, a "kid" * Sends a signed POST request. If the session's KeyIdentifier is set, a "kid"
* protected header is sent. If not, a "jwk" protected header is sent. * protected header is sent. If not, a "jwk" protected header is sent.
* *
* @param uri * @param url
* {@link URI} to send the request to. * {@link URL} to send the request to.
* @param claims * @param claims
* {@link JSONBuilder} containing claims. Must not be {@code null}. * {@link JSONBuilder} containing claims. Must not be {@code null}.
* @param session * @param session
* {@link Session} instance to be used for signing and tracking * {@link Session} instance to be used for signing and tracking
*/ */
void sendJwkSignedRequest(URI uri, JSONBuilder claims, Session session) throws AcmeException; void sendJwkSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException;
/** /**
* Checks if the HTTP response status is in the given list of acceptable HTTP states, * Checks if the HTTP response status is in the given list of acceptable HTTP states,
@ -118,12 +119,12 @@ public interface Connection extends AutoCloseable {
* <p> * <p>
* Relative links are resolved against the last request's URL. * Relative links are resolved against the last request's URL.
* *
* @return Location {@link URI}, or {@code null} if no Location header was set * @return Location {@link URL}, or {@code null} if no Location header was set
*/ */
URI getLocation(); URL getLocation();
/** /**
* Gets a relation link from the header. * Gets a relation link from the header. The result is expected to be an URL.
* <p> * <p>
* Relative links are resolved against the last request's URL. If there is more than * Relative links are resolved against the last request's URL. If there is more than
* one relation, the first one is returned. * one relation, the first one is returned.
@ -132,10 +133,10 @@ public interface Connection extends AutoCloseable {
* Link relation * Link relation
* @return Link, or {@code null} if there was no such relation link * @return Link, or {@code null} if there was no such relation link
*/ */
URI getLink(String relation); URL getLink(String relation);
/** /**
* Gets one or more relation link from the header. * Gets one or more relation links from the header.
* <p> * <p>
* Relative links are resolved against the last request's URL. * Relative links are resolved against the last request's URL.
* *

View File

@ -97,9 +97,9 @@ public class DefaultConnection implements Connection {
try { try {
session.setNonce(null); session.setNonce(null);
URI newNonceUri = session.resourceUri(Resource.NEW_NONCE); URL newNonceUrl = session.resourceUrl(Resource.NEW_NONCE);
conn = httpConnector.openConnection(newNonceUri); conn = httpConnector.openConnection(newNonceUrl);
conn.setRequestMethod("HEAD"); conn.setRequestMethod("HEAD");
conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag());
conn.connect(); conn.connect();
@ -123,15 +123,15 @@ public class DefaultConnection implements Connection {
} }
@Override @Override
public void sendRequest(URI uri, Session session) throws AcmeException { public void sendRequest(URL url, Session session) throws AcmeException {
Objects.requireNonNull(uri, "uri"); Objects.requireNonNull(url, "url");
Objects.requireNonNull(session, "session"); Objects.requireNonNull(session, "session");
assertConnectionIsClosed(); assertConnectionIsClosed();
LOG.debug("GET {}", uri); LOG.debug("GET {}", url);
try { try {
conn = httpConnector.openConnection(uri); conn = httpConnector.openConnection(url);
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET);
conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag());
@ -146,17 +146,17 @@ public class DefaultConnection implements Connection {
} }
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) throws AcmeException { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException {
if (session.getKeyIdentifier() == null) { if (session.getKeyIdentifier() == null) {
throw new IllegalStateException("session has no KeyIdentifier set"); throw new IllegalStateException("session has no KeyIdentifier set");
} }
sendJwkSignedRequest(uri, claims, session); sendJwkSignedRequest(url, claims, session);
} }
@Override @Override
public void sendJwkSignedRequest(URI uri, JSONBuilder claims, Session session) throws AcmeException { public void sendJwkSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException {
Objects.requireNonNull(uri, "uri"); Objects.requireNonNull(url, "url");
Objects.requireNonNull(claims, "claims"); Objects.requireNonNull(claims, "claims");
Objects.requireNonNull(session, "session"); Objects.requireNonNull(session, "session");
assertConnectionIsClosed(); assertConnectionIsClosed();
@ -168,9 +168,9 @@ public class DefaultConnection implements Connection {
resetNonce(session); resetNonce(session);
} }
LOG.debug("POST {} with claims: {}", uri, claims); LOG.debug("POST {} with claims: {}", url, claims);
conn = httpConnector.openConnection(uri); conn = httpConnector.openConnection(url);
conn.setRequestMethod("POST"); conn.setRequestMethod("POST");
conn.setRequestProperty(ACCEPT_HEADER, "application/json"); conn.setRequestProperty(ACCEPT_HEADER, "application/json");
conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET);
@ -182,7 +182,7 @@ public class DefaultConnection implements Connection {
JsonWebSignature jws = new JsonWebSignature(); JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toString()); jws.setPayload(claims.toString());
jws.getHeaders().setObjectHeaderValue("nonce", Base64Url.encode(session.getNonce())); jws.getHeaders().setObjectHeaderValue("nonce", Base64Url.encode(session.getNonce()));
jws.getHeaders().setObjectHeaderValue("url", uri); jws.getHeaders().setObjectHeaderValue("url", url);
if (session.getKeyIdentifier() != null) { if (session.getKeyIdentifier() != null) {
jws.getHeaders().setObjectHeaderValue("kid", session.getKeyIdentifier()); jws.getHeaders().setObjectHeaderValue("kid", session.getKeyIdentifier());
} else { } else {
@ -317,7 +317,7 @@ public class DefaultConnection implements Connection {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
assertConnectionIsOpen(); assertConnectionIsOpen();
String location = conn.getHeaderField(LOCATION_HEADER); String location = conn.getHeaderField(LOCATION_HEADER);
@ -326,11 +326,11 @@ public class DefaultConnection implements Connection {
} }
LOG.debug("Location: {}", location); LOG.debug("Location: {}", location);
return resolveRelative(location); return toURL(resolveRelative(location));
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
Collection<URI> links = getLinks(relation); Collection<URI> links = getLinks(relation);
if (links == null) { if (links == null) {
return null; return null;
@ -340,7 +340,7 @@ public class DefaultConnection implements Connection {
LOG.debug("Link: {} - using the first of {}", relation, links.size()); LOG.debug("Link: {} - using the first of {}", relation, links.size());
} }
return links.iterator().next(); return toURL(links.iterator().next());
} }
@Override @Override
@ -418,8 +418,8 @@ public class DefaultConnection implements Connection {
if ("agreementRequired".equals(error)) { if ("agreementRequired".equals(error)) {
URI instance = resolveRelative(json.get("instance").asString()); URI instance = resolveRelative(json.get("instance").asString());
URI tos = getLink("terms-of-service"); URI tos = getLinks("terms-of-service").stream().findFirst().orElse(null);
return new AcmeAgreementRequiredException(type, detail, tos, instance); return new AcmeAgreementRequiredException(type, detail, tos, toURL(instance));
} }
if ("rateLimited".equals(error)) { if ("rateLimited".equals(error)) {
@ -465,7 +465,7 @@ public class DefaultConnection implements Connection {
} }
/** /**
* Resolves a relative link against the connection's last URI. * Resolves a relative link against the connection's last URL.
* *
* @param link * @param link
* Link to resolve. Absolute links are just converted to an URI. May be * Link to resolve. Absolute links are just converted to an URI. May be
@ -480,10 +480,27 @@ public class DefaultConnection implements Connection {
assertConnectionIsOpen(); assertConnectionIsOpen();
try { try {
return new URL(conn.getURL(), link).toURI(); return conn.getURL().toURI().resolve(link);
} catch (MalformedURLException | URISyntaxException ex) { } catch (URISyntaxException ex) {
throw new AcmeProtocolException("Cannot resolve relative link: " + link, ex); throw new AcmeProtocolException("Cannot resolve relative link: " + link, ex);
} }
} }
/**
* Converts {@link URI} to {@link URL}.
*
* @param uri
* {@link URI} to convert
* @return {@link URL}
* @throws AcmeProtocolException
* if the URI could not be converted to URL
*/
private static URL toURL(URI uri) {
try {
return uri.toURL();
} catch (MalformedURLException ex) {
throw new AcmeProtocolException("Invalid URL: " + uri, ex);
}
}
} }

View File

@ -16,7 +16,7 @@ package org.shredzone.acme4j.connector;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.util.Properties; import java.util.Properties;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -59,14 +59,14 @@ public class HttpConnector {
} }
/** /**
* Opens a {@link HttpURLConnection} to the given {@link URI}. * Opens a {@link HttpURLConnection} to the given {@link URL}.
* *
* @param uri * @param url
* {@link URI} to connect to * {@link URL} to connect to
* @return {@link HttpURLConnection} connected to the {@link URI} * @return {@link HttpURLConnection} connected to the {@link URL}
*/ */
public HttpURLConnection openConnection(URI uri) throws IOException { public HttpURLConnection openConnection(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection(); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
configure(conn); configure(conn);
return conn; return conn;
} }

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j.connector; package org.shredzone.acme4j.connector;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;
import java.util.Iterator; import java.util.Iterator;
@ -29,7 +29,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.util.JSON; import org.shredzone.acme4j.util.JSON;
/** /**
* An {@link Iterator} that fetches a batch of URIs from the ACME server, and generates * An {@link Iterator} that fetches a batch of URLs from the ACME server, and generates
* {@link AcmeResource} instances. * {@link AcmeResource} instances.
* *
* @param <T> * @param <T>
@ -39,10 +39,10 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
private final Session session; private final Session session;
private final String field; private final String field;
private final Deque<URI> uriList = new ArrayDeque<>(); private final Deque<URL> urlList = new ArrayDeque<>();
private final BiFunction<Session, URI, T> creator; private final BiFunction<Session, URL, T> creator;
private boolean eol = false; private boolean eol = false;
private URI nextUri; private URL nextUrl;
/** /**
* Creates a new {@link ResourceIterator}. * Creates a new {@link ResourceIterator}.
@ -52,15 +52,15 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
* @param field * @param field
* Field name to be used in the JSON response * Field name to be used in the JSON response
* @param start * @param start
* URI of the first JSON array, may be {@code null} for an empty iterator * URL of the first JSON array, may be {@code null} for an empty iterator
* @param creator * @param creator
* Creator for an {@link AcmeResource} that is bound to the given * Creator for an {@link AcmeResource} that is bound to the given
* {@link Session} and {@link URI}. * {@link Session} and {@link URL}.
*/ */
public ResourceIterator(Session session, String field, URI start, BiFunction<Session, URI, T> creator) { public ResourceIterator(Session session, String field, URL start, BiFunction<Session, URL, T> creator) {
this.session = Objects.requireNonNull(session, "session"); this.session = Objects.requireNonNull(session, "session");
this.field = Objects.requireNonNull(field, "field"); this.field = Objects.requireNonNull(field, "field");
this.nextUri = start; this.nextUrl = start;
this.creator = Objects.requireNonNull(creator, "creator"); this.creator = Objects.requireNonNull(creator, "creator");
} }
@ -68,7 +68,7 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
* Checks if there is another object in the result. * Checks if there is another object in the result.
* *
* @throws AcmeProtocolException * @throws AcmeProtocolException
* if the next batch of URIs could not be fetched from the server * if the next batch of URLs could not be fetched from the server
*/ */
@Override @Override
public boolean hasNext() { public boolean hasNext() {
@ -76,32 +76,32 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
return false; return false;
} }
if (uriList.isEmpty()) { if (urlList.isEmpty()) {
fetch(); fetch();
} }
if (uriList.isEmpty()) { if (urlList.isEmpty()) {
eol = true; eol = true;
} }
return !uriList.isEmpty(); return !urlList.isEmpty();
} }
/** /**
* Returns the next object of the result. * Returns the next object of the result.
* *
* @throws AcmeProtocolException * @throws AcmeProtocolException
* if the next batch of URIs could not be fetched from the server * if the next batch of URLs could not be fetched from the server
* @throws NoSuchElementException * @throws NoSuchElementException
* if there are no more entries * if there are no more entries
*/ */
@Override @Override
public T next() { public T next() {
if (!eol && uriList.isEmpty()) { if (!eol && urlList.isEmpty()) {
fetch(); fetch();
} }
URI next = uriList.poll(); URL next = urlList.poll();
if (next == null) { if (next == null) {
eol = true; eol = true;
throw new NoSuchElementException("no more " + field); throw new NoSuchElementException("no more " + field);
@ -119,11 +119,11 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
} }
/** /**
* Fetches the next batch of URIs. Handles exceptions. Does nothing if there is no * Fetches the next batch of URLs. Handles exceptions. Does nothing if there is no
* URI of the next batch. * URL of the next batch.
*/ */
private void fetch() { private void fetch() {
if (nextUri == null) { if (nextUrl == null) {
return; return;
} }
@ -135,31 +135,31 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
} }
/** /**
* Reads the next batch of URIs from the server, and fills the queue with the URIs. If * Reads the next batch of URLs from the server, and fills the queue with the URLs. If
* there is a "next" header, it is used for the next batch of URIs. * there is a "next" header, it is used for the next batch of URLs.
*/ */
private void readAndQueue() throws AcmeException { private void readAndQueue() throws AcmeException {
try (Connection conn = session.provider().connect()) { try (Connection conn = session.provider().connect()) {
conn.sendRequest(nextUri, session); conn.sendRequest(nextUrl, session);
conn.accept(HttpURLConnection.HTTP_OK); conn.accept(HttpURLConnection.HTTP_OK);
JSON json = conn.readJsonResponse(); JSON json = conn.readJsonResponse();
fillUriList(json); fillUrlList(json);
nextUri = conn.getLink("next"); nextUrl = conn.getLink("next");
} }
} }
/** /**
* Fills the uri list with the URIs found in the desired field. * Fills the url list with the URLs found in the desired field.
* *
* @param json * @param json
* JSON map to read from * JSON map to read from
*/ */
private void fillUriList(JSON json) { private void fillUrlList(JSON json) {
json.get(field).asArray().stream() json.get(field).asArray().stream()
.map(JSON.Value::asURI) .map(JSON.Value::asURL)
.forEach(uriList::add); .forEach(urlList::add);
} }
} }

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.exception; package org.shredzone.acme4j.exception;
import java.net.URI; import java.net.URI;
import java.net.URL;
/** /**
* An exception that is thrown when the client needs to accept the terms of service in * An exception that is thrown when the client needs to accept the terms of service in
@ -23,7 +24,7 @@ public class AcmeAgreementRequiredException extends AcmeServerException {
private static final long serialVersionUID = 7719055447283858352L; private static final long serialVersionUID = 7719055447283858352L;
private final URI agreementUri; private final URI agreementUri;
private final URI instance; private final URL instance;
/** /**
* Creates a new {@link AcmeAgreementRequiredException}. * Creates a new {@link AcmeAgreementRequiredException}.
@ -36,10 +37,10 @@ public class AcmeAgreementRequiredException extends AcmeServerException {
* @param agreementUri * @param agreementUri
* {@link URI} of the agreement document to accept * {@link URI} of the agreement document to accept
* @param instance * @param instance
* {@link URI} to be visited by a human, showing instructions for how to * {@link URL} to be visited by a human, showing instructions for how to
* agree to the terms and conditions. * agree to the terms and conditions.
*/ */
public AcmeAgreementRequiredException(String type, String detail, URI agreementUri, URI instance) { public AcmeAgreementRequiredException(String type, String detail, URI agreementUri, URL instance) {
super(type, detail); super(type, detail);
this.agreementUri = agreementUri; this.agreementUri = agreementUri;
this.instance = instance; this.instance = instance;
@ -54,10 +55,10 @@ public class AcmeAgreementRequiredException extends AcmeServerException {
} }
/** /**
* Returns the {@link URI} of a document showing a human how to agree to the terms and * Returns the {@link URL} of a document showing a human how to agree to the terms and
* conditions, or {@code null} if the server did not provide such a link. * conditions, or {@code null} if the server did not provide such a link.
*/ */
public URI getInstance() { public URL getInstance() {
return instance; return instance;
} }

View File

@ -13,7 +13,7 @@
*/ */
package org.shredzone.acme4j.exception; package org.shredzone.acme4j.exception;
import java.net.URI; import java.net.URL;
import java.util.Objects; import java.util.Objects;
/** /**
@ -23,7 +23,7 @@ import java.util.Objects;
public class AcmeConflictException extends AcmeException { public class AcmeConflictException extends AcmeException {
private static final long serialVersionUID = 7454201988845449591L; private static final long serialVersionUID = 7454201988845449591L;
private final URI location; private final URL location;
/** /**
* Creates a new {@link AcmeConflictException}. * Creates a new {@link AcmeConflictException}.
@ -31,9 +31,9 @@ public class AcmeConflictException extends AcmeException {
* @param msg * @param msg
* Details about the conflicting resource * Details about the conflicting resource
* @param location * @param location
* {@link URI} of the conflicting resource * {@link URL} of the conflicting resource
*/ */
public AcmeConflictException(String msg, URI location) { public AcmeConflictException(String msg, URL location) {
super(msg); super(msg);
this.location = Objects.requireNonNull(location, "location"); this.location = Objects.requireNonNull(location, "location");
} }
@ -41,7 +41,7 @@ public class AcmeConflictException extends AcmeException {
/** /**
* Location of the conflicting resource. * Location of the conflicting resource.
*/ */
public URI getLocation() { public URL getLocation() {
return location; return location;
} }

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.provider; package org.shredzone.acme4j.provider;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import org.shredzone.acme4j.Session; import org.shredzone.acme4j.Session;
@ -41,15 +42,15 @@ public interface AcmeProvider {
boolean accepts(URI serverUri); boolean accepts(URI serverUri);
/** /**
* Resolves the server URI and returns the matching directory URI. * Resolves the server URI and returns the matching directory URL.
* *
* @param serverUri * @param serverUri
* Server {@link URI} * Server {@link URI}
* @return Resolved directory {@link URI} * @return Resolved directory {@link URL}
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if the server {@link URI} is not accepted * if the server {@link URI} is not accepted
*/ */
URI resolve(URI serverUri); URL resolve(URI serverUri);
/** /**
* Creates a {@link Connection} for communication with the ACME server. * Creates a {@link Connection} for communication with the ACME server.

View File

@ -13,7 +13,9 @@
*/ */
package org.shredzone.acme4j.provider; package org.shredzone.acme4j.provider;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL;
/** /**
* A generic {@link AcmeProvider}. It should be working for all ACME servers complying to * A generic {@link AcmeProvider}. It should be working for all ACME servers complying to
@ -30,8 +32,12 @@ public class GenericAcmeProvider extends AbstractAcmeProvider {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
return serverUri; try {
return serverUri.toURL();
} catch (MalformedURLException ex) {
throw new IllegalArgumentException("Bad generic server URI", ex);
}
} }
} }

View File

@ -13,8 +13,9 @@
*/ */
package org.shredzone.acme4j.provider.letsencrypt; package org.shredzone.acme4j.provider.letsencrypt;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URL;
import org.shredzone.acme4j.connector.HttpConnector; import org.shredzone.acme4j.connector.HttpConnector;
import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.exception.AcmeProtocolException;
@ -34,8 +35,8 @@ import org.shredzone.acme4j.provider.AcmeProvider;
*/ */
public class LetsEncryptAcmeProvider extends AbstractAcmeProvider { public class LetsEncryptAcmeProvider extends AbstractAcmeProvider {
private static final String V01_DIRECTORY_URI = "https://acme-v01.api.letsencrypt.org/directory"; private static final String V01_DIRECTORY_URL = "https://acme-v01.api.letsencrypt.org/directory";
private static final String STAGING_DIRECTORY_URI = "https://acme-staging.api.letsencrypt.org/directory"; private static final String STAGING_DIRECTORY_URL = "https://acme-staging.api.letsencrypt.org/directory";
@Override @Override
public boolean accepts(URI serverUri) { public boolean accepts(URI serverUri) {
@ -44,21 +45,21 @@ public class LetsEncryptAcmeProvider extends AbstractAcmeProvider {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
String path = serverUri.getPath(); String path = serverUri.getPath();
String directoryUri; String directoryUrl;
if (path == null || "".equals(path) || "/".equals(path) || "/v01".equals(path)) { if (path == null || "".equals(path) || "/".equals(path) || "/v01".equals(path)) {
directoryUri = V01_DIRECTORY_URI; directoryUrl = V01_DIRECTORY_URL;
} else if ("/staging".equals(path)) { } else if ("/staging".equals(path)) {
directoryUri = STAGING_DIRECTORY_URI; directoryUrl = STAGING_DIRECTORY_URL;
} else { } else {
throw new IllegalArgumentException("Unknown URI " + serverUri); throw new IllegalArgumentException("Unknown URI " + serverUri);
} }
try { try {
return new URI(directoryUri); return new URL(directoryUrl);
} catch (URISyntaxException ex) { } catch (MalformedURLException ex) {
throw new AcmeProtocolException(directoryUri, ex); throw new AcmeProtocolException(directoryUrl, ex);
} }
} }

View File

@ -15,7 +15,7 @@ package org.shredzone.acme4j.provider.letsencrypt;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
@ -38,8 +38,8 @@ public class LetsEncryptHttpConnector extends HttpConnector {
private static SSLSocketFactory sslSocketFactory; private static SSLSocketFactory sslSocketFactory;
@Override @Override
public HttpURLConnection openConnection(URI uri) throws IOException { public HttpURLConnection openConnection(URL url) throws IOException {
HttpURLConnection conn = super.openConnection(uri); HttpURLConnection conn = super.openConnection(url);
if (conn instanceof HttpsURLConnection) { if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection) conn).setSSLSocketFactory(createSocketFactory()); ((HttpsURLConnection) conn).setSSLSocketFactory(createSocketFactory());
} }

View File

@ -15,7 +15,6 @@ package org.shredzone.acme4j.provider.pebble;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -44,7 +43,7 @@ public class PebbleAcmeProvider extends AbstractAcmeProvider {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
try { try {
String path = serverUri.getPath(); String path = serverUri.getPath();
@ -64,8 +63,8 @@ public class PebbleAcmeProvider extends AbstractAcmeProvider {
} }
} }
return baseUrl.toURI(); return baseUrl;
} catch (MalformedURLException | URISyntaxException ex) { } catch (MalformedURLException ex) {
throw new IllegalArgumentException("Bad server URI " + serverUri, ex); throw new IllegalArgumentException("Bad server URI " + serverUri, ex);
} }
} }

View File

@ -20,7 +20,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.net.URI; import java.net.URL;
import org.junit.Test; import org.junit.Test;
import org.shredzone.acme4j.util.TestUtils; import org.shredzone.acme4j.util.TestUtils;
@ -36,7 +36,7 @@ public class AcmeResourceTest {
@Test @Test
public void testConstructor() throws Exception { public void testConstructor() throws Exception {
Session session = TestUtils.session(); Session session = TestUtils.session();
URI location = new URI("http://example.com/acme/resource"); URL location = new URL("http://example.com/acme/resource");
try { try {
new DummyResource(null); new DummyResource(null);

View File

@ -20,7 +20,7 @@ import static org.shredzone.acme4j.util.TestUtils.*;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Collection; import java.util.Collection;
@ -44,7 +44,7 @@ public class AuthorizationTest {
private static final String SNAILMAIL_TYPE = "snail-01"; // a non-existent challenge private static final String SNAILMAIL_TYPE = "snail-01"; // a non-existent challenge
private URI locationUri = URI.create("http://example.com/acme/registration");; private URL locationUrl = url("http://example.com/acme/registration");
/** /**
* Test that {@link Authorization#findChallenge(String)} does only find standalone * Test that {@link Authorization#findChallenge(String)} does only find standalone
@ -121,8 +121,8 @@ public class AuthorizationTest {
public void testUpdate() throws Exception { public void testUpdate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -150,13 +150,13 @@ public class AuthorizationTest {
provider.putTestChallenge("http-01", httpChallenge); provider.putTestChallenge("http-01", httpChallenge);
provider.putTestChallenge("dns-01", dnsChallenge); provider.putTestChallenge("dns-01", dnsChallenge);
Authorization auth = new Authorization(session, locationUri); Authorization auth = new Authorization(session, locationUrl);
auth.update(); auth.update();
assertThat(auth.getDomain(), is("example.org")); assertThat(auth.getDomain(), is("example.org"));
assertThat(auth.getStatus(), is(Status.VALID)); assertThat(auth.getStatus(), is(Status.VALID));
assertThat(auth.getExpires(), is(parseTimestamp("2016-01-02T17:12:40Z"))); assertThat(auth.getExpires(), is(parseTimestamp("2016-01-02T17:12:40Z")));
assertThat(auth.getLocation(), is(locationUri)); assertThat(auth.getLocation(), is(locationUrl));
assertThat(auth.getChallenges(), containsInAnyOrder( assertThat(auth.getChallenges(), containsInAnyOrder(
(Challenge) httpChallenge, (Challenge) dnsChallenge)); (Challenge) httpChallenge, (Challenge) dnsChallenge));
@ -179,9 +179,9 @@ public class AuthorizationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
requestWasSent.set(true); requestWasSent.set(true);
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -207,7 +207,7 @@ public class AuthorizationTest {
provider.putTestChallenge("http-01", new Http01Challenge(session)); provider.putTestChallenge("http-01", new Http01Challenge(session));
provider.putTestChallenge("dns-01", new Dns01Challenge(session)); provider.putTestChallenge("dns-01", new Dns01Challenge(session));
Authorization auth = new Authorization(session, locationUri); Authorization auth = new Authorization(session, locationUrl);
// Lazy loading // Lazy loading
assertThat(requestWasSent.get(), is(false)); assertThat(requestWasSent.get(), is(false));
@ -233,8 +233,8 @@ public class AuthorizationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -262,7 +262,7 @@ public class AuthorizationTest {
provider.putTestChallenge("http-01", httpChallenge); provider.putTestChallenge("http-01", httpChallenge);
provider.putTestChallenge("dns-01", dnsChallenge); provider.putTestChallenge("dns-01", dnsChallenge);
Authorization auth = new Authorization(session, locationUri); Authorization auth = new Authorization(session, locationUrl);
try { try {
auth.update(); auth.update();
@ -274,7 +274,7 @@ public class AuthorizationTest {
assertThat(auth.getDomain(), is("example.org")); assertThat(auth.getDomain(), is("example.org"));
assertThat(auth.getStatus(), is(Status.VALID)); assertThat(auth.getStatus(), is(Status.VALID));
assertThat(auth.getExpires(), is(parseTimestamp("2016-01-02T17:12:40Z"))); assertThat(auth.getExpires(), is(parseTimestamp("2016-01-02T17:12:40Z")));
assertThat(auth.getLocation(), is(locationUri)); assertThat(auth.getLocation(), is(locationUrl));
assertThat(auth.getChallenges(), containsInAnyOrder( assertThat(auth.getChallenges(), containsInAnyOrder(
(Challenge) httpChallenge, (Challenge) dnsChallenge)); (Challenge) httpChallenge, (Challenge) dnsChallenge));
@ -295,11 +295,11 @@ public class AuthorizationTest {
public void testDeactivate() throws Exception { public void testDeactivate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
JSON json = claims.toJSON(); JSON json = claims.toJSON();
assertThat(json.get("resource").asString(), is("authz")); assertThat(json.get("resource").asString(), is("authz"));
assertThat(json.get("status").asString(), is("deactivated")); assertThat(json.get("status").asString(), is("deactivated"));
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -311,7 +311,7 @@ public class AuthorizationTest {
} }
}; };
Authorization auth = new Authorization(provider.createSession(), locationUri); Authorization auth = new Authorization(provider.createSession(), locationUrl);
auth.deactivate(); auth.deactivate();
provider.close(); provider.close();
@ -328,7 +328,7 @@ public class AuthorizationTest {
provider.putTestChallenge(Dns01Challenge.TYPE, new Dns01Challenge(session)); provider.putTestChallenge(Dns01Challenge.TYPE, new Dns01Challenge(session));
provider.putTestChallenge(TlsSni02Challenge.TYPE, new TlsSni02Challenge(session)); provider.putTestChallenge(TlsSni02Challenge.TYPE, new TlsSni02Challenge(session));
Authorization authorization = new Authorization(session, locationUri); Authorization authorization = new Authorization(session, locationUrl);
authorization.unmarshalAuthorization(getJsonAsObject("authorizationChallenges")); authorization.unmarshalAuthorization(getJsonAsObject("authorizationChallenges"));
return authorization; return authorization;
} }

View File

@ -20,7 +20,7 @@ import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@ -38,9 +38,9 @@ import org.shredzone.acme4j.util.TestUtils;
*/ */
public class CertificateTest { public class CertificateTest {
private URI resourceUri = URI.create("http://example.com/acme/resource"); private URL resourceUrl = url("http://example.com/acme/resource");
private URI locationUri = URI.create("http://example.com/acme/certificate"); private URL locationUrl = url("http://example.com/acme/certificate");
private URI chainUri = URI.create("http://example.com/acme/chain"); private URL chainUrl = url("http://example.com/acme/chain");
/** /**
* Test that a certificate can be downloaded. * Test that a certificate can be downloaded.
@ -50,17 +50,17 @@ public class CertificateTest {
final X509Certificate originalCert = TestUtils.createCertificate(); final X509Certificate originalCert = TestUtils.createCertificate();
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
private boolean isLocationUri; private boolean isLocationUrl;
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, isOneOf(locationUri, chainUri)); assertThat(url, isOneOf(locationUrl, chainUrl));
isLocationUri = uri.equals(locationUri); isLocationUrl = url.equals(locationUrl);
} }
@Override @Override
public int accept(int... httpStatus) throws AcmeException { public int accept(int... httpStatus) throws AcmeException {
if (isLocationUri) { if (isLocationUrl) {
// The leaf certificate, might be asynchronous // The leaf certificate, might be asynchronous
assertThat(httpStatus, isIntArrayContainingInAnyOrder( assertThat(httpStatus, isIntArrayContainingInAnyOrder(
HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED)); HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED));
@ -83,18 +83,18 @@ public class CertificateTest {
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
switch(relation) { switch(relation) {
case "up": return (isLocationUri ? chainUri : null); case "up": return (isLocationUrl ? chainUrl : null);
default: return null; default: return null;
} }
} }
}; };
Certificate cert = new Certificate(provider.createSession(), locationUri); Certificate cert = new Certificate(provider.createSession(), locationUrl);
X509Certificate downloadedCert = cert.download(); X509Certificate downloadedCert = cert.download();
assertThat(downloadedCert, is(sameInstance(originalCert))); assertThat(downloadedCert, is(sameInstance(originalCert)));
assertThat(cert.getChainLocation(), is(chainUri)); assertThat(cert.getChainLocation(), is(chainUrl));
X509Certificate[] downloadedChain = cert.downloadChain(); X509Certificate[] downloadedChain = cert.downloadChain();
assertThat(downloadedChain.length, is(1)); assertThat(downloadedChain.length, is(1));
@ -112,8 +112,8 @@ public class CertificateTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -130,7 +130,7 @@ public class CertificateTest {
} }
}; };
Certificate cert = new Certificate(provider.createSession(), locationUri); Certificate cert = new Certificate(provider.createSession(), locationUrl);
try { try {
cert.download(); cert.download();
@ -151,8 +151,8 @@ public class CertificateTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateRequest"))); assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateRequest")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -164,9 +164,9 @@ public class CertificateTest {
} }
}; };
provider.putTestResource(Resource.REVOKE_CERT, resourceUri); provider.putTestResource(Resource.REVOKE_CERT, resourceUrl);
Certificate cert = new Certificate(provider.createSession(), locationUri, null, originalCert); Certificate cert = new Certificate(provider.createSession(), locationUrl, null, originalCert);
cert.revoke(); cert.revoke();
provider.close(); provider.close();
@ -181,8 +181,8 @@ public class CertificateTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateWithReasonRequest"))); assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateWithReasonRequest")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -194,9 +194,9 @@ public class CertificateTest {
} }
}; };
provider.putTestResource(Resource.REVOKE_CERT, resourceUri); provider.putTestResource(Resource.REVOKE_CERT, resourceUrl);
Certificate cert = new Certificate(provider.createSession(), locationUri, null, originalCert); Certificate cert = new Certificate(provider.createSession(), locationUrl, null, originalCert);
cert.revoke(RevocationReason.KEY_COMPROMISE); cert.revoke(RevocationReason.KEY_COMPROMISE);
provider.close(); provider.close();

View File

@ -19,7 +19,7 @@ import static org.shredzone.acme4j.util.TestUtils.*;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import org.junit.Test; import org.junit.Test;
import org.shredzone.acme4j.connector.Resource; import org.shredzone.acme4j.connector.Resource;
@ -33,8 +33,8 @@ import org.shredzone.acme4j.util.JSONBuilder;
*/ */
public class RegistrationBuilderTest { public class RegistrationBuilderTest {
private URI resourceUri = URI.create("http://example.com/acme/resource");; private URL resourceUrl = url("http://example.com/acme/resource");
private URI locationUri = URI.create("http://example.com/acme/registration");; private URL locationUrl = url("http://example.com/acme/registration");;
/** /**
* Test if a new registration can be created. * Test if a new registration can be created.
@ -45,17 +45,17 @@ public class RegistrationBuilderTest {
private boolean isUpdate; private boolean isUpdate;
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
assertThat(isUpdate, is(false)); assertThat(isUpdate, is(false));
isUpdate = true; isUpdate = true;
} }
@Override @Override
public void sendJwkSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendJwkSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("newRegistration"))); assertThat(claims.toString(), sameJSONAs(getJson("newRegistration")));
isUpdate = false; isUpdate = false;
} }
@ -72,8 +72,8 @@ public class RegistrationBuilderTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
@Override @Override
@ -83,7 +83,7 @@ public class RegistrationBuilderTest {
} }
}; };
provider.putTestResource(Resource.NEW_REG, resourceUri); provider.putTestResource(Resource.NEW_REG, resourceUrl);
RegistrationBuilder builder = new RegistrationBuilder(); RegistrationBuilder builder = new RegistrationBuilder();
builder.addContact("mailto:foo@example.com"); builder.addContact("mailto:foo@example.com");
@ -92,9 +92,9 @@ public class RegistrationBuilderTest {
Session session = provider.createSession(); Session session = provider.createSession();
Registration registration = builder.create(session); Registration registration = builder.create(session);
assertThat(registration.getLocation(), is(locationUri)); assertThat(registration.getLocation(), is(locationUrl));
assertThat(registration.getTermsOfServiceAgreed(), is(true)); assertThat(registration.getTermsOfServiceAgreed(), is(true));
assertThat(session.getKeyIdentifier(), is(locationUri)); assertThat(session.getKeyIdentifier(), is(locationUrl.toURI()));
try { try {
RegistrationBuilder builder2 = new RegistrationBuilder(); RegistrationBuilder builder2 = new RegistrationBuilder();

View File

@ -21,11 +21,15 @@ import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -51,23 +55,24 @@ import org.shredzone.acme4j.util.TestUtils;
*/ */
public class RegistrationTest { public class RegistrationTest {
private URI resourceUri = URI.create("http://example.com/acme/resource"); private URL resourceUrl = url("http://example.com/acme/resource");
private URI locationUri = URI.create("http://example.com/acme/registration"); private URL locationUrl = url("http://example.com/acme/registration");
private URI agreementUri = URI.create("http://example.com/agreement.pdf"); private URI agreementUri = URI.create("http://example.com/agreement.pdf");
private URI chainUri = URI.create("http://example.com/acme/chain"); private URL chainUrl = url("http://example.com/acme/chain");
/** /**
* Test that a registration can be updated. * Test that a registration can be updated.
* @throws URISyntaxException
*/ */
@Test @Test
public void testUpdateRegistration() throws AcmeException, IOException { public void testUpdateRegistration() throws AcmeException, IOException, URISyntaxException {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
private JSON jsonResponse; private JSON jsonResponse;
private Integer response; private Integer response;
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
assertThat(claims.toString(), sameJSONAs(getJson("updateRegistration"))); assertThat(claims.toString(), sameJSONAs(getJson("updateRegistration")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
jsonResponse = getJsonAsObject("updateRegistrationResponse"); jsonResponse = getJsonAsObject("updateRegistrationResponse");
@ -75,8 +80,8 @@ public class RegistrationTest {
} }
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
if (URI.create("https://example.com/acme/reg/1/authz").equals(uri)) { if (url("https://example.com/acme/reg/1/authz").equals(url)) {
jsonResponse = new JSONBuilder() jsonResponse = new JSONBuilder()
.array("authorizations", "https://example.com/acme/auth/1") .array("authorizations", "https://example.com/acme/auth/1")
.toJSON(); .toJSON();
@ -84,7 +89,7 @@ public class RegistrationTest {
return; return;
} }
if (URI.create("https://example.com/acme/reg/1/cert").equals(uri)) { if (url("https://example.com/acme/reg/1/cert").equals(url)) {
jsonResponse = new JSONBuilder() jsonResponse = new JSONBuilder()
.array("certificates", "https://example.com/acme/cert/1") .array("certificates", "https://example.com/acme/cert/1")
.toJSON(); .toJSON();
@ -107,26 +112,30 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
return null;
}
@Override
public Collection<URI> getLinks(String relation) {
switch(relation) { switch(relation) {
case "terms-of-service": return agreementUri; case "terms-of-service": return Arrays.asList(agreementUri);
case "next": return null;
default: return null; default: return null;
} }
} }
}; };
Session session = provider.createSession(); Session session = provider.createSession();
Registration registration = new Registration(session, locationUri); Registration registration = new Registration(session, locationUrl);
registration.update(); registration.update();
assertThat(session.getKeyIdentifier(), is(locationUri)); assertThat(session.getKeyIdentifier(), is(locationUrl.toURI()));
assertThat(registration.getLocation(), is(locationUri)); assertThat(registration.getLocation(), is(locationUrl));
assertThat(registration.getTermsOfServiceAgreed(), is(true)); assertThat(registration.getTermsOfServiceAgreed(), is(true));
assertThat(registration.getContacts(), hasSize(1)); assertThat(registration.getContacts(), hasSize(1));
assertThat(registration.getContacts().get(0), is(URI.create("mailto:foo2@example.com"))); assertThat(registration.getContacts().get(0), is(URI.create("mailto:foo2@example.com")));
@ -134,14 +143,12 @@ public class RegistrationTest {
Iterator<Authorization> authIt = registration.getAuthorizations(); Iterator<Authorization> authIt = registration.getAuthorizations();
assertThat(authIt, not(nullValue())); assertThat(authIt, not(nullValue()));
assertThat(authIt.next().getLocation(), assertThat(authIt.next().getLocation(), is(url("https://example.com/acme/auth/1")));
is(URI.create("https://example.com/acme/auth/1")));
assertThat(authIt.hasNext(), is(false)); assertThat(authIt.hasNext(), is(false));
Iterator<Certificate> certIt = registration.getCertificates(); Iterator<Certificate> certIt = registration.getCertificates();
assertThat(certIt, not(nullValue())); assertThat(certIt, not(nullValue()));
assertThat(certIt.next().getLocation(), assertThat(certIt.next().getLocation(), is(url("https://example.com/acme/cert/1")));
is(URI.create("https://example.com/acme/cert/1")));
assertThat(certIt.hasNext(), is(false)); assertThat(certIt.hasNext(), is(false));
provider.close(); provider.close();
@ -156,9 +163,9 @@ public class RegistrationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
requestWasSent.set(true); requestWasSent.set(true);
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -174,20 +181,25 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
return null;
}
@Override
public Collection<URI> getLinks(String relation) {
switch(relation) { switch(relation) {
case "terms-of-service": return agreementUri; case "terms-of-service": return Arrays.asList(agreementUri);
default: return null; default: return null;
} }
} }
}; };
Registration registration = new Registration(provider.createSession(), locationUri); Registration registration = new Registration(provider.createSession(), locationUrl);
// Lazy loading // Lazy loading
assertThat(requestWasSent.get(), is(false)); assertThat(requestWasSent.get(), is(false));
@ -210,8 +222,8 @@ public class RegistrationTest {
public void testAuthorizeDomain() throws Exception { public void testAuthorizeDomain() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("newAuthorizationRequest"))); assertThat(claims.toString(), sameJSONAs(getJson("newAuthorizationRequest")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -228,8 +240,8 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
}; };
@ -238,19 +250,19 @@ public class RegistrationTest {
Http01Challenge httpChallenge = new Http01Challenge(session); Http01Challenge httpChallenge = new Http01Challenge(session);
Dns01Challenge dnsChallenge = new Dns01Challenge(session); Dns01Challenge dnsChallenge = new Dns01Challenge(session);
provider.putTestResource(Resource.NEW_AUTHZ, resourceUri); provider.putTestResource(Resource.NEW_AUTHZ, resourceUrl);
provider.putTestChallenge(Http01Challenge.TYPE, httpChallenge); provider.putTestChallenge(Http01Challenge.TYPE, httpChallenge);
provider.putTestChallenge(Dns01Challenge.TYPE, dnsChallenge); provider.putTestChallenge(Dns01Challenge.TYPE, dnsChallenge);
String domainName = "example.org"; String domainName = "example.org";
Registration registration = new Registration(session, locationUri); Registration registration = new Registration(session, locationUrl);
Authorization auth = registration.authorizeDomain(domainName); Authorization auth = registration.authorizeDomain(domainName);
assertThat(auth.getDomain(), is(domainName)); assertThat(auth.getDomain(), is(domainName));
assertThat(auth.getStatus(), is(Status.PENDING)); assertThat(auth.getStatus(), is(Status.PENDING));
assertThat(auth.getExpires(), is(nullValue())); assertThat(auth.getExpires(), is(nullValue()));
assertThat(auth.getLocation(), is(locationUri)); assertThat(auth.getLocation(), is(locationUrl));
assertThat(auth.getChallenges(), containsInAnyOrder( assertThat(auth.getChallenges(), containsInAnyOrder(
(Challenge) httpChallenge, (Challenge) dnsChallenge)); (Challenge) httpChallenge, (Challenge) dnsChallenge));
@ -271,7 +283,7 @@ public class RegistrationTest {
public void testAuthorizeBadDomain() throws Exception { public void testAuthorizeBadDomain() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider(); TestableConnectionProvider provider = new TestableConnectionProvider();
Session session = provider.createSession(); Session session = provider.createSession();
Registration registration = Registration.bind(session, locationUri); Registration registration = Registration.bind(session, locationUrl);
try { try {
registration.authorizeDomain(null); registration.authorizeDomain(null);
@ -299,13 +311,13 @@ public class RegistrationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
fail("Attempted to download the certificate. Should be downloaded already!"); fail("Attempted to download the certificate. Should be downloaded already!");
} }
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequestWithDate"))); assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequestWithDate")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -323,32 +335,32 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
switch(relation) { switch(relation) {
case "up": return chainUri; case "up": return chainUrl;
default: return null; default: return null;
} }
} }
}; };
provider.putTestResource(Resource.NEW_CERT, resourceUri); provider.putTestResource(Resource.NEW_CERT, resourceUrl);
byte[] csr = TestUtils.getResourceAsByteArray("/csr.der"); byte[] csr = TestUtils.getResourceAsByteArray("/csr.der");
ZoneId utc = ZoneId.of("UTC"); ZoneId utc = ZoneId.of("UTC");
Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant(); Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant();
Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant(); Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant();
Registration registration = new Registration(provider.createSession(), locationUri); Registration registration = new Registration(provider.createSession(), locationUrl);
Certificate cert = registration.requestCertificate(csr, notBefore, notAfter); Certificate cert = registration.requestCertificate(csr, notBefore, notAfter);
assertThat(cert.download(), is(originalCert)); assertThat(cert.download(), is(originalCert));
assertThat(cert.getLocation(), is(locationUri)); assertThat(cert.getLocation(), is(locationUrl));
assertThat(cert.getChainLocation(), is(chainUri)); assertThat(cert.getChainLocation(), is(chainUrl));
provider.close(); provider.close();
} }
@ -360,8 +372,8 @@ public class RegistrationTest {
public void testRequestCertificateAsync() throws AcmeException, IOException { public void testRequestCertificateAsync() throws AcmeException, IOException {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequest"))); assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequest")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -374,28 +386,28 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
switch(relation) { switch(relation) {
case "up": return chainUri; case "up": return chainUrl;
default: return null; default: return null;
} }
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
}; };
provider.putTestResource(Resource.NEW_CERT, resourceUri); provider.putTestResource(Resource.NEW_CERT, resourceUrl);
byte[] csr = TestUtils.getResourceAsByteArray("/csr.der"); byte[] csr = TestUtils.getResourceAsByteArray("/csr.der");
Registration registration = new Registration(provider.createSession(), locationUri); Registration registration = new Registration(provider.createSession(), locationUrl);
Certificate cert = registration.requestCertificate(csr); Certificate cert = registration.requestCertificate(csr);
assertThat(cert.getLocation(), is(locationUri)); assertThat(cert.getLocation(), is(locationUrl));
assertThat(cert.getChainLocation(), is(chainUri)); assertThat(cert.getChainLocation(), is(chainUrl));
provider.close(); provider.close();
} }
@ -408,8 +420,8 @@ public class RegistrationTest {
public void testRequestCertificateBrokenSync() throws AcmeException, IOException { public void testRequestCertificateBrokenSync() throws AcmeException, IOException {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequestWithDate"))); assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequestWithDate")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -427,31 +439,31 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
switch(relation) { switch(relation) {
case "up": return chainUri; case "up": return chainUrl;
default: return null; default: return null;
} }
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
}; };
provider.putTestResource(Resource.NEW_CERT, resourceUri); provider.putTestResource(Resource.NEW_CERT, resourceUrl);
byte[] csr = TestUtils.getResourceAsByteArray("/csr.der"); byte[] csr = TestUtils.getResourceAsByteArray("/csr.der");
ZoneId utc = ZoneId.of("UTC"); ZoneId utc = ZoneId.of("UTC");
Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant(); Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant();
Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant(); Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant();
Registration registration = new Registration(provider.createSession(), locationUri); Registration registration = new Registration(provider.createSession(), locationUrl);
Certificate cert = registration.requestCertificate(csr, notBefore, notAfter); Certificate cert = registration.requestCertificate(csr, notBefore, notAfter);
assertThat(cert.getLocation(), is(locationUri)); assertThat(cert.getLocation(), is(locationUrl));
assertThat(cert.getChainLocation(), is(chainUri)); assertThat(cert.getChainLocation(), is(chainUrl));
provider.close(); provider.close();
} }
@ -466,9 +478,9 @@ public class RegistrationTest {
final TestableConnectionProvider provider = new TestableConnectionProvider() { final TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder payload, Session session) { public void sendSignedRequest(URL url, JSONBuilder payload, Session session) {
try { try {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
assertThat(session.getKeyPair(), is(sameInstance(oldKeyPair))); assertThat(session.getKeyPair(), is(sameInstance(oldKeyPair)));
@ -489,7 +501,7 @@ public class RegistrationTest {
StringBuilder expectedPayload = new StringBuilder(); StringBuilder expectedPayload = new StringBuilder();
expectedPayload.append('{'); expectedPayload.append('{');
expectedPayload.append("\"account\":\"").append(resourceUri).append("\","); expectedPayload.append("\"account\":\"").append(resourceUrl).append("\",");
expectedPayload.append("\"newKey\":{"); expectedPayload.append("\"newKey\":{");
expectedPayload.append("\"kty\":\"").append(TestUtils.D_KTY).append("\","); expectedPayload.append("\"kty\":\"").append(TestUtils.D_KTY).append("\",");
expectedPayload.append("\"e\":\"").append(TestUtils.D_E).append("\","); expectedPayload.append("\"e\":\"").append(TestUtils.D_E).append("\",");
@ -508,12 +520,12 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return resourceUri; return resourceUrl;
} }
}; };
provider.putTestResource(Resource.KEY_CHANGE, locationUri); provider.putTestResource(Resource.KEY_CHANGE, locationUrl);
Session session = new Session(new URI(TestUtils.ACME_SERVER_URI), oldKeyPair) { Session session = new Session(new URI(TestUtils.ACME_SERVER_URI), oldKeyPair) {
@Override @Override
@ -524,7 +536,7 @@ public class RegistrationTest {
assertThat(session.getKeyPair(), is(sameInstance(oldKeyPair))); assertThat(session.getKeyPair(), is(sameInstance(oldKeyPair)));
Registration registration = new Registration(session, resourceUri); Registration registration = new Registration(session, resourceUrl);
registration.changeKey(newKeyPair); registration.changeKey(newKeyPair);
assertThat(session.getKeyPair(), is(sameInstance(newKeyPair))); assertThat(session.getKeyPair(), is(sameInstance(newKeyPair)));
@ -538,7 +550,7 @@ public class RegistrationTest {
TestableConnectionProvider provider = new TestableConnectionProvider(); TestableConnectionProvider provider = new TestableConnectionProvider();
Session session = provider.createSession(); Session session = provider.createSession();
Registration registration = new Registration(session, locationUri); Registration registration = new Registration(session, locationUrl);
registration.changeKey(session.getKeyPair()); registration.changeKey(session.getKeyPair());
provider.close(); provider.close();
@ -551,11 +563,11 @@ public class RegistrationTest {
public void testDeactivate() throws Exception { public void testDeactivate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
JSON json = claims.toJSON(); JSON json = claims.toJSON();
assertThat(json.get("resource").asString(), is("reg")); assertThat(json.get("resource").asString(), is("reg"));
assertThat(json.get("status").asString(), is("deactivated")); assertThat(json.get("status").asString(), is("deactivated"));
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -567,7 +579,7 @@ public class RegistrationTest {
} }
}; };
Registration registration = new Registration(provider.createSession(), locationUri); Registration registration = new Registration(provider.createSession(), locationUrl);
registration.deactivate(); registration.deactivate();
provider.close(); provider.close();
@ -580,8 +592,8 @@ public class RegistrationTest {
public void testModify() throws Exception { public void testModify() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
assertThat(claims.toString(), sameJSONAs(getJson("modifyRegistration"))); assertThat(claims.toString(), sameJSONAs(getJson("modifyRegistration")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -598,12 +610,12 @@ public class RegistrationTest {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
return locationUri; return locationUrl;
} }
}; };
Registration registration = new Registration(provider.createSession(), locationUri); Registration registration = new Registration(provider.createSession(), locationUrl);
EditableRegistration editable = registration.modify(); EditableRegistration editable = registration.modify();
assertThat(editable, notNullValue()); assertThat(editable, notNullValue());
@ -612,7 +624,7 @@ public class RegistrationTest {
editable.getContacts().add(URI.create("mailto:foo3@example.com")); editable.getContacts().add(URI.create("mailto:foo3@example.com"));
editable.commit(); editable.commit();
assertThat(registration.getLocation(), is(locationUri)); assertThat(registration.getLocation(), is(locationUrl));
assertThat(registration.getContacts().size(), is(2)); assertThat(registration.getContacts().size(), is(2));
assertThat(registration.getContacts().get(0), is(URI.create("mailto:foo2@example.com"))); assertThat(registration.getContacts().get(0), is(URI.create("mailto:foo2@example.com")));
assertThat(registration.getContacts().get(1), is(URI.create("mailto:foo3@example.com"))); assertThat(registration.getContacts().get(1), is(URI.create("mailto:foo3@example.com")));

View File

@ -16,10 +16,11 @@ package org.shredzone.acme4j;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject; import static org.shredzone.acme4j.util.TestUtils.*;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import java.time.Instant; import java.time.Instant;
@ -210,13 +211,13 @@ public class SessionTest {
}; };
}; };
assertThat(session.resourceUri(Resource.NEW_REG), assertThat(session.resourceUrl(Resource.NEW_REG),
is(URI.create("https://example.com/acme/new-reg"))); is(new URL("https://example.com/acme/new-reg")));
assertThat(session.resourceUri(Resource.NEW_AUTHZ), assertThat(session.resourceUrl(Resource.NEW_AUTHZ),
is(URI.create("https://example.com/acme/new-authz"))); is(new URL("https://example.com/acme/new-authz")));
assertThat(session.resourceUri(Resource.NEW_CERT), assertThat(session.resourceUrl(Resource.NEW_CERT),
is(URI.create("https://example.com/acme/new-cert"))); is(new URL("https://example.com/acme/new-cert")));
assertThat(session.resourceUri(Resource.REVOKE_CERT), assertThat(session.resourceUrl(Resource.REVOKE_CERT),
is(nullValue())); is(nullValue()));
Metadata meta = session.getMetadata(); Metadata meta = session.getMetadata();
@ -233,20 +234,20 @@ public class SessionTest {
* @param session * @param session
* {@link Session} to assert * {@link Session} to assert
*/ */
private void assertSession(Session session) throws AcmeException { private void assertSession(Session session) throws AcmeException, IOException {
assertThat(session.resourceUri(Resource.NEW_REG), assertThat(session.resourceUrl(Resource.NEW_REG),
is(URI.create("https://example.com/acme/new-reg"))); is(new URL("https://example.com/acme/new-reg")));
assertThat(session.resourceUri(Resource.NEW_AUTHZ), assertThat(session.resourceUrl(Resource.NEW_AUTHZ),
is(URI.create("https://example.com/acme/new-authz"))); is(new URL("https://example.com/acme/new-authz")));
assertThat(session.resourceUri(Resource.NEW_CERT), assertThat(session.resourceUrl(Resource.NEW_CERT),
is(URI.create("https://example.com/acme/new-cert"))); is(new URL("https://example.com/acme/new-cert")));
assertThat(session.resourceUri(Resource.REVOKE_CERT), assertThat(session.resourceUrl(Resource.REVOKE_CERT),
is(nullValue())); is(nullValue()));
Metadata meta = session.getMetadata(); Metadata meta = session.getMetadata();
assertThat(meta, not(nullValue())); assertThat(meta, not(nullValue()));
assertThat(meta.getTermsOfService(), is(URI.create("https://example.com/acme/terms"))); assertThat(meta.getTermsOfService(), is(URI.create("https://example.com/acme/terms")));
assertThat(meta.getWebsite(), is(URI.create("https://www.example.com/"))); assertThat(meta.getWebsite(), is(url("https://www.example.com/")));
assertThat(meta.getCaaIdentities(), containsInAnyOrder("example.com")); assertThat(meta.getCaaIdentities(), containsInAnyOrder("example.com"));
assertThat(meta.getJSON(), is(notNullValue())); assertThat(meta.getJSON(), is(notNullValue()));
} }

View File

@ -22,7 +22,6 @@ import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.time.Duration; import java.time.Duration;
@ -46,8 +45,8 @@ import org.shredzone.acme4j.util.TestUtils;
*/ */
public class ChallengeTest { public class ChallengeTest {
private Session session; private Session session;
private URI resourceUri = URI.create("https://example.com/acme/some-resource"); private URL resourceUrl = url("https://example.com/acme/some-resource");
private URI locationUri = URI.create("https://example.com/acme/some-location"); private URL locationUrl = url("https://example.com/acme/some-location");
@Before @Before
public void setup() throws IOException { public void setup() throws IOException {
@ -61,8 +60,8 @@ public class ChallengeTest {
public void testChallenge() throws Exception { public void testChallenge() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -82,11 +81,11 @@ public class ChallengeTest {
provider.putTestChallenge(Http01Challenge.TYPE, new Http01Challenge(session)); provider.putTestChallenge(Http01Challenge.TYPE, new Http01Challenge(session));
Http01Challenge challenge = Challenge.bind(session, locationUri); Http01Challenge challenge = Challenge.bind(session, locationUrl);
assertThat(challenge.getType(), is(Http01Challenge.TYPE)); assertThat(challenge.getType(), is(Http01Challenge.TYPE));
assertThat(challenge.getStatus(), is(Status.VALID)); assertThat(challenge.getStatus(), is(Status.VALID));
assertThat(challenge.getLocation(), is(locationUri)); assertThat(challenge.getLocation(), is(locationUrl));
assertThat(challenge.getToken(), is("IlirfxKKXAsHtmzK29Pj8A")); assertThat(challenge.getToken(), is("IlirfxKKXAsHtmzK29Pj8A"));
provider.close(); provider.close();
@ -111,7 +110,7 @@ public class ChallengeTest {
// Test unmarshalled values // Test unmarshalled values
assertThat(challenge.getType(), is("generic-01")); assertThat(challenge.getType(), is("generic-01"));
assertThat(challenge.getStatus(), is(Status.VALID)); assertThat(challenge.getStatus(), is(Status.VALID));
assertThat(challenge.getLocation(), is(new URI("http://example.com/challenge/123"))); assertThat(challenge.getLocation(), is(url("http://example.com/challenge/123")));
assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z"))); assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z")));
assertThat(challenge.getJSON().get("type").asString(), is("generic-01")); assertThat(challenge.getJSON().get("type").asString(), is("generic-01"));
assertThat(challenge.getJSON().get("uri").asURL(), is(new URL("http://example.com/challenge/123"))); assertThat(challenge.getJSON().get("uri").asURL(), is(new URL("http://example.com/challenge/123")));
@ -151,8 +150,8 @@ public class ChallengeTest {
public void testTrigger() throws Exception { public void testTrigger() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
assertThat(uri, is(resourceUri)); assertThat(url, is(resourceUrl));
assertThat(claims.toString(), sameJSONAs(getJson("triggerHttpChallengeRequest"))); assertThat(claims.toString(), sameJSONAs(getJson("triggerHttpChallengeRequest")));
assertThat(session, is(notNullValue())); assertThat(session, is(notNullValue()));
} }
@ -178,7 +177,7 @@ public class ChallengeTest {
challenge.trigger(); challenge.trigger();
assertThat(challenge.getStatus(), is(Status.PENDING)); assertThat(challenge.getStatus(), is(Status.PENDING));
assertThat(challenge.getLocation(), is(locationUri)); assertThat(challenge.getLocation(), is(locationUrl));
provider.close(); provider.close();
} }
@ -190,8 +189,8 @@ public class ChallengeTest {
public void testUpdate() throws Exception { public void testUpdate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -220,7 +219,7 @@ public class ChallengeTest {
challenge.update(); challenge.update();
assertThat(challenge.getStatus(), is(Status.VALID)); assertThat(challenge.getStatus(), is(Status.VALID));
assertThat(challenge.getLocation(), is(locationUri)); assertThat(challenge.getLocation(), is(locationUrl));
provider.close(); provider.close();
} }
@ -234,8 +233,8 @@ public class ChallengeTest {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -270,7 +269,7 @@ public class ChallengeTest {
} }
assertThat(challenge.getStatus(), is(Status.VALID)); assertThat(challenge.getStatus(), is(Status.VALID));
assertThat(challenge.getLocation(), is(locationUri)); assertThat(challenge.getLocation(), is(locationUrl));
provider.close(); provider.close();
} }
@ -288,7 +287,7 @@ public class ChallengeTest {
} }
try { try {
Challenge.bind(null, locationUri); Challenge.bind(null, locationUrl);
fail("session accepts null"); fail("session accepts null");
} catch (NullPointerException ex) { } catch (NullPointerException ex) {
// expected // expected
@ -296,14 +295,14 @@ public class ChallengeTest {
} }
/** /**
* Test that an exception is thrown on a bad location URI. * Test that an exception is thrown on a bad location URL.
*/ */
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testBadBind() throws Exception { public void testBadBind() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
assertThat(uri, is(locationUri)); assertThat(url, is(locationUrl));
} }
@Override @Override
@ -320,7 +319,7 @@ public class ChallengeTest {
}; };
Session session = provider.createSession(); Session session = provider.createSession();
Challenge.bind(session, locationUri); Challenge.bind(session, locationUrl);
provider.close(); provider.close();
} }

View File

@ -56,7 +56,7 @@ import org.shredzone.acme4j.util.TestUtils;
*/ */
public class DefaultConnectionTest { public class DefaultConnectionTest {
private URI requestUri = URI.create("http://example.com/acme/"); private URL requestUrl = TestUtils.url("http://example.com/acme/");
private URI keyIdentifierUri = URI.create(TestUtils.ACME_SERVER_URI + "/acct/1"); private URI keyIdentifierUri = URI.create(TestUtils.ACME_SERVER_URI + "/acct/1");
private HttpURLConnection mockUrlConnection; private HttpURLConnection mockUrlConnection;
private HttpConnector mockHttpConnection; private HttpConnector mockHttpConnection;
@ -67,7 +67,7 @@ public class DefaultConnectionTest {
mockUrlConnection = mock(HttpURLConnection.class); mockUrlConnection = mock(HttpURLConnection.class);
mockHttpConnection = mock(HttpConnector.class); mockHttpConnection = mock(HttpConnector.class);
when(mockHttpConnection.openConnection(requestUri)).thenReturn(mockUrlConnection); when(mockHttpConnection.openConnection(requestUrl)).thenReturn(mockUrlConnection);
final AcmeProvider mockProvider = mock(AcmeProvider.class); final AcmeProvider mockProvider = mock(AcmeProvider.class);
when(mockProvider.directory( when(mockProvider.directory(
@ -149,7 +149,7 @@ public class DefaultConnectionTest {
public void testResetNonce() throws AcmeException, IOException { public void testResetNonce() throws AcmeException, IOException {
byte[] nonce = "foo-nonce-foo".getBytes(); byte[] nonce = "foo-nonce-foo".getBytes();
when(mockHttpConnection.openConnection(URI.create("https://example.com/acme/new-nonce"))) when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce")))
.thenReturn(mockUrlConnection); .thenReturn(mockUrlConnection);
when(mockUrlConnection.getResponseCode()) when(mockUrlConnection.getResponseCode())
.thenReturn(HttpURLConnection.HTTP_NO_CONTENT); .thenReturn(HttpURLConnection.HTTP_NO_CONTENT);
@ -192,8 +192,8 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection; conn.conn = mockUrlConnection;
URI location = conn.getLocation(); URL location = conn.getLocation();
assertThat(location, is(new URI("https://example.com/otherlocation"))); assertThat(location, is(new URL("https://example.com/otherlocation")));
} }
verify(mockUrlConnection).getHeaderField("Location"); verify(mockUrlConnection).getHeaderField("Location");
@ -211,8 +211,8 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection; conn.conn = mockUrlConnection;
URI location = conn.getLocation(); URL location = conn.getLocation();
assertThat(location, is(new URI("https://example.org/otherlocation"))); assertThat(location, is(new URL("https://example.org/otherlocation")));
} }
verify(mockUrlConnection).getHeaderField("Location"); verify(mockUrlConnection).getHeaderField("Location");
@ -239,9 +239,9 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection; conn.conn = mockUrlConnection;
assertThat(conn.getLink("next"), is(new URI("https://example.com/acme/new-authz"))); assertThat(conn.getLink("next"), is(new URL("https://example.com/acme/new-authz")));
assertThat(conn.getLink("recover"), is(new URI("https://example.org/recover-reg"))); assertThat(conn.getLink("recover"), is(new URL("https://example.org/recover-reg")));
assertThat(conn.getLink("terms-of-service"), is(new URI("https://example.com/acme/terms"))); assertThat(conn.getLink("terms-of-service"), is(new URL("https://example.com/acme/terms")));
assertThat(conn.getLink("secret-stuff"), is(nullValue())); assertThat(conn.getLink("secret-stuff"), is(nullValue()));
} }
} }
@ -251,14 +251,17 @@ public class DefaultConnectionTest {
*/ */
@Test @Test
public void testGetMultiLink() { public void testGetMultiLink() {
URL baseUrl = TestUtils.url("https://example.com/acme/request/1234");
Map<String, List<String>> headers = new HashMap<>(); Map<String, List<String>> headers = new HashMap<>();
headers.put("Link", Arrays.asList( headers.put("Link", Arrays.asList(
"<https://example.com/acme/terms1>; rel=\"terms-of-service\"", "<https://example.com/acme/terms1>; rel=\"terms-of-service\"",
"<https://example.com/acme/terms2>; rel=\"terms-of-service\"", "<https://example.com/acme/terms2>; rel=\"terms-of-service\"",
"<https://example.com/acme/terms3>; rel=\"terms-of-service\"" "<../terms3>; rel=\"terms-of-service\""
)); ));
when(mockUrlConnection.getHeaderFields()).thenReturn(headers); when(mockUrlConnection.getHeaderFields()).thenReturn(headers);
when(mockUrlConnection.getURL()).thenReturn(baseUrl);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection; conn.conn = mockUrlConnection;
@ -291,7 +294,7 @@ public class DefaultConnectionTest {
public void testNoLocation() throws Exception { public void testNoLocation() throws Exception {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection; conn.conn = mockUrlConnection;
URI location = conn.getLocation(); URL location = conn.getLocation();
assertThat(location, is(nullValue())); assertThat(location, is(nullValue()));
} }
@ -536,7 +539,7 @@ public class DefaultConnectionTest {
@Test @Test
public void testSendRequest() throws Exception { public void testSendRequest() throws Exception {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.sendRequest(requestUri, session); conn.sendRequest(requestUrl, session);
} }
verify(mockUrlConnection).setRequestMethod("GET"); verify(mockUrlConnection).setRequestMethod("GET");
@ -583,7 +586,7 @@ public class DefaultConnectionTest {
JSONBuilder cb = new JSONBuilder(); JSONBuilder cb = new JSONBuilder();
cb.put("foo", 123).put("bar", "a-string"); cb.put("foo", 123).put("bar", "a-string");
session.setKeyIdentifier(keyIdentifierUri); session.setKeyIdentifier(keyIdentifierUri);
conn.sendSignedRequest(requestUri, cb, session); conn.sendSignedRequest(requestUrl, cb, session);
} }
verify(mockUrlConnection).setRequestMethod("POST"); verify(mockUrlConnection).setRequestMethod("POST");
@ -607,7 +610,7 @@ public class DefaultConnectionTest {
StringBuilder expectedHeader = new StringBuilder(); StringBuilder expectedHeader = new StringBuilder();
expectedHeader.append('{'); expectedHeader.append('{');
expectedHeader.append("\"nonce\":\"").append(Base64Url.encode(nonce1)).append("\","); expectedHeader.append("\"nonce\":\"").append(Base64Url.encode(nonce1)).append("\",");
expectedHeader.append("\"url\":\"").append(requestUri).append("\","); expectedHeader.append("\"url\":\"").append(requestUrl).append("\",");
expectedHeader.append("\"alg\":\"RS256\","); expectedHeader.append("\"alg\":\"RS256\",");
expectedHeader.append("\"kid\":\"").append(keyIdentifierUri).append('"'); expectedHeader.append("\"kid\":\"").append(keyIdentifierUri).append('"');
expectedHeader.append('}'); expectedHeader.append('}');
@ -656,7 +659,7 @@ public class DefaultConnectionTest {
}) { }) {
JSONBuilder cb = new JSONBuilder(); JSONBuilder cb = new JSONBuilder();
cb.put("foo", 123).put("bar", "a-string"); cb.put("foo", 123).put("bar", "a-string");
conn.sendJwkSignedRequest(requestUri, cb, session); conn.sendJwkSignedRequest(requestUrl, cb, session);
} }
verify(mockUrlConnection).setRequestMethod("POST"); verify(mockUrlConnection).setRequestMethod("POST");
@ -680,7 +683,7 @@ public class DefaultConnectionTest {
StringBuilder expectedHeader = new StringBuilder(); StringBuilder expectedHeader = new StringBuilder();
expectedHeader.append('{'); expectedHeader.append('{');
expectedHeader.append("\"nonce\":\"").append(Base64Url.encode(nonce1)).append("\","); expectedHeader.append("\"nonce\":\"").append(Base64Url.encode(nonce1)).append("\",");
expectedHeader.append("\"url\":\"").append(requestUri).append("\","); expectedHeader.append("\"url\":\"").append(requestUrl).append("\",");
expectedHeader.append("\"alg\":\"RS256\","); expectedHeader.append("\"alg\":\"RS256\",");
expectedHeader.append("\"jwk\":{"); expectedHeader.append("\"jwk\":{");
expectedHeader.append("\"kty\":\"").append(TestUtils.KTY).append("\","); expectedHeader.append("\"kty\":\"").append(TestUtils.KTY).append("\",");
@ -705,7 +708,7 @@ public class DefaultConnectionTest {
public void testSendSignedRequestNoKidFailed() throws Exception { public void testSendSignedRequestNoKidFailed() throws Exception {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
JSONBuilder cb = new JSONBuilder(); JSONBuilder cb = new JSONBuilder();
conn.sendSignedRequest(requestUri, cb, session); conn.sendSignedRequest(requestUrl, cb, session);
} }
} }
@ -714,14 +717,14 @@ public class DefaultConnectionTest {
*/ */
@Test(expected = AcmeProtocolException.class) @Test(expected = AcmeProtocolException.class)
public void testSendSignedRequestNoNonce() throws Exception { public void testSendSignedRequestNoNonce() throws Exception {
when(mockHttpConnection.openConnection(URI.create("https://example.com/acme/new-nonce"))) when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce")))
.thenReturn(mockUrlConnection); .thenReturn(mockUrlConnection);
when(mockUrlConnection.getResponseCode()) when(mockUrlConnection.getResponseCode())
.thenReturn(HttpURLConnection.HTTP_NOT_FOUND); .thenReturn(HttpURLConnection.HTTP_NOT_FOUND);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
JSONBuilder cb = new JSONBuilder(); JSONBuilder cb = new JSONBuilder();
conn.sendJwkSignedRequest(requestUri, cb, DefaultConnectionTest.this.session); conn.sendJwkSignedRequest(requestUrl, cb, DefaultConnectionTest.this.session);
} }
} }

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.connector; package org.shredzone.acme4j.connector;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Collection; import java.util.Collection;
@ -34,17 +35,17 @@ public class DummyConnection implements Connection {
} }
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void sendJwkSignedRequest(URI uri, JSONBuilder claims, Session session) { public void sendJwkSignedRequest(URL url, JSONBuilder claims, Session session) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -74,12 +75,12 @@ public class DummyConnection implements Connection {
} }
@Override @Override
public URI getLocation() { public URL getLocation() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -20,8 +20,8 @@ import static org.mockito.Mockito.*;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
@ -57,9 +57,9 @@ public class HttpConnectorTest {
*/ */
@Test @Test
@Category(HttpURLConnection.class) @Category(HttpURLConnection.class)
public void testOpenConnection() throws IOException, URISyntaxException { public void testOpenConnection() throws IOException {
HttpConnector connector = new HttpConnector(); HttpConnector connector = new HttpConnector();
HttpURLConnection conn = connector.openConnection(new URI("http://example.com")); HttpURLConnection conn = connector.openConnection(new URL("http://example.com"));
assertThat(conn, not(nullValue())); assertThat(conn, not(nullValue()));
conn.connect(); conn.connect();
assertThat(conn.getResponseCode(), is(HttpURLConnection.HTTP_OK)); assertThat(conn.getResponseCode(), is(HttpURLConnection.HTTP_OK));

View File

@ -15,11 +15,11 @@ package org.shredzone.acme4j.connector;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.isIntArrayContainingInAnyOrder; import static org.shredzone.acme4j.util.TestUtils.*;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -43,24 +43,24 @@ public class ResourceIteratorTest {
private final int RESOURCES_PER_PAGE = 5; private final int RESOURCES_PER_PAGE = 5;
private final String TYPE = "authorizations"; private final String TYPE = "authorizations";
private List<URI> resourceURIs = new ArrayList<>(PAGES * RESOURCES_PER_PAGE); private List<URL> resourceURLs = new ArrayList<>(PAGES * RESOURCES_PER_PAGE);
private List<URI> pageURIs = new ArrayList<>(PAGES); private List<URL> pageURLs = new ArrayList<>(PAGES);
@Before @Before
public void setup() { public void setup() {
resourceURIs.clear(); resourceURLs.clear();
for (int ix = 0; ix < RESOURCES_PER_PAGE * PAGES; ix++) { for (int ix = 0; ix < RESOURCES_PER_PAGE * PAGES; ix++) {
resourceURIs.add(URI.create("https://example.com/acme/auth/" + ix)); resourceURLs.add(url("https://example.com/acme/auth/" + ix));
} }
pageURIs.clear(); pageURLs.clear();
for (int ix = 0; ix < PAGES; ix++) { for (int ix = 0; ix < PAGES; ix++) {
pageURIs.add(URI.create("https://example.com/acme/batch/" + ix)); pageURLs.add(url("https://example.com/acme/batch/" + ix));
} }
} }
/** /**
* Test if the {@link ResourceIterator} handles a {@code null} start URI. * Test if the {@link ResourceIterator} handles a {@code null} start URL.
*/ */
@Test(expected = NoSuchElementException.class) @Test(expected = NoSuchElementException.class)
public void nullTest() throws IOException { public void nullTest() throws IOException {
@ -76,14 +76,14 @@ public class ResourceIteratorTest {
*/ */
@Test @Test
public void iteratorTest() throws IOException { public void iteratorTest() throws IOException {
List<URI> result = new ArrayList<>(); List<URL> result = new ArrayList<>();
Iterator<Authorization> it = createIterator(pageURIs.get(0)); Iterator<Authorization> it = createIterator(pageURLs.get(0));
while (it.hasNext()) { while (it.hasNext()) {
result.add(it.next().getLocation()); result.add(it.next().getLocation());
} }
assertThat(result, is(equalTo(resourceURIs))); assertThat(result, is(equalTo(resourceURLs)));
} }
/** /**
@ -91,9 +91,9 @@ public class ResourceIteratorTest {
*/ */
@Test @Test
public void nextHasNextTest() throws IOException { public void nextHasNextTest() throws IOException {
List<URI> result = new ArrayList<>(); List<URL> result = new ArrayList<>();
Iterator<Authorization> it = createIterator(pageURIs.get(0)); Iterator<Authorization> it = createIterator(pageURLs.get(0));
assertThat(it.hasNext(), is(true)); assertThat(it.hasNext(), is(true));
assertThat(it.hasNext(), is(true)); assertThat(it.hasNext(), is(true));
@ -107,7 +107,7 @@ public class ResourceIteratorTest {
assertThat(it.hasNext(), is(false)); assertThat(it.hasNext(), is(false));
} }
assertThat(result, is(equalTo(resourceURIs))); assertThat(result, is(equalTo(resourceURLs)));
} }
/** /**
@ -115,7 +115,7 @@ public class ResourceIteratorTest {
*/ */
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void removeTest() throws IOException { public void removeTest() throws IOException {
Iterator<Authorization> it = createIterator(pageURIs.get(0)); Iterator<Authorization> it = createIterator(pageURLs.get(0));
it.next(); it.next();
it.remove(); // throws UnsupportedOperationException it.remove(); // throws UnsupportedOperationException
} }
@ -124,16 +124,16 @@ public class ResourceIteratorTest {
* Creates a new {@link Iterator} of {@link Authorization} objects. * Creates a new {@link Iterator} of {@link Authorization} objects.
* *
* @param first * @param first
* URI of the first page * URL of the first page
* @return Created {@link Iterator} * @return Created {@link Iterator}
*/ */
private Iterator<Authorization> createIterator(URI first) throws IOException { private Iterator<Authorization> createIterator(URL first) throws IOException {
TestableConnectionProvider provider = new TestableConnectionProvider() { TestableConnectionProvider provider = new TestableConnectionProvider() {
private int ix; private int ix;
@Override @Override
public void sendRequest(URI uri, Session session) { public void sendRequest(URL url, Session session) {
ix = pageURIs.indexOf(uri); ix = pageURLs.indexOf(url);
assertThat(ix, is(greaterThanOrEqualTo(0))); assertThat(ix, is(greaterThanOrEqualTo(0)));
} }
@ -149,15 +149,15 @@ public class ResourceIteratorTest {
int end = (ix + 1) * RESOURCES_PER_PAGE; int end = (ix + 1) * RESOURCES_PER_PAGE;
JSONBuilder cb = new JSONBuilder(); JSONBuilder cb = new JSONBuilder();
cb.array(TYPE, resourceURIs.subList(start, end).toArray()); cb.array(TYPE, resourceURLs.subList(start, end).toArray());
return JSON.parse(cb.toString()); return JSON.parse(cb.toString());
} }
@Override @Override
public URI getLink(String relation) { public URL getLink(String relation) {
if ("next".equals(relation) && (ix + 1 < pageURIs.size())) { if ("next".equals(relation) && (ix + 1 < pageURLs.size())) {
return pageURIs.get(ix + 1); return pageURLs.get(ix + 1);
} }
return null; return null;
} }

View File

@ -18,6 +18,7 @@ import static org.junit.Assert.assertThat;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import java.util.ServiceLoader; import java.util.ServiceLoader;
@ -92,7 +93,7 @@ public class SessionProviderTest {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -120,7 +121,7 @@ public class SessionProviderTest {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -16,7 +16,9 @@ package org.shredzone.acme4j.exception;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import org.junit.Test; import org.junit.Test;
@ -29,19 +31,19 @@ public class AcmeAgreementRequiredExceptionTest {
* Test that parameters are correctly returned. * Test that parameters are correctly returned.
*/ */
@Test @Test
public void testAcmeAgreementRequiredException() { public void testAcmeAgreementRequiredException() throws MalformedURLException {
String type = "urn:ietf:params:acme:error:agreementRequired"; String type = "urn:ietf:params:acme:error:agreementRequired";
String detail = "Agreement is required"; String detail = "Agreement is required";
URI agreementUri = URI.create("http://example.com/agreement.pdf"); URI agreementUri = URI.create("http://example.com/agreement.pdf");
URI instanceUri = URI.create("http://example.com/howToAgree.html"); URL instanceUrl = new URL("http://example.com/howToAgree.html");
AcmeAgreementRequiredException ex AcmeAgreementRequiredException ex
= new AcmeAgreementRequiredException(type, detail, agreementUri, instanceUri); = new AcmeAgreementRequiredException(type, detail, agreementUri, instanceUrl);
assertThat(ex.getType(), is(type)); assertThat(ex.getType(), is(type));
assertThat(ex.getMessage(), is(detail)); assertThat(ex.getMessage(), is(detail));
assertThat(ex.getAgreementUri(), is(agreementUri)); assertThat(ex.getAgreementUri(), is(agreementUri));
assertThat(ex.getInstance(), is(instanceUri)); assertThat(ex.getInstance(), is(instanceUrl));
} }
/** /**

View File

@ -16,7 +16,8 @@ package org.shredzone.acme4j.exception;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.net.URI; import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Test; import org.junit.Test;
@ -26,15 +27,15 @@ import org.junit.Test;
public class AcmeConflictExceptionTest { public class AcmeConflictExceptionTest {
@Test @Test
public void testAcmeConflictException() { public void testAcmeConflictException() throws MalformedURLException {
String msg = "Account already exists"; String msg = "Account already exists";
URI locationUri = URI.create("http://example.com/location/123"); URL locationUrl = new URL("http://example.com/location/123");
AcmeConflictException ex AcmeConflictException ex
= new AcmeConflictException(msg, locationUri); = new AcmeConflictException(msg, locationUrl);
assertThat(ex.getMessage(), is(msg)); assertThat(ex.getMessage(), is(msg));
assertThat(ex.getLocation(), is(locationUri)); assertThat(ex.getLocation(), is(locationUrl));
} }
} }

View File

@ -16,7 +16,6 @@ package org.shredzone.acme4j.it;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
@ -58,24 +57,18 @@ public abstract class AbstractPebbleIT {
} }
/** /**
* Asserts that the given {@link URI} is not {@code null} and refers to the Pebble * Asserts that the given {@link URL} is not {@code null} and refers to the Pebble
* server. * server.
* *
* @param uri * @param url
* {@link URI} to assert * {@link URL} to assert
*/ */
protected void assertIsPebbleUri(URI uri) { protected void assertIsPebbleUrl(URL url) {
assertThat(uri, not(nullValue())); assertThat(url, not(nullValue()));
try {
URL url = uri.toURL();
assertThat(url.getProtocol(), is("http")); assertThat(url.getProtocol(), is("http"));
assertThat(url.getHost(), is(pebbleHost)); assertThat(url.getHost(), is(pebbleHost));
assertThat(url.getPort(), is(pebblePort)); assertThat(url.getPort(), is(pebblePort));
assertThat(url.getPath(), not(isEmptyOrNullString())); assertThat(url.getPath(), not(isEmptyOrNullString()));
} catch (MalformedURLException ex) {
throw new IllegalArgumentException(ex);
}
} }
} }

View File

@ -17,6 +17,7 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.KeyPair; import java.security.KeyPair;
import org.junit.Ignore; import org.junit.Ignore;
@ -44,11 +45,10 @@ public class RegistrationIT extends AbstractPebbleIT {
rb.agreeToTermsOfService(); rb.agreeToTermsOfService();
Registration reg = rb.create(session); Registration reg = rb.create(session);
URI location = reg.getLocation(); URL location = reg.getLocation();
assertIsPebbleUri(location); assertIsPebbleUrl(location);
URI keyIdentifier = session.getKeyIdentifier(); URI keyIdentifier = session.getKeyIdentifier();
assertIsPebbleUri(keyIdentifier); assertThat(keyIdentifier.toString(), is(location.toString()));
assertThat(keyIdentifier, is(location));
// TODO: Not yet supported by Pebble // TODO: Not yet supported by Pebble
/* /*
@ -81,8 +81,8 @@ public class RegistrationIT extends AbstractPebbleIT {
rb.agreeToTermsOfService(); rb.agreeToTermsOfService();
Registration reg = rb.create(session); Registration reg = rb.create(session);
URI location = reg.getLocation(); URL location = reg.getLocation();
assertIsPebbleUri(location); assertIsPebbleUrl(location);
reg.modify().addContact("mailto:acme2@example.com").commit(); reg.modify().addContact("mailto:acme2@example.com").commit();
@ -104,7 +104,7 @@ public class RegistrationIT extends AbstractPebbleIT {
Session session = new Session(pebbleURI(), keyPair); Session session = new Session(pebbleURI(), keyPair);
Registration reg = new RegistrationBuilder().agreeToTermsOfService().create(session); Registration reg = new RegistrationBuilder().agreeToTermsOfService().create(session);
URI location = reg.getLocation(); URL location = reg.getLocation();
KeyPair newKeyPair = createKeyPair(); KeyPair newKeyPair = createKeyPair();
reg.changeKey(newKeyPair); reg.changeKey(newKeyPair);
@ -129,7 +129,7 @@ public class RegistrationIT extends AbstractPebbleIT {
Session session = new Session(pebbleURI(), keyPair); Session session = new Session(pebbleURI(), keyPair);
Registration reg = new RegistrationBuilder().agreeToTermsOfService().create(session); Registration reg = new RegistrationBuilder().agreeToTermsOfService().create(session);
URI location = reg.getLocation(); URL location = reg.getLocation();
reg.deactivate(); reg.deactivate();

View File

@ -53,10 +53,10 @@ public class SessionIT extends AbstractPebbleIT {
Session session = new Session(pebbleURI(), keyPair); Session session = new Session(pebbleURI(), keyPair);
// TODO: Not yet supported by Pebble // TODO: Not yet supported by Pebble
// assertIsPebbleUri(session.resourceUri(Resource.KEY_CHANGE)); // assertIsPebbleUrl(session.resourceUrl(Resource.KEY_CHANGE));
assertIsPebbleUri(session.resourceUri(Resource.NEW_NONCE)); assertIsPebbleUrl(session.resourceUrl(Resource.NEW_NONCE));
assertIsPebbleUri(session.resourceUri(Resource.NEW_REG)); assertIsPebbleUrl(session.resourceUrl(Resource.NEW_REG));
} }
@Test @Test

View File

@ -22,6 +22,7 @@ import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test; import org.junit.Test;
@ -34,6 +35,7 @@ import org.shredzone.acme4j.challenge.TlsSni02Challenge;
import org.shredzone.acme4j.connector.Connection; import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.connector.DefaultConnection; import org.shredzone.acme4j.connector.DefaultConnection;
import org.shredzone.acme4j.connector.HttpConnector; import org.shredzone.acme4j.connector.HttpConnector;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSON; import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.TestUtils; import org.shredzone.acme4j.util.TestUtils;
@ -56,7 +58,7 @@ public class AbstractAcmeProviderTest {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -77,9 +79,9 @@ public class AbstractAcmeProviderTest {
* Verify that the resources directory is read. * Verify that the resources directory is read.
*/ */
@Test @Test
public void testResources() throws Exception { public void testResources() throws AcmeException {
final URI testServerUri = new URI("http://example.com/acme"); final URI testServerUri = URI.create("http://example.com/acme");
final URI testResolvedUri = new URI("http://example.com/acme/directory"); final URL testResolvedUrl = TestUtils.url("http://example.com/acme/directory");
final Connection connection = mock(Connection.class); final Connection connection = mock(Connection.class);
final Session session = mock(Session.class); final Session session = mock(Session.class);
@ -99,16 +101,16 @@ public class AbstractAcmeProviderTest {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
assertThat(serverUri, is(testServerUri)); assertThat(serverUri, is(testServerUri));
return testResolvedUri; return testResolvedUrl;
} }
}; };
JSON map = provider.directory(session, testServerUri); JSON map = provider.directory(session, testServerUri);
assertThat(map.toString(), sameJSONAs(TestUtils.getJson("directory"))); assertThat(map.toString(), sameJSONAs(TestUtils.getJson("directory")));
verify(connection).sendRequest(testResolvedUri, session); verify(connection).sendRequest(testResolvedUrl, session);
verify(connection).accept(any(Integer.class)); verify(connection).accept(any(Integer.class));
verify(connection).updateSession(any(Session.class)); verify(connection).updateSession(any(Session.class));
verify(connection).readJsonResponse(); verify(connection).readJsonResponse();
@ -130,7 +132,7 @@ public class AbstractAcmeProviderTest {
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
}; };

View File

@ -18,6 +18,7 @@ import static org.junit.Assert.assertThat;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import org.junit.Test; import org.junit.Test;
@ -47,8 +48,8 @@ public class GenericAcmeProviderTest {
GenericAcmeProvider provider = new GenericAcmeProvider(); GenericAcmeProvider provider = new GenericAcmeProvider();
URI resolvedUri = provider.resolve(serverUri); URL resolvedUrl = provider.resolve(serverUri);
assertThat(resolvedUri, is(equalTo(serverUri))); assertThat(resolvedUrl.toString(), is(equalTo(serverUri.toString())));
} }
} }

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.provider;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -24,8 +25,8 @@ import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.connector.DummyConnection; import org.shredzone.acme4j.connector.DummyConnection;
import org.shredzone.acme4j.connector.Resource; import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException; import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.JSON; import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.TestUtils; import org.shredzone.acme4j.util.TestUtils;
/** /**
@ -42,9 +43,9 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP
* @param r * @param r
* {@link Resource} to be mapped * {@link Resource} to be mapped
* @param u * @param u
* {@link URI} to be returned * {@link URL} to be returned
*/ */
public void putTestResource(Resource r, URI u) { public void putTestResource(Resource r, URL u) {
directory.put(r.path(), u); directory.put(r.path(), u);
} }
@ -75,7 +76,7 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP
} }
@Override @Override
public URI resolve(URI serverUri) { public URL resolve(URI serverUri) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.provider.letsencrypt;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.shredzone.acme4j.util.TestUtils.url;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -52,10 +53,10 @@ public class LetsEncryptAcmeProviderTest {
public void testResolve() throws URISyntaxException { public void testResolve() throws URISyntaxException {
LetsEncryptAcmeProvider provider = new LetsEncryptAcmeProvider(); LetsEncryptAcmeProvider provider = new LetsEncryptAcmeProvider();
assertThat(provider.resolve(new URI("acme://letsencrypt.org")), is(new URI(V01_DIRECTORY_URI))); assertThat(provider.resolve(new URI("acme://letsencrypt.org")), is(url(V01_DIRECTORY_URI)));
assertThat(provider.resolve(new URI("acme://letsencrypt.org/")), is(new URI(V01_DIRECTORY_URI))); assertThat(provider.resolve(new URI("acme://letsencrypt.org/")), is(url(V01_DIRECTORY_URI)));
assertThat(provider.resolve(new URI("acme://letsencrypt.org/v01")), is(new URI(V01_DIRECTORY_URI))); assertThat(provider.resolve(new URI("acme://letsencrypt.org/v01")), is(url(V01_DIRECTORY_URI)));
assertThat(provider.resolve(new URI("acme://letsencrypt.org/staging")), is(new URI(STAGING_DIRECTORY_URI))); assertThat(provider.resolve(new URI("acme://letsencrypt.org/staging")), is(url(STAGING_DIRECTORY_URI)));
try { try {
provider.resolve(new URI("acme://letsencrypt.org/v99")); provider.resolve(new URI("acme://letsencrypt.org/v99"));

View File

@ -18,8 +18,7 @@ import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI; import java.net.URL;
import java.net.URISyntaxException;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLHandshakeException;
@ -41,12 +40,12 @@ public class LetsEncryptHttpConnectorTest {
*/ */
@Test @Test
@Category(HttpURLConnection.class) @Category(HttpURLConnection.class)
public void testCertificate() throws IOException, URISyntaxException { public void testCertificate() throws IOException {
LetsEncryptHttpConnector connector = new LetsEncryptHttpConnector(); LetsEncryptHttpConnector connector = new LetsEncryptHttpConnector();
try { try {
HttpURLConnection goodConn = connector.openConnection( HttpURLConnection goodConn = connector.openConnection(
new URI("https://acme-staging.api.letsencrypt.org/directory")); new URL("https://acme-staging.api.letsencrypt.org/directory"));
assertThat(goodConn, is(instanceOf(HttpsURLConnection.class))); assertThat(goodConn, is(instanceOf(HttpsURLConnection.class)));
goodConn.connect(); goodConn.connect();
} catch (SSLHandshakeException ex) { } catch (SSLHandshakeException ex) {
@ -55,7 +54,7 @@ public class LetsEncryptHttpConnectorTest {
try { try {
HttpURLConnection badConn = connector.openConnection( HttpURLConnection badConn = connector.openConnection(
new URI("https://www.google.com")); new URL("https://www.google.com"));
assertThat(badConn, is(instanceOf(HttpsURLConnection.class))); assertThat(badConn, is(instanceOf(HttpsURLConnection.class)));
badConn.connect(); badConn.connect();
fail("Connection accepts foreign certificate"); fail("Connection accepts foreign certificate");

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.provider.pebble;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.shredzone.acme4j.util.TestUtils.url;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -50,15 +51,15 @@ public class PebbleAcmeProviderTest {
PebbleAcmeProvider provider = new PebbleAcmeProvider(); PebbleAcmeProvider provider = new PebbleAcmeProvider();
assertThat(provider.resolve(new URI("acme://pebble")), assertThat(provider.resolve(new URI("acme://pebble")),
is(new URI("http://localhost:14000/dir"))); is(url("http://localhost:14000/dir")));
assertThat(provider.resolve(new URI("acme://pebble/")), assertThat(provider.resolve(new URI("acme://pebble/")),
is(new URI("http://localhost:14000/dir"))); is(url("http://localhost:14000/dir")));
assertThat(provider.resolve(new URI("acme://pebble/pebble.example.com")), assertThat(provider.resolve(new URI("acme://pebble/pebble.example.com")),
is(new URI("http://pebble.example.com:14000/dir"))); is(url("http://pebble.example.com:14000/dir")));
assertThat(provider.resolve(new URI("acme://pebble/pebble.example.com:12345")), assertThat(provider.resolve(new URI("acme://pebble/pebble.example.com:12345")),
is(new URI("http://pebble.example.com:12345/dir"))); is(url("http://pebble.example.com:12345/dir")));
assertThat(provider.resolve(new URI("acme://pebble/pebble.example.com:12345/")), assertThat(provider.resolve(new URI("acme://pebble/pebble.example.com:12345/")),
is(new URI("http://pebble.example.com:12345/dir"))); is(url("http://pebble.example.com:12345/dir")));
try { try {
provider.resolve(new URI("acme://pebble/bad.example.com:port")); provider.resolve(new URI("acme://pebble/bad.example.com:port"));

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.util;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.shredzone.acme4j.util.TestUtils.url;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -25,7 +26,6 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
@ -183,7 +183,7 @@ public class JSONTest {
* Test all getters on existing values. * Test all getters on existing values.
*/ */
@Test @Test
public void testGetter() throws MalformedURLException { public void testGetter() {
Instant date = LocalDate.of(2016, 1, 8).atStartOfDay(ZoneId.of("UTC")).toInstant(); Instant date = LocalDate.of(2016, 1, 8).atStartOfDay(ZoneId.of("UTC")).toInstant();
JSON json = TestUtils.getJsonAsObject("json"); JSON json = TestUtils.getJsonAsObject("json");
@ -192,7 +192,7 @@ public class JSONTest {
assertThat(json.get("number").asInt(), is(123)); assertThat(json.get("number").asInt(), is(123));
assertThat(json.get("boolean").asBoolean(), is(true)); assertThat(json.get("boolean").asBoolean(), is(true));
assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com"))); assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com")));
assertThat(json.get("url").asURL(), is(new URL("http://example.com"))); assertThat(json.get("url").asURL(), is(url("http://example.com")));
assertThat(json.get("date").asInstant(), is(date)); assertThat(json.get("date").asInstant(), is(date));
assertThat(json.get("status").asStatusOrElse(Status.INVALID), is(Status.VALID)); assertThat(json.get("status").asStatusOrElse(Status.INVALID), is(Status.VALID));
assertThat(json.get("binary").asBinary(), is("Chainsaw".getBytes())); assertThat(json.get("binary").asBinary(), is("Chainsaw".getBytes()));

View File

@ -17,7 +17,9 @@ import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.KeyPair; import java.security.KeyPair;
@ -120,6 +122,22 @@ public final class TestUtils {
return new Session(URI.create(ACME_SERVER_URI), keyPair); return new Session(URI.create(ACME_SERVER_URI), keyPair);
} }
/**
* Creates an {@link URL} from a String. Only throws a runtime exception if the URL is
* malformed.
*
* @param url
* URL to use
* @return {@link URL} object
*/
public static URL url(String url) {
try {
return new URL(url);
} catch (MalformedURLException ex) {
throw new IllegalArgumentException(url, ex);
}
}
/** /**
* Creates a {@link Session} instance. It uses {@link #ACME_SERVER_URI} as server URI. * Creates a {@link Session} instance. It uses {@link #ACME_SERVER_URI} as server URI.
* *

View File

@ -24,7 +24,7 @@ Some CAs provide metadata related to their ACME server. This information can be
```java ```java
Metadata meta = session.getMetadata(); Metadata meta = session.getMetadata();
URI website = meta.getWebsite(); URL website = meta.getWebsite();
``` ```
`meta` is never `null`, even if the server did not provide any metadata. All of the `Metadata` getters are optional though, and may return `null` if the respective information was not provided by the server. `meta` is never `null`, even if the server did not provide any metadata. All of the `Metadata` getters are optional though, and may return `null` if the respective information was not provided by the server.

View File

@ -32,11 +32,11 @@ Session session = new Session("acme://letsencrypt.org/staging", keyPair);
Instead of creating a plain `Registration` object, you now bind it to the session. Instead of creating a plain `Registration` object, you now bind it to the session.
```java ```java
URI accountLocationUri = ... // your account's URI URL accountLocationUrl = ... // your account's URL
Registration registration = Registration.bind(session, accountLocationUri); Registration registration = Registration.bind(session, accountLocationUrl);
``` ```
You must know your account's location URI. Use a `RegistrationBuilder` if you do not know it, or if you want to register a new account: You must know your account's location URL. Use a `RegistrationBuilder` if you do not know it, or if you want to register a new account:
```java ```java
Registration registration; Registration registration;
@ -45,7 +45,7 @@ try {
registration = new RegistrationBuilder().create(session); registration = new RegistrationBuilder().create(session);
} catch (AcmeConflictException ex) { } catch (AcmeConflictException ex) {
// It failed because your key was already registered. // It failed because your key was already registered.
// Retrieve the registration location URI from the exception. // Retrieve the registration location URL from the exception.
registration = Registration.bind(session, ex.getLocation()); registration = Registration.bind(session, ex.getLocation());
} }
``` ```

View File

@ -21,11 +21,11 @@ However, it is also possible to adapt the behavior of wide parts of _acme4j_ to
A client provider implements the [`AcmeProvider`](./apidocs/org/shredzone/acme4j/provider/AcmeProvider.html) interface, but usually it is easier to extend [`AbstractAcmeProvider`](./apidocs/org/shredzone/acme4j/provider/AbstractAcmeProvider.html) and implement only these two methods: A client provider implements the [`AcmeProvider`](./apidocs/org/shredzone/acme4j/provider/AcmeProvider.html) interface, but usually it is easier to extend [`AbstractAcmeProvider`](./apidocs/org/shredzone/acme4j/provider/AbstractAcmeProvider.html) and implement only these two methods:
* `accepts(URI)` checks if the client provider is accepting the provided URI. Usually it would be an URI like `acme://example.com`. Note that the `http` and `https` schemes are reserved for the generic provider and cannot be used by other providers. * `accepts(URI)` checks if the client provider is accepting the provided URI. Usually it would be an URI like `acme://example.com`. Note that the `http` and `https` schemes are reserved for the generic provider and cannot be used by other providers.
* `resolve(URI)` parses that URI and returns the corresponding URI of the directory service. * `resolve(URI)` parses that URI and returns the corresponding URL of the directory service.
The `AcmeProvider` implementation needs to be registered with Java's `ServiceLoader`. In the `META-INF/services` path of your project, create a file `org.shredzone.acme4j.provider.AcmeProvider` and write the fully qualified class name of your implementation into that file. The `AcmeProvider` implementation needs to be registered with Java's `ServiceLoader`. In the `META-INF/services` path of your project, create a file `org.shredzone.acme4j.provider.AcmeProvider` and write the fully qualified class name of your implementation into that file.
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 URI that is returned. 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 none or more than one `AcmeProvider` implementations `accept` the acme URI.
@ -45,4 +45,4 @@ In your `AcmeProvider` implementation, override the `createChallenge(Session, St
An ACME server may not provide a directory service, for example when fixed URIs are to be used. An ACME server may not provide a directory service, for example when fixed URIs are to be used.
In this case, override the `resources(Session, URI)` method, and return a `Map` of all available resources and their respective URI. In this case, override the `directory(Session, URI)` method, and return a `JSON` of all available resources and their respective URI.

View File

@ -56,12 +56,12 @@ If your final certificate will contain further domains or subdomains, repeat the
## Update an Authorization ## Update an Authorization
The server also provides an authorization URI. It can be retrieved from `Authorization.getLocation()`. You can recreate the `Authorization` object at a later time just by binding it to your `Session`: 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 ```java
URI authUri = ... // Authorization URI URL authUrl = ... // Authorization URL
Authorization auth = Authorization.bind(session, authUri); 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. 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.
@ -84,13 +84,13 @@ To recreate a `Challenge` object at a later time, all you need is to store the o
```java ```java
Challenge originalChallenge = ... // some Challenge instance Challenge originalChallenge = ... // some Challenge instance
URI challengeUri = originalChallenge.getLocation(); URL challengeUrl = originalChallenge.getLocation();
``` ```
Later, you restore the `Challenge` object by invoking `Challenge.bind()`. Later, you restore the `Challenge` object by invoking `Challenge.bind()`.
```java ```java
URI challengeUri = ... // challenge URI URL challengeUrl = ... // challenge URL
Challenge restoredChallenge = Challenge.bind(session, challengeUri); Challenge restoredChallenge = Challenge.bind(session, challengeUri);
``` ```

View File

@ -34,7 +34,7 @@ Now all you need to do is to pass in a binary representation of the CSR and requ
Certificate cert = registration.requestCertificate(csr); Certificate cert = registration.requestCertificate(csr);
``` ```
`cert.getLocation()` returns an URI where the signed certificate can be downloaded from. Optionally (if delivered by the ACME server) `cert.getChainLocation()` returns the URI of the first part of the CA chain. `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. The `Certificate` object offers methods to download the certificate and the certificate chain.
@ -50,8 +50,8 @@ Congratulations! You have just created your first certificate via _acme4j_.
To recreate a `Certificate` object from the location, just bind it: To recreate a `Certificate` object from the location, just bind it:
```java ```java
URI locationUri = ... // location URI from cert.getLocation() URL locationUrl = ... // location URL from cert.getLocation()
Certificate cert = Certificate.bind(session, locationUri); Certificate cert = Certificate.bind(session, locationUrl);
``` ```
### Saving Certificates ### Saving Certificates

View File

@ -2,7 +2,7 @@
If it is the first time you connect to the ACME server, you need to register your account key. 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, 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. 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 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 ```java
RegistrationBuilder builder = new RegistrationBuilder(); RegistrationBuilder builder = new RegistrationBuilder();
@ -11,10 +11,10 @@ builder.agreeToTermsOfService();
Registration registration = builder.create(session); Registration registration = builder.create(session);
URI accountLocationUri = registration.getLocation(); URL accountLocationUrl = registration.getLocation();
``` ```
`create()` will fail and throw an `AcmeConflictException` if your key was already registered with the CA. The `AcmeConflictException` contains the location of the registration. This may be helpful if you forgot your account URI and need to recover it. `create()` will fail and throw an `AcmeConflictException` if your key was already registered with the CA. The `AcmeConflictException` contains the location of the registration. This may be helpful if you forgot your account URL and need to recover it.
The following example will create a new `Registration` and restore an existing `Registration`. The following example will create a new `Registration` and restore an existing `Registration`.
@ -34,8 +34,6 @@ At some point, you may want to update your registration. For example your contac
The following example adds another email address. The following example adds another email address.
```java ```java
URI agreementUri = ... // TAC link provided by the CA
registration.modify() registration.modify()
.addContact("mailto:acme2@example.com") .addContact("mailto:acme2@example.com")
.commit(); .commit();

View File

@ -31,12 +31,12 @@ Instead of a generic provider, this call uses a special _Let's Encrypt_ provider
Now that you have a `Session` object, you can use it to bind ACME resource objects. For example, this is the way to get a `Registration` object to an existing registration: Now that you have a `Session` object, you can use it to bind ACME resource objects. For example, this is the way to get a `Registration` object to an existing registration:
```java ```java
URI accountLocationUri = ... // your account's URI, as returned by Registration.getLocation() URL accountLocationUrl = ... // your account's URL, as returned by Registration.getLocation()
Registration registration = Registration.bind(session, accountLocationUri); Registration registration = Registration.bind(session, accountLocationUrl);
``` ```
You can create any of the resource objects `Registration`, `Authorization`, `Challenge` and `Certificate` like that, as long as you know the corresponding resource URI. To get the resource URI, use the `getLocation()` method. You can create any of the resource objects `Registration`, `Authorization`, `Challenge` and `Certificate` like that, as long as you know the corresponding resource URL. To get the resource URL, use the `getLocation()` method.
## Serialization ## Serialization