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;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Objects;
import org.shredzone.acme4j.exception.AcmeProtocolException;
/**
* A generic ACME resource.
*/
@ -24,7 +27,7 @@ public abstract class AcmeResource implements Serializable {
private static final long serialVersionUID = -7930580802257379731L;
private transient Session session;
private URI location;
private URL location;
/**
* Create a new {@link AcmeResource}.
@ -57,9 +60,13 @@ public abstract class AcmeResource implements Serializable {
/**
* Sets the resource's location.
*/
protected void setLocation(URI location) {
protected void setLocation(URL 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.
*/
public URI getLocation() {
public URL getLocation() {
return location;
}

View File

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

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
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 int MAX_CHAIN_LENGTH = 10;
private URI chainCertUri;
private URL chainCertUrl;
private X509Certificate cert = null;
private X509Certificate[] chain = null;
protected Certificate(Session session, URI certUri) {
protected Certificate(Session session, URL certUrl) {
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);
setLocation(certUri);
this.chainCertUri = chainUri;
setLocation(certUrl);
this.chainCertUrl = chainUrl;
this.cert = cert;
}
@ -62,16 +62,16 @@ public class Certificate extends AcmeResource {
* Location of the Certificate
* @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);
}
/**
* 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.
*/
public URI getChainLocation() {
return chainCertUri;
public URL getChainLocation() {
return chainCertUrl;
}
/**
@ -92,7 +92,7 @@ public class Certificate extends AcmeResource {
conn.accept(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED);
conn.handleRetryAfter("certificate is not available for download yet");
chainCertUri = conn.getLink("up");
chainCertUrl = conn.getLink("up");
cert = conn.readCertificate();
}
}
@ -111,21 +111,21 @@ public class Certificate extends AcmeResource {
*/
public X509Certificate[] downloadChain() throws AcmeException {
if (chain == null) {
if (chainCertUri == null) {
if (chainCertUrl == null) {
download();
}
if (chainCertUri == null) {
if (chainCertUrl == null) {
throw new AcmeProtocolException("No certificate chain provided");
}
LOG.debug("downloadChain");
List<X509Certificate> certChain = new ArrayList<>();
URI link = chainCertUri;
URL link = chainCertUrl;
while (link != null && certChain.size() < MAX_CHAIN_LENGTH) {
try (Connection conn = getSession().provider().connect()) {
conn.sendRequest(chainCertUri, getSession());
conn.sendRequest(chainCertUrl, getSession());
conn.accept(HttpURLConnection.HTTP_OK);
certChain.add(conn.readCertificate());
@ -159,8 +159,8 @@ public class Certificate extends AcmeResource {
*/
public void revoke(RevocationReason reason) throws AcmeException {
LOG.debug("revoke");
URI resUri = getSession().resourceUri(Resource.REVOKE_CERT);
if (resUri == null) {
URL resUrl = getSession().resourceUrl(Resource.REVOKE_CERT);
if (resUrl == null) {
throw new AcmeProtocolException("CA does not support certificate revocation");
}
@ -176,7 +176,7 @@ public class Certificate extends AcmeResource {
claims.put("reason", reason.getReasonCode());
}
conn.sendSignedRequest(resUri, claims, getSession());
conn.sendSignedRequest(resUrl, claims, getSession());
conn.accept(HttpURLConnection.HTTP_OK);
} catch (CertificateEncodingException 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 java.net.URI;
import java.net.URL;
import java.util.Collection;
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.
*/
public URI getWebsite() {
return meta.get("website").asURI();
public URL getWebsite() {
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.URI;
import java.net.URL;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.time.Instant;
@ -57,11 +58,11 @@ public class Registration extends AcmeResource {
private final List<URI> contacts = new ArrayList<>();
private Status status;
private Boolean termsOfServiceAgreed;
private URI authorizations;
private URI certificates;
private URL authorizations;
private URL certificates;
private boolean loaded = false;
protected Registration(Session session, URI location) {
protected Registration(Session session, URL location) {
super(session);
setLocation(location);
}
@ -75,7 +76,7 @@ public class Registration extends AcmeResource {
* Location URI of the registration
* @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);
}
@ -180,7 +181,7 @@ public class Registration extends AcmeResource {
.put("type", "dns")
.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);
JSON json = conn.readJsonResponse();
@ -235,7 +236,7 @@ public class Registration extends AcmeResource {
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);
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");
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());
JSONBuilder payloadClaim = new JSONBuilder();
@ -281,7 +282,7 @@ public class Registration extends AcmeResource {
JsonWebSignature innerJws = new JsonWebSignature();
innerJws.setPayload(payloadClaim.toString());
innerJws.getHeaders().setObjectHeaderValue("url", keyChangeUri);
innerJws.getHeaders().setObjectHeaderValue("url", keyChangeUrl);
innerJws.getHeaders().setJwkHeaderValue("jwk", newKeyJwk);
innerJws.setAlgorithmHeaderValue(keyAlgorithm(newKeyJwk));
innerJws.setKey(newKeyPair.getPrivate());
@ -293,7 +294,7 @@ public class Registration extends AcmeResource {
outerClaim.put("signature", innerJws.getEncodedSignature());
outerClaim.put("payload", innerJws.getEncodedPayload());
conn.sendSignedRequest(keyChangeUri, outerClaim, getSession());
conn.sendSignedRequest(keyChangeUrl, outerClaim, getSession());
conn.accept(HttpURLConnection.HTTP_OK);
getSession().setKeyPair(newKeyPair);
@ -356,14 +357,14 @@ public class Registration extends AcmeResource {
.forEach(contacts::add);
}
this.authorizations = json.get(KEY_AUTHORIZATIONS).asURI();
this.certificates = json.get(KEY_CERTIFICATES).asURI();
this.authorizations = json.get(KEY_AUTHORIZATIONS).asURL();
this.certificates = json.get(KEY_CERTIFICATES).asURL();
if (json.contains(KEY_STATUS)) {
this.status = Status.parse(json.get(KEY_STATUS).asString());
}
URI location = conn.getLocation();
URL location = conn.getLocation();
if (location != null) {
setLocation(location);
}

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@ -101,10 +102,10 @@ public class RegistrationBuilder {
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);
URI location = conn.getLocation();
URL location = conn.getLocation();
return new Registration(session, location);
}

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j;
import java.net.URI;
import java.net.URL;
import java.security.KeyPair;
import java.time.Duration;
import java.time.Instant;
@ -40,7 +41,7 @@ import org.shredzone.acme4j.util.JSON;
* volatile data.
*/
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 URI serverUri;
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.
*
* @param resource
* {@link Resource} to get the {@link URI} of
* @return {@link URI}, or {@code null} if the server does not offer that resource
* {@link Resource} to get the {@link URL} of
* @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();
return resourceMap.get().get(Objects.requireNonNull(resource, "resource"));
}
@ -234,11 +235,11 @@ public class Session {
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()) {
URI uri = directoryJson.get(res.path()).asURI();
if (uri != null) {
map.put(res, uri);
URL url = directoryJson.get(res.path()).asURL();
if (url != null) {
map.put(res, url);
}
}
resourceMap.set(map);

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j.challenge;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.time.Instant;
import java.util.Objects;
@ -70,7 +70,7 @@ public class Challenge extends AcmeResource {
* @return {@link Challenge} bound to this session and location
*/
@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(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
public URI getLocation() {
return data.get(KEY_URI).asURI();
public URL getLocation() {
return data.get(KEY_URI).asURL();
}
/**

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.connector;
import java.net.URI;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.Collection;
@ -39,38 +40,38 @@ public interface Connection extends AutoCloseable {
/**
* Sends a simple GET request.
*
* @param uri
* {@link URI} to send the request to.
* @param url
* {@link URL} to send the request to.
* @param session
* {@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
* is used in the "kid" protected header.
*
* @param uri
* {@link URI} to send the request to.
* @param url
* {@link URL} to send the request to.
* @param claims
* {@link JSONBuilder} containing claims. Must not be {@code null}.
* @param session
* {@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"
* protected header is sent. If not, a "jwk" protected header is sent.
*
* @param uri
* {@link URI} to send the request to.
* @param url
* {@link URL} to send the request to.
* @param claims
* {@link JSONBuilder} containing claims. Must not be {@code null}.
* @param session
* {@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,
@ -118,12 +119,12 @@ public interface Connection extends AutoCloseable {
* <p>
* 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>
* Relative links are resolved against the last request's URL. If there is more than
* one relation, the first one is returned.
@ -132,10 +133,10 @@ public interface Connection extends AutoCloseable {
* Link relation
* @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>
* Relative links are resolved against the last request's URL.
*

View File

@ -97,9 +97,9 @@ public class DefaultConnection implements Connection {
try {
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.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag());
conn.connect();
@ -123,15 +123,15 @@ public class DefaultConnection implements Connection {
}
@Override
public void sendRequest(URI uri, Session session) throws AcmeException {
Objects.requireNonNull(uri, "uri");
public void sendRequest(URL url, Session session) throws AcmeException {
Objects.requireNonNull(url, "url");
Objects.requireNonNull(session, "session");
assertConnectionIsClosed();
LOG.debug("GET {}", uri);
LOG.debug("GET {}", url);
try {
conn = httpConnector.openConnection(uri);
conn = httpConnector.openConnection(url);
conn.setRequestMethod("GET");
conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET);
conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag());
@ -146,17 +146,17 @@ public class DefaultConnection implements Connection {
}
@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) {
throw new IllegalStateException("session has no KeyIdentifier set");
}
sendJwkSignedRequest(uri, claims, session);
sendJwkSignedRequest(url, claims, session);
}
@Override
public void sendJwkSignedRequest(URI uri, JSONBuilder claims, Session session) throws AcmeException {
Objects.requireNonNull(uri, "uri");
public void sendJwkSignedRequest(URL url, JSONBuilder claims, Session session) throws AcmeException {
Objects.requireNonNull(url, "url");
Objects.requireNonNull(claims, "claims");
Objects.requireNonNull(session, "session");
assertConnectionIsClosed();
@ -168,9 +168,9 @@ public class DefaultConnection implements Connection {
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.setRequestProperty(ACCEPT_HEADER, "application/json");
conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET);
@ -182,7 +182,7 @@ public class DefaultConnection implements Connection {
JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toString());
jws.getHeaders().setObjectHeaderValue("nonce", Base64Url.encode(session.getNonce()));
jws.getHeaders().setObjectHeaderValue("url", uri);
jws.getHeaders().setObjectHeaderValue("url", url);
if (session.getKeyIdentifier() != null) {
jws.getHeaders().setObjectHeaderValue("kid", session.getKeyIdentifier());
} else {
@ -317,7 +317,7 @@ public class DefaultConnection implements Connection {
}
@Override
public URI getLocation() {
public URL getLocation() {
assertConnectionIsOpen();
String location = conn.getHeaderField(LOCATION_HEADER);
@ -326,11 +326,11 @@ public class DefaultConnection implements Connection {
}
LOG.debug("Location: {}", location);
return resolveRelative(location);
return toURL(resolveRelative(location));
}
@Override
public URI getLink(String relation) {
public URL getLink(String relation) {
Collection<URI> links = getLinks(relation);
if (links == null) {
return null;
@ -340,7 +340,7 @@ public class DefaultConnection implements Connection {
LOG.debug("Link: {} - using the first of {}", relation, links.size());
}
return links.iterator().next();
return toURL(links.iterator().next());
}
@Override
@ -418,8 +418,8 @@ public class DefaultConnection implements Connection {
if ("agreementRequired".equals(error)) {
URI instance = resolveRelative(json.get("instance").asString());
URI tos = getLink("terms-of-service");
return new AcmeAgreementRequiredException(type, detail, tos, instance);
URI tos = getLinks("terms-of-service").stream().findFirst().orElse(null);
return new AcmeAgreementRequiredException(type, detail, tos, toURL(instance));
}
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
* Link to resolve. Absolute links are just converted to an URI. May be
@ -480,10 +480,27 @@ public class DefaultConnection implements Connection {
assertConnectionIsOpen();
try {
return new URL(conn.getURL(), link).toURI();
} catch (MalformedURLException | URISyntaxException ex) {
return conn.getURL().toURI().resolve(link);
} catch (URISyntaxException 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.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.Properties;
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
* {@link URI} to connect to
* @return {@link HttpURLConnection} connected to the {@link URI}
* @param url
* {@link URL} to connect to
* @return {@link HttpURLConnection} connected to the {@link URL}
*/
public HttpURLConnection openConnection(URI uri) throws IOException {
HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection();
public HttpURLConnection openConnection(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
configure(conn);
return conn;
}

View File

@ -14,7 +14,7 @@
package org.shredzone.acme4j.connector;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
@ -29,7 +29,7 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
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.
*
* @param <T>
@ -39,10 +39,10 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
private final Session session;
private final String field;
private final Deque<URI> uriList = new ArrayDeque<>();
private final BiFunction<Session, URI, T> creator;
private final Deque<URL> urlList = new ArrayDeque<>();
private final BiFunction<Session, URL, T> creator;
private boolean eol = false;
private URI nextUri;
private URL nextUrl;
/**
* Creates a new {@link ResourceIterator}.
@ -52,15 +52,15 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
* @param field
* Field name to be used in the JSON response
* @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
* 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.field = Objects.requireNonNull(field, "field");
this.nextUri = start;
this.nextUrl = start;
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.
*
* @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
public boolean hasNext() {
@ -76,32 +76,32 @@ public class ResourceIterator<T extends AcmeResource> implements Iterator<T> {
return false;
}
if (uriList.isEmpty()) {
if (urlList.isEmpty()) {
fetch();
}
if (uriList.isEmpty()) {
if (urlList.isEmpty()) {
eol = true;
}
return !uriList.isEmpty();
return !urlList.isEmpty();
}
/**
* Returns the next object of the result.
*
* @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
* if there are no more entries
*/
@Override
public T next() {
if (!eol && uriList.isEmpty()) {
if (!eol && urlList.isEmpty()) {
fetch();
}
URI next = uriList.poll();
URL next = urlList.poll();
if (next == null) {
eol = true;
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
* URI of the next batch.
* Fetches the next batch of URLs. Handles exceptions. Does nothing if there is no
* URL of the next batch.
*/
private void fetch() {
if (nextUri == null) {
if (nextUrl == null) {
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
* there is a "next" header, it is used for the next batch of URIs.
* 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 URLs.
*/
private void readAndQueue() throws AcmeException {
try (Connection conn = session.provider().connect()) {
conn.sendRequest(nextUri, session);
conn.sendRequest(nextUrl, session);
conn.accept(HttpURLConnection.HTTP_OK);
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
* JSON map to read from
*/
private void fillUriList(JSON json) {
private void fillUrlList(JSON json) {
json.get(field).asArray().stream()
.map(JSON.Value::asURI)
.forEach(uriList::add);
.map(JSON.Value::asURL)
.forEach(urlList::add);
}
}

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.exception;
import java.net.URI;
import java.net.URL;
/**
* 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 final URI agreementUri;
private final URI instance;
private final URL instance;
/**
* Creates a new {@link AcmeAgreementRequiredException}.
@ -36,10 +37,10 @@ public class AcmeAgreementRequiredException extends AcmeServerException {
* @param agreementUri
* {@link URI} of the agreement document to accept
* @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.
*/
public AcmeAgreementRequiredException(String type, String detail, URI agreementUri, URI instance) {
public AcmeAgreementRequiredException(String type, String detail, URI agreementUri, URL instance) {
super(type, detail);
this.agreementUri = agreementUri;
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.
*/
public URI getInstance() {
public URL getInstance() {
return instance;
}

View File

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

View File

@ -14,6 +14,7 @@
package org.shredzone.acme4j.provider;
import java.net.URI;
import java.net.URL;
import java.util.ServiceLoader;
import org.shredzone.acme4j.Session;
@ -41,15 +42,15 @@ public interface AcmeProvider {
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
* Server {@link URI}
* @return Resolved directory {@link URI}
* @return Resolved directory {@link URL}
* @throws IllegalArgumentException
* 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.

View File

@ -13,7 +13,9 @@
*/
package org.shredzone.acme4j.provider;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
/**
* A generic {@link AcmeProvider}. It should be working for all ACME servers complying to
@ -30,8 +32,12 @@ public class GenericAcmeProvider extends AbstractAcmeProvider {
}
@Override
public URI resolve(URI serverUri) {
return serverUri;
public URL resolve(URI 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;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.shredzone.acme4j.connector.HttpConnector;
import org.shredzone.acme4j.exception.AcmeProtocolException;
@ -34,8 +35,8 @@ import org.shredzone.acme4j.provider.AcmeProvider;
*/
public class LetsEncryptAcmeProvider extends AbstractAcmeProvider {
private static final String V01_DIRECTORY_URI = "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 V01_DIRECTORY_URL = "https://acme-v01.api.letsencrypt.org/directory";
private static final String STAGING_DIRECTORY_URL = "https://acme-staging.api.letsencrypt.org/directory";
@Override
public boolean accepts(URI serverUri) {
@ -44,21 +45,21 @@ public class LetsEncryptAcmeProvider extends AbstractAcmeProvider {
}
@Override
public URI resolve(URI serverUri) {
public URL resolve(URI serverUri) {
String path = serverUri.getPath();
String directoryUri;
String directoryUrl;
if (path == null || "".equals(path) || "/".equals(path) || "/v01".equals(path)) {
directoryUri = V01_DIRECTORY_URI;
directoryUrl = V01_DIRECTORY_URL;
} else if ("/staging".equals(path)) {
directoryUri = STAGING_DIRECTORY_URI;
directoryUrl = STAGING_DIRECTORY_URL;
} else {
throw new IllegalArgumentException("Unknown URI " + serverUri);
}
try {
return new URI(directoryUri);
} catch (URISyntaxException ex) {
throw new AcmeProtocolException(directoryUri, ex);
return new URL(directoryUrl);
} catch (MalformedURLException ex) {
throw new AcmeProtocolException(directoryUrl, ex);
}
}

View File

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

View File

@ -15,7 +15,6 @@ package org.shredzone.acme4j.provider.pebble;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -44,7 +43,7 @@ public class PebbleAcmeProvider extends AbstractAcmeProvider {
}
@Override
public URI resolve(URI serverUri) {
public URL resolve(URI serverUri) {
try {
String path = serverUri.getPath();
@ -64,8 +63,8 @@ public class PebbleAcmeProvider extends AbstractAcmeProvider {
}
}
return baseUrl.toURI();
} catch (MalformedURLException | URISyntaxException ex) {
return baseUrl;
} catch (MalformedURLException 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.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URI;
import java.net.URL;
import org.junit.Test;
import org.shredzone.acme4j.util.TestUtils;
@ -36,7 +36,7 @@ public class AcmeResourceTest {
@Test
public void testConstructor() throws Exception {
Session session = TestUtils.session();
URI location = new URI("http://example.com/acme/resource");
URL location = new URL("http://example.com/acme/resource");
try {
new DummyResource(null);

View File

@ -20,7 +20,7 @@ import static org.shredzone.acme4j.util.TestUtils.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
@ -44,7 +44,7 @@ public class AuthorizationTest {
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
@ -121,8 +121,8 @@ public class AuthorizationTest {
public void testUpdate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendRequest(URI uri, Session session) {
assertThat(uri, is(locationUri));
public void sendRequest(URL url, Session session) {
assertThat(url, is(locationUrl));
}
@Override
@ -150,13 +150,13 @@ public class AuthorizationTest {
provider.putTestChallenge("http-01", httpChallenge);
provider.putTestChallenge("dns-01", dnsChallenge);
Authorization auth = new Authorization(session, locationUri);
Authorization auth = new Authorization(session, locationUrl);
auth.update();
assertThat(auth.getDomain(), is("example.org"));
assertThat(auth.getStatus(), is(Status.VALID));
assertThat(auth.getExpires(), is(parseTimestamp("2016-01-02T17:12:40Z")));
assertThat(auth.getLocation(), is(locationUri));
assertThat(auth.getLocation(), is(locationUrl));
assertThat(auth.getChallenges(), containsInAnyOrder(
(Challenge) httpChallenge, (Challenge) dnsChallenge));
@ -179,9 +179,9 @@ public class AuthorizationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendRequest(URI uri, Session session) {
public void sendRequest(URL url, Session session) {
requestWasSent.set(true);
assertThat(uri, is(locationUri));
assertThat(url, is(locationUrl));
}
@Override
@ -207,7 +207,7 @@ public class AuthorizationTest {
provider.putTestChallenge("http-01", new Http01Challenge(session));
provider.putTestChallenge("dns-01", new Dns01Challenge(session));
Authorization auth = new Authorization(session, locationUri);
Authorization auth = new Authorization(session, locationUrl);
// Lazy loading
assertThat(requestWasSent.get(), is(false));
@ -233,8 +233,8 @@ public class AuthorizationTest {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendRequest(URI uri, Session session) {
assertThat(uri, is(locationUri));
public void sendRequest(URL url, Session session) {
assertThat(url, is(locationUrl));
}
@Override
@ -262,7 +262,7 @@ public class AuthorizationTest {
provider.putTestChallenge("http-01", httpChallenge);
provider.putTestChallenge("dns-01", dnsChallenge);
Authorization auth = new Authorization(session, locationUri);
Authorization auth = new Authorization(session, locationUrl);
try {
auth.update();
@ -274,7 +274,7 @@ public class AuthorizationTest {
assertThat(auth.getDomain(), is("example.org"));
assertThat(auth.getStatus(), is(Status.VALID));
assertThat(auth.getExpires(), is(parseTimestamp("2016-01-02T17:12:40Z")));
assertThat(auth.getLocation(), is(locationUri));
assertThat(auth.getLocation(), is(locationUrl));
assertThat(auth.getChallenges(), containsInAnyOrder(
(Challenge) httpChallenge, (Challenge) dnsChallenge));
@ -295,11 +295,11 @@ public class AuthorizationTest {
public void testDeactivate() throws Exception {
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) {
public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
JSON json = claims.toJSON();
assertThat(json.get("resource").asString(), is("authz"));
assertThat(json.get("status").asString(), is("deactivated"));
assertThat(uri, is(locationUri));
assertThat(url, is(locationUrl));
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();
provider.close();
@ -328,7 +328,7 @@ public class AuthorizationTest {
provider.putTestChallenge(Dns01Challenge.TYPE, new Dns01Challenge(session));
provider.putTestChallenge(TlsSni02Challenge.TYPE, new TlsSni02Challenge(session));
Authorization authorization = new Authorization(session, locationUri);
Authorization authorization = new Authorization(session, locationUrl);
authorization.unmarshalAuthorization(getJsonAsObject("authorizationChallenges"));
return authorization;
}

View File

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

View File

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

View File

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

View File

@ -56,7 +56,7 @@ import org.shredzone.acme4j.util.TestUtils;
*/
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 HttpURLConnection mockUrlConnection;
private HttpConnector mockHttpConnection;
@ -67,7 +67,7 @@ public class DefaultConnectionTest {
mockUrlConnection = mock(HttpURLConnection.class);
mockHttpConnection = mock(HttpConnector.class);
when(mockHttpConnection.openConnection(requestUri)).thenReturn(mockUrlConnection);
when(mockHttpConnection.openConnection(requestUrl)).thenReturn(mockUrlConnection);
final AcmeProvider mockProvider = mock(AcmeProvider.class);
when(mockProvider.directory(
@ -149,7 +149,7 @@ public class DefaultConnectionTest {
public void testResetNonce() throws AcmeException, IOException {
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);
when(mockUrlConnection.getResponseCode())
.thenReturn(HttpURLConnection.HTTP_NO_CONTENT);
@ -192,8 +192,8 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
URI location = conn.getLocation();
assertThat(location, is(new URI("https://example.com/otherlocation")));
URL location = conn.getLocation();
assertThat(location, is(new URL("https://example.com/otherlocation")));
}
verify(mockUrlConnection).getHeaderField("Location");
@ -211,8 +211,8 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
URI location = conn.getLocation();
assertThat(location, is(new URI("https://example.org/otherlocation")));
URL location = conn.getLocation();
assertThat(location, is(new URL("https://example.org/otherlocation")));
}
verify(mockUrlConnection).getHeaderField("Location");
@ -239,9 +239,9 @@ public class DefaultConnectionTest {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
assertThat(conn.getLink("next"), is(new URI("https://example.com/acme/new-authz")));
assertThat(conn.getLink("recover"), is(new URI("https://example.org/recover-reg")));
assertThat(conn.getLink("terms-of-service"), is(new URI("https://example.com/acme/terms")));
assertThat(conn.getLink("next"), is(new URL("https://example.com/acme/new-authz")));
assertThat(conn.getLink("recover"), is(new URL("https://example.org/recover-reg")));
assertThat(conn.getLink("terms-of-service"), is(new URL("https://example.com/acme/terms")));
assertThat(conn.getLink("secret-stuff"), is(nullValue()));
}
}
@ -251,14 +251,17 @@ public class DefaultConnectionTest {
*/
@Test
public void testGetMultiLink() {
URL baseUrl = TestUtils.url("https://example.com/acme/request/1234");
Map<String, List<String>> headers = new HashMap<>();
headers.put("Link", Arrays.asList(
"<https://example.com/acme/terms1>; 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.getURL()).thenReturn(baseUrl);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
@ -291,7 +294,7 @@ public class DefaultConnectionTest {
public void testNoLocation() throws Exception {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
URI location = conn.getLocation();
URL location = conn.getLocation();
assertThat(location, is(nullValue()));
}
@ -536,7 +539,7 @@ public class DefaultConnectionTest {
@Test
public void testSendRequest() throws Exception {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.sendRequest(requestUri, session);
conn.sendRequest(requestUrl, session);
}
verify(mockUrlConnection).setRequestMethod("GET");
@ -583,7 +586,7 @@ public class DefaultConnectionTest {
JSONBuilder cb = new JSONBuilder();
cb.put("foo", 123).put("bar", "a-string");
session.setKeyIdentifier(keyIdentifierUri);
conn.sendSignedRequest(requestUri, cb, session);
conn.sendSignedRequest(requestUrl, cb, session);
}
verify(mockUrlConnection).setRequestMethod("POST");
@ -607,7 +610,7 @@ public class DefaultConnectionTest {
StringBuilder expectedHeader = new StringBuilder();
expectedHeader.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("\"kid\":\"").append(keyIdentifierUri).append('"');
expectedHeader.append('}');
@ -656,7 +659,7 @@ public class DefaultConnectionTest {
}) {
JSONBuilder cb = new JSONBuilder();
cb.put("foo", 123).put("bar", "a-string");
conn.sendJwkSignedRequest(requestUri, cb, session);
conn.sendJwkSignedRequest(requestUrl, cb, session);
}
verify(mockUrlConnection).setRequestMethod("POST");
@ -680,7 +683,7 @@ public class DefaultConnectionTest {
StringBuilder expectedHeader = new StringBuilder();
expectedHeader.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("\"jwk\":{");
expectedHeader.append("\"kty\":\"").append(TestUtils.KTY).append("\",");
@ -705,7 +708,7 @@ public class DefaultConnectionTest {
public void testSendSignedRequestNoKidFailed() throws Exception {
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
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)
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);
when(mockUrlConnection.getResponseCode())
.thenReturn(HttpURLConnection.HTTP_NOT_FOUND);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
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;
import java.net.URI;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.Collection;
@ -34,17 +35,17 @@ public class DummyConnection implements Connection {
}
@Override
public void sendRequest(URI uri, Session session) {
public void sendRequest(URL url, Session session) {
throw new UnsupportedOperationException();
}
@Override
public void sendSignedRequest(URI uri, JSONBuilder claims, Session session) {
public void sendSignedRequest(URL url, JSONBuilder claims, Session session) {
throw new UnsupportedOperationException();
}
@Override
public void sendJwkSignedRequest(URI uri, JSONBuilder claims, Session session) {
public void sendJwkSignedRequest(URL url, JSONBuilder claims, Session session) {
throw new UnsupportedOperationException();
}
@ -74,12 +75,12 @@ public class DummyConnection implements Connection {
}
@Override
public URI getLocation() {
public URL getLocation() {
throw new UnsupportedOperationException();
}
@Override
public URI getLink(String relation) {
public URL getLink(String relation) {
throw new UnsupportedOperationException();
}

View File

@ -20,8 +20,8 @@ import static org.mockito.Mockito.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@ -57,9 +57,9 @@ public class HttpConnectorTest {
*/
@Test
@Category(HttpURLConnection.class)
public void testOpenConnection() throws IOException, URISyntaxException {
public void testOpenConnection() throws IOException {
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()));
conn.connect();
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.junit.Assert.assertThat;
import static org.shredzone.acme4j.util.TestUtils.isIntArrayContainingInAnyOrder;
import static org.shredzone.acme4j.util.TestUtils.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@ -43,24 +43,24 @@ public class ResourceIteratorTest {
private final int RESOURCES_PER_PAGE = 5;
private final String TYPE = "authorizations";
private List<URI> resourceURIs = new ArrayList<>(PAGES * RESOURCES_PER_PAGE);
private List<URI> pageURIs = new ArrayList<>(PAGES);
private List<URL> resourceURLs = new ArrayList<>(PAGES * RESOURCES_PER_PAGE);
private List<URL> pageURLs = new ArrayList<>(PAGES);
@Before
public void setup() {
resourceURIs.clear();
resourceURLs.clear();
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++) {
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)
public void nullTest() throws IOException {
@ -76,14 +76,14 @@ public class ResourceIteratorTest {
*/
@Test
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()) {
result.add(it.next().getLocation());
}
assertThat(result, is(equalTo(resourceURIs)));
assertThat(result, is(equalTo(resourceURLs)));
}
/**
@ -91,9 +91,9 @@ public class ResourceIteratorTest {
*/
@Test
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));
@ -107,7 +107,7 @@ public class ResourceIteratorTest {
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)
public void removeTest() throws IOException {
Iterator<Authorization> it = createIterator(pageURIs.get(0));
Iterator<Authorization> it = createIterator(pageURLs.get(0));
it.next();
it.remove(); // throws UnsupportedOperationException
}
@ -124,16 +124,16 @@ public class ResourceIteratorTest {
* Creates a new {@link Iterator} of {@link Authorization} objects.
*
* @param first
* URI of the first page
* URL of the first page
* @return Created {@link Iterator}
*/
private Iterator<Authorization> createIterator(URI first) throws IOException {
private Iterator<Authorization> createIterator(URL first) throws IOException {
TestableConnectionProvider provider = new TestableConnectionProvider() {
private int ix;
@Override
public void sendRequest(URI uri, Session session) {
ix = pageURIs.indexOf(uri);
public void sendRequest(URL url, Session session) {
ix = pageURLs.indexOf(url);
assertThat(ix, is(greaterThanOrEqualTo(0)));
}
@ -149,15 +149,15 @@ public class ResourceIteratorTest {
int end = (ix + 1) * RESOURCES_PER_PAGE;
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());
}
@Override
public URI getLink(String relation) {
if ("next".equals(relation) && (ix + 1 < pageURIs.size())) {
return pageURIs.get(ix + 1);
public URL getLink(String relation) {
if ("next".equals(relation) && (ix + 1 < pageURLs.size())) {
return pageURLs.get(ix + 1);
}
return null;
}

View File

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

View File

@ -16,7 +16,9 @@ package org.shredzone.acme4j.exception;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import org.junit.Test;
@ -29,19 +31,19 @@ public class AcmeAgreementRequiredExceptionTest {
* Test that parameters are correctly returned.
*/
@Test
public void testAcmeAgreementRequiredException() {
public void testAcmeAgreementRequiredException() throws MalformedURLException {
String type = "urn:ietf:params:acme:error:agreementRequired";
String detail = "Agreement is required";
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
= new AcmeAgreementRequiredException(type, detail, agreementUri, instanceUri);
= new AcmeAgreementRequiredException(type, detail, agreementUri, instanceUrl);
assertThat(ex.getType(), is(type));
assertThat(ex.getMessage(), is(detail));
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.junit.Assert.assertThat;
import java.net.URI;
import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Test;
@ -26,15 +27,15 @@ import org.junit.Test;
public class AcmeConflictExceptionTest {
@Test
public void testAcmeConflictException() {
public void testAcmeConflictException() throws MalformedURLException {
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
= new AcmeConflictException(msg, locationUri);
= new AcmeConflictException(msg, locationUrl);
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.junit.Assert.assertThat;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
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.
*
* @param uri
* {@link URI} to assert
* @param url
* {@link URL} to assert
*/
protected void assertIsPebbleUri(URI uri) {
assertThat(uri, not(nullValue()));
try {
URL url = uri.toURL();
protected void assertIsPebbleUrl(URL url) {
assertThat(url, not(nullValue()));
assertThat(url.getProtocol(), is("http"));
assertThat(url.getHost(), is(pebbleHost));
assertThat(url.getPort(), is(pebblePort));
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 java.net.URI;
import java.net.URL;
import java.security.KeyPair;
import org.junit.Ignore;
@ -44,11 +45,10 @@ public class RegistrationIT extends AbstractPebbleIT {
rb.agreeToTermsOfService();
Registration reg = rb.create(session);
URI location = reg.getLocation();
assertIsPebbleUri(location);
URL location = reg.getLocation();
assertIsPebbleUrl(location);
URI keyIdentifier = session.getKeyIdentifier();
assertIsPebbleUri(keyIdentifier);
assertThat(keyIdentifier, is(location));
assertThat(keyIdentifier.toString(), is(location.toString()));
// TODO: Not yet supported by Pebble
/*
@ -81,8 +81,8 @@ public class RegistrationIT extends AbstractPebbleIT {
rb.agreeToTermsOfService();
Registration reg = rb.create(session);
URI location = reg.getLocation();
assertIsPebbleUri(location);
URL location = reg.getLocation();
assertIsPebbleUrl(location);
reg.modify().addContact("mailto:acme2@example.com").commit();
@ -104,7 +104,7 @@ public class RegistrationIT extends AbstractPebbleIT {
Session session = new Session(pebbleURI(), keyPair);
Registration reg = new RegistrationBuilder().agreeToTermsOfService().create(session);
URI location = reg.getLocation();
URL location = reg.getLocation();
KeyPair newKeyPair = createKeyPair();
reg.changeKey(newKeyPair);
@ -129,7 +129,7 @@ public class RegistrationIT extends AbstractPebbleIT {
Session session = new Session(pebbleURI(), keyPair);
Registration reg = new RegistrationBuilder().agreeToTermsOfService().create(session);
URI location = reg.getLocation();
URL location = reg.getLocation();
reg.deactivate();

View File

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

View File

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

View File

@ -18,6 +18,7 @@ import static org.junit.Assert.assertThat;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.junit.Test;
@ -47,8 +48,8 @@ public class GenericAcmeProviderTest {
GenericAcmeProvider provider = new GenericAcmeProvider();
URI resolvedUri = provider.resolve(serverUri);
assertThat(resolvedUri, is(equalTo(serverUri)));
URL resolvedUrl = provider.resolve(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.net.URI;
import java.net.URL;
import java.util.HashMap;
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.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.JSONBuilder;
import org.shredzone.acme4j.util.TestUtils;
/**
@ -42,9 +43,9 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP
* @param r
* {@link Resource} to be mapped
* @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);
}
@ -75,7 +76,7 @@ public class TestableConnectionProvider extends DummyConnection implements AcmeP
}
@Override
public URI resolve(URI serverUri) {
public URL resolve(URI serverUri) {
throw new UnsupportedOperationException();
}

View File

@ -15,6 +15,7 @@ package org.shredzone.acme4j.provider.letsencrypt;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.shredzone.acme4j.util.TestUtils.url;
import java.net.URI;
import java.net.URISyntaxException;
@ -52,10 +53,10 @@ public class LetsEncryptAcmeProviderTest {
public void testResolve() throws URISyntaxException {
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(new URI(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/staging")), is(new URI(STAGING_DIRECTORY_URI)));
assertThat(provider.resolve(new URI("acme://letsencrypt.org")), is(url(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(url(V01_DIRECTORY_URI)));
assertThat(provider.resolve(new URI("acme://letsencrypt.org/staging")), is(url(STAGING_DIRECTORY_URI)));
try {
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.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
@ -41,12 +40,12 @@ public class LetsEncryptHttpConnectorTest {
*/
@Test
@Category(HttpURLConnection.class)
public void testCertificate() throws IOException, URISyntaxException {
public void testCertificate() throws IOException {
LetsEncryptHttpConnector connector = new LetsEncryptHttpConnector();
try {
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)));
goodConn.connect();
} catch (SSLHandshakeException ex) {
@ -55,7 +54,7 @@ public class LetsEncryptHttpConnectorTest {
try {
HttpURLConnection badConn = connector.openConnection(
new URI("https://www.google.com"));
new URL("https://www.google.com"));
assertThat(badConn, is(instanceOf(HttpsURLConnection.class)));
badConn.connect();
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.junit.Assert.*;
import static org.shredzone.acme4j.util.TestUtils.url;
import java.net.URI;
import java.net.URISyntaxException;
@ -50,15 +51,15 @@ public class PebbleAcmeProviderTest {
PebbleAcmeProvider provider = new PebbleAcmeProvider();
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/")),
is(new URI("http://localhost:14000/dir")));
is(url("http://localhost:14000/dir")));
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")),
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/")),
is(new URI("http://pebble.example.com:12345/dir")));
is(url("http://pebble.example.com:12345/dir")));
try {
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.junit.Assert.*;
import static org.shredzone.acme4j.util.TestUtils.url;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import java.io.ByteArrayInputStream;
@ -25,7 +26,6 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
@ -183,7 +183,7 @@ public class JSONTest {
* Test all getters on existing values.
*/
@Test
public void testGetter() throws MalformedURLException {
public void testGetter() {
Instant date = LocalDate.of(2016, 1, 8).atStartOfDay(ZoneId.of("UTC")).toInstant();
JSON json = TestUtils.getJsonAsObject("json");
@ -192,7 +192,7 @@ public class JSONTest {
assertThat(json.get("number").asInt(), is(123));
assertThat(json.get("boolean").asBoolean(), is(true));
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("status").asStatusOrElse(Status.INVALID), is(Status.VALID));
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.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
@ -120,6 +122,22 @@ public final class TestUtils {
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.
*

View File

@ -24,7 +24,7 @@ Some CAs provide metadata related to their ACME server. This information can be
```java
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.

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.
```java
URI accountLocationUri = ... // your account's URI
Registration registration = Registration.bind(session, accountLocationUri);
URL accountLocationUrl = ... // your account's URL
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
Registration registration;
@ -45,7 +45,7 @@ try {
registration = new RegistrationBuilder().create(session);
} catch (AcmeConflictException ex) {
// 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());
}
```

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:
* `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.
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.
@ -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.
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
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
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.
@ -84,13 +84,13 @@ To recreate a `Challenge` object at a later time, all you need is to store the o
```java
Challenge originalChallenge = ... // some Challenge instance
URI challengeUri = originalChallenge.getLocation();
URL challengeUrl = originalChallenge.getLocation();
```
Later, you restore the `Challenge` object by invoking `Challenge.bind()`.
```java
URI challengeUri = ... // challenge URI
URL challengeUrl = ... // challenge URL
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);
```
`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.
@ -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:
```java
URI locationUri = ... // location URI from cert.getLocation()
Certificate cert = Certificate.bind(session, locationUri);
URL locationUrl = ... // location URL from cert.getLocation()
Certificate cert = Certificate.bind(session, locationUrl);
```
### 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.
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
RegistrationBuilder builder = new RegistrationBuilder();
@ -11,10 +11,10 @@ builder.agreeToTermsOfService();
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`.
@ -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.
```java
URI agreementUri = ... // TAC link provided by the CA
registration.modify()
.addContact("mailto:acme2@example.com")
.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:
```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