diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java
index af9a0001..8ccc27fe 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java
@@ -50,18 +50,6 @@ public class Http01Challenge extends TokenChallenge {
return super.getToken();
}
- /**
- * Returns the authorization string to be used for the response.
- *
- * NOTE: The response file must only contain the returned String (UTF-8
- * or ASCII encoded). There must not be any other leading or trailing characters
- * (like white-spaces or line breaks). Otherwise the challenge will fail.
- */
- @Override
- public String getAuthorization() {
- return super.getAuthorization();
- }
-
@Override
protected boolean acceptable(String type) {
return TYPE.equals(type);
diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java
index f47ae091..ed59bd9b 100644
--- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java
+++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java
@@ -65,7 +65,7 @@ public class TokenChallenge extends Challenge {
* The default is {@code token + '.' + base64url(jwkThumbprint)}. Subclasses may
* override this method if a different algorithm is used.
*/
- protected String getAuthorization() {
+ public String getAuthorization() {
try {
PublicKey pk = getLogin().getKeyPair().getPublic();
PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(pk);
diff --git a/acme4j-it/pom.xml b/acme4j-it/pom.xml
index 3f8f8ccd..67ac280c 100644
--- a/acme4j-it/pom.xml
+++ b/acme4j-it/pom.xml
@@ -29,10 +29,7 @@
acme4j Integration Tests
-
-
- 8u181
- 8.1.12.v20180117
+ latesttruesrc/main/java/org/shredzone/acme4j/**
@@ -119,38 +116,7 @@
pebble
- acme4j/pebble:${project.version}
-
-
- golang:1.11
- true
-
- go get -u -v -d gopkg.in/square/go-jose.v2
- go get -u -v -d github.com/jmhodges/clock
- go get -u -v -d github.com/letsencrypt/pebble || true
- go test github.com/letsencrypt/pebble/...
- go install github.com/letsencrypt/pebble/...
-
-
- 14000
-
-
-
- pebble -strict -dnsserver bammbamm:53 -config /etc/pebble/pebble-config.json
-
-
-
- dir
- /etc/pebble
-
-
- src/test/pebble
- .
-
-
-
-
-
+ letsencrypt/pebble:${pebble.version}alias
@@ -159,6 +125,13 @@
bammbamm
+
+
+ sh
+ -c
+ pebble -strict -dnsserver $(getent hosts bammbamm|cut -d' ' -f1):8053 -config /test/config/pebble-config.json
+
+ Listening
@@ -170,34 +143,22 @@
bammbamm
- acme4j/bammbamm:${project.version}
-
-
- openjdk:${alpn-java.version}-jre-alpine
-
- 53/udp
- 5001
- 5002
- 14001
-
-
-
- java -Xbootclasspath/p:/maven/alpn-boot-${alpn-boot.version}.jar -cp "/maven/*" org.shredzone.acme4j.it.BammBamm
-
-
-
- artifact-with-dependencies
-
-
-
+ letsencrypt/pebble-challtestsrv:${pebble.version}aliasbammbamm
- 14001:14001
+ 8055:8055
+
+
+ sh
+ -c
+ pebble-challtestsrv -defaultIPv6 "" -defaultIPv4 $(getent hosts bammbamm|cut -d' ' -f1)
+
+
- Bammbamm running
+ Starting management server
@@ -219,26 +180,6 @@
${project.version}
-
- org.mortbay.jetty.alpn
- alpn-boot
- ${alpn-boot.version}
-
-
- org.nanohttpd
- nanohttpd
- ${nanohttpd.version}
-
-
- org.nanohttpd
- nanohttpd-nanolets
- ${nanohttpd.version}
-
-
- dnsjava
- dnsjava
- ${dnsjava.version}
- org.apache.httpcomponentshttpclient
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/AbstractResponder.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/AbstractResponder.java
deleted file mode 100644
index c661e0ed..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/AbstractResponder.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2017 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import fi.iki.elonen.NanoHTTPD;
-import fi.iki.elonen.NanoHTTPD.IHTTPSession;
-import fi.iki.elonen.NanoHTTPD.Response;
-import fi.iki.elonen.router.RouterNanoHTTPD.UriResource;
-import fi.iki.elonen.router.RouterNanoHTTPD.UriResponder;
-
-/**
- * A generic responder class for requests.
- */
-@ParametersAreNonnullByDefault
-public abstract class AbstractResponder implements UriResponder {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractResponder.class);
-
- /**
- * Handles the request.
- *
- * @param urlParams
- * Map of decoded URL parameters
- * @param session
- * {@link IHTTPSession} containing the decoding body parameters
- */
- public abstract void handle(Map urlParams, IHTTPSession session)
- throws Exception; //NOSONAR: the request fails on any exception
-
- @Override
- public Response post(UriResource uriResource, Map urlParams, IHTTPSession session) {
- LOG.info("POST " + uriResource);
- try {
- session.parseBody(new HashMap<>());
- handle(urlParams, session);
- return NanoHTTPD.newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "OK");
- } catch (Exception ex) {
- LOG.error("Request failed", ex);
- return NanoHTTPD.newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, ex.toString());
- }
- }
-
- @Override
- public Response get(UriResource uriResource, Map urlParams, IHTTPSession session) {
- LOG.warn("Unsupported " + session.getMethod() + " " + uriResource);
- return NanoHTTPD.newFixedLengthResponse(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "use POST");
- }
-
- @Override
- public Response put(UriResource uriResource, Map urlParams, IHTTPSession session) {
- return get(uriResource, urlParams, session);
- }
-
- @Override
- public Response delete(UriResource uriResource, Map urlParams, IHTTPSession session) {
- return get(uriResource, urlParams, session);
- }
-
- @Override
- public Response other(String method, UriResource uriResource, Map urlParams, IHTTPSession session) {
- return get(uriResource, urlParams, session);
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBamm.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBamm.java
deleted file mode 100644
index 803f6d3c..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBamm.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2017 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.ResourceBundle;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.shredzone.acme4j.it.server.DnsServer;
-import org.shredzone.acme4j.it.server.HttpServer;
-import org.shredzone.acme4j.it.server.TlsAlpnServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import fi.iki.elonen.NanoHTTPD;
-import fi.iki.elonen.router.RouterNanoHTTPD;
-
-/**
- * A mock server to test Pebble. It provides a HTTP server, TLS-ALPN server and DNS
- * server. The servers can be configured remotely via simple HTTP POST requests.
- *
- * WARNING: This is a very simple server that is only meant to be used for
- * integration tests. Do not use in the outside world!
- */
-@ParametersAreNonnullByDefault
-public class BammBamm {
- private static final Logger LOG = LoggerFactory.getLogger(BammBamm.class);
-
- private static final BammBamm INSTANCE = new BammBamm();
-
- private final int appPort;
- private final int httpPort;
- private final int dnsPort;
- private final int tlsAlpnPort;
- private final AppServer appServer;
- private final DnsServer dnsServer;
- private final HttpServer httpServer;
- private final TlsAlpnServer tlsAlpnServer;
-
- private BammBamm() {
- ResourceBundle bundle = ResourceBundle.getBundle("bammbamm");
- appPort = Integer.parseInt(bundle.getString("app.port"));
- dnsPort = Integer.parseInt(bundle.getString("dns.port"));
- httpPort = Integer.parseInt(bundle.getString("http.port"));
- tlsAlpnPort = Integer.parseInt(bundle.getString("tlsAlpn.port"));
-
- dnsServer = new DnsServer();
- httpServer = new HttpServer();
- tlsAlpnServer = new TlsAlpnServer();
- appServer = new AppServer(appPort);
- }
-
- /**
- * Retrieves the singleton instance of {@link BammBamm}.
- *
- * @return {@link BammBamm} singleton instance
- */
- public static BammBamm instance() {
- return INSTANCE;
- }
-
- /**
- * Returns the {@link DnsServer} instance.
- */
- public DnsServer getDnsServer() {
- return dnsServer;
- }
-
- /**
- * Returns the {@link HttpServer} instance.
- */
- public HttpServer getHttpServer() {
- return httpServer;
- }
-
- /**
- * Returns the {@link TlsAlpnServer} instance.
- */
- public TlsAlpnServer getTlsAlpnServer() {
- return tlsAlpnServer;
- }
-
- /**
- * Starts the servers.
- */
- public void start() {
- dnsServer.start(dnsPort);
- httpServer.start(httpPort);
- tlsAlpnServer.start(tlsAlpnPort);
-
- try {
- appServer.start(NanoHTTPD.SOCKET_READ_TIMEOUT, true);
- } catch (IOException ex) {
- throw new UncheckedIOException(ex);
- }
-
- LOG.info("Bammbamm running, listening on port {}", appServer.getListeningPort());
- }
-
- /**
- * Stops the servers.
- */
- public void stop() {
- appServer.stop();
- tlsAlpnServer.stop();
- httpServer.stop();
- dnsServer.stop();
-
- LOG.info("Bammbamm was stopped.");
- }
-
- /**
- * App server with all predefined routes.
- */
- private static class AppServer extends RouterNanoHTTPD {
- public AppServer(int port) {
- super(port);
- super.addMappings();
-
- addRoute(DnsHandler.ADD_A_RECORD, DnsHandler.AddARecord.class);
- addRoute(DnsHandler.REMOVE_A_RECORD, DnsHandler.RemoveARecord.class);
- addRoute(DnsHandler.ADD_TXT_RECORD, DnsHandler.AddTxtRecord.class);
- addRoute(DnsHandler.REMOVE_TXT_RECORD, DnsHandler.RemoveTxtRecord.class);
-
- addRoute(HttpHandler.ADD, HttpHandler.Add.class);
- addRoute(HttpHandler.REMOVE, HttpHandler.Remove.class);
-
- addRoute(TlsAlpnHandler.ADD, TlsAlpnHandler.Add.class);
- addRoute(TlsAlpnHandler.REMOVE, TlsAlpnHandler.Remove.class);
- }
- }
-
- /**
- * Start bammbamm. It runs until the Java process is stopped.
- *
- * @param args
- * Command line arguments
- */
- public static void main(String[] args) {
- BammBamm.instance().start();
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBammClient.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBammClient.java
index af299d8d..c6dba6db 100644
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBammClient.java
+++ b/acme4j-it/src/main/java/org/shredzone/acme4j/it/BammBammClient.java
@@ -14,45 +14,39 @@
package org.shredzone.acme4j.it;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.security.PrivateKey;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.Base64.Encoder;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
-import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
-import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
+import org.shredzone.acme4j.toolbox.JSONBuilder;
/**
- * A BammBamm client.
+ * The BammBamm client connects to the pebble-challtestsrv.
*/
@ParametersAreNonnullByDefault
public class BammBammClient {
+ private static final HttpClient CLIENT = HttpClients.createDefault();
+
private final String baseUrl;
/**
* Creates a new BammBamm client.
*
* @param baseUrl
- * Base URL of the BammBamm server to connect to.
+ * Base URL of the pebble-challtestsrv server to connect to.
*/
public BammBammClient(String baseUrl) {
- this.baseUrl = baseUrl;
+ this.baseUrl = Objects.requireNonNull(baseUrl) + '/';
}
/**
@@ -64,10 +58,10 @@ public class BammBammClient {
* Challenge to respond with
*/
public void httpAddToken(String token, String challenge) throws IOException {
- createRequest(HttpHandler.ADD)
- .arg(":token", token)
- .param("challenge", challenge)
- .submit();
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("token", token);
+ jb.put("content", challenge);
+ sendRequest("add-http01", jb.toString());
}
/**
@@ -77,9 +71,9 @@ public class BammBammClient {
* Token to remove
*/
public void httpRemoveToken(String token) throws IOException {
- createRequest(HttpHandler.REMOVE)
- .arg(":token", token)
- .submit();
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("token", token);
+ sendRequest("del-http01", jb.toString());
}
/**
@@ -93,10 +87,10 @@ public class BammBammClient {
* and the IP will be used.
*/
public void dnsAddARecord(String domain, String ip) throws IOException {
- createRequest(DnsHandler.ADD_A_RECORD)
- .arg(":domain", domain)
- .param("ip", ip)
- .submit();
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("host", domain);
+ jb.array("addresses", Arrays.asList(ip));
+ sendRequest("add-a", jb.toString());
}
/**
@@ -106,9 +100,9 @@ public class BammBammClient {
* Domain to remove the A Record from
*/
public void dnsRemoveARecord(String domain) throws IOException {
- createRequest(DnsHandler.REMOVE_A_RECORD)
- .arg(":domain", domain)
- .submit();
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("host", domain);
+ sendRequest("clear-a", jb.toString());
}
/**
@@ -121,10 +115,10 @@ public class BammBammClient {
* TXT record to add
*/
public void dnsAddTxtRecord(String domain, String txt) throws IOException {
- createRequest(DnsHandler.ADD_TXT_RECORD)
- .arg(":domain", domain)
- .param("txt", txt)
- .submit();
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("host", domain + '.');
+ jb.put("value", txt);
+ sendRequest("set-txt", jb.toString());
}
/**
@@ -134,147 +128,60 @@ public class BammBammClient {
* Domain to remove the TXT Record from
*/
public void dnsRemoveTxtRecord(String domain) throws IOException {
- createRequest(DnsHandler.REMOVE_TXT_RECORD)
- .arg(":domain", domain)
- .submit();
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("host", domain + '.');
+ sendRequest("clear-txt", jb.toString());
}
/**
* Adds a certificate for TLS-ALPN tests.
*
- * @param alias
- * An alias to be used for removal, for example the domain name being
- * validated.
- * @param privateKey
- * {@link PrivateKey} of the certificate
- * @param cert
- * {@link X509Certificate} containing the domain name to respond to
+ * @param domain
+ * Certificate domain to be added
+ * @param keyauth
+ * Key authorization to be used for validation
*/
- public void tlsAlpnAddCertificate(String alias, PrivateKey privateKey, X509Certificate cert) throws IOException {
- try {
- createRequest(TlsAlpnHandler.ADD)
- .arg(":alias", alias)
- .param("privateKey", privateKey.getEncoded())
- .param("cert", cert.getEncoded())
- .submit();
- } catch (CertificateEncodingException ex) {
- throw new IOException(ex);
- }
+ public void tlsAlpnAddCertificate(String domain, String keyauth) throws IOException {
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("host", domain);
+ jb.put("content", keyauth);
+ sendRequest("add-tlsalpn01", jb.toString());
}
/**
* Removes a certificate.
*
- * @param alias
- * Certificate alias to remove
+ * @param domain
+ * Certificate domain to be removed
*/
- public void tlsAlpnRemoveCertificate(String alias) throws IOException {
- createRequest(TlsAlpnHandler.REMOVE)
- .arg(":alias", alias)
- .submit();
+ public void tlsAlpnRemoveCertificate(String domain) throws IOException {
+ JSONBuilder jb = new JSONBuilder();
+ jb.put("host", domain);
+ sendRequest("del-tlsalpn01", jb.toString());
}
/**
- * Creates a new {@link Request} object.
+ * Sends a request to the pebble-challtestsrv.
*
* @param call
- * Path to be called
- * @return Created {@link Request} object
+ * Endpoint to be called
+ * @param body
+ * JSON body
*/
- private Request createRequest(String call) {
- return new Request(baseUrl, call);
- }
+ private void sendRequest(String call, String body) throws IOException {
+ try {
+ HttpPost httppost = new HttpPost(baseUrl + call);
+ httppost.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON));
- /**
- * This class helps to assemble and invoke a HTTP POST request.
- */
- @ParametersAreNonnullByDefault
- private static class Request {
- private static final HttpClient CLIENT = HttpClients.createDefault();
- private static final Encoder BASE64 = Base64.getEncoder();
- private static final Charset UTF8 = Charset.forName("utf-8");
+ HttpResponse response = CLIENT.execute(httppost);
- private final List params = new ArrayList<>();
- private final String baseUrl;
- private String call;
+ EntityUtils.consume(response.getEntity());
- /**
- * Creates a new {@link Request}.
- *
- * @param baseUrl
- * Base URL of the server to invoke
- * @param call
- * Path to invoke. It may contain placeholders.
- */
- public Request(String baseUrl, String call) {
- this.baseUrl = baseUrl;
- this.call = call;
- }
-
- /**
- * Sets a path parameter.
- *
- * @param key
- * Placeholder to change, leading ':' inclusive!
- * @param value
- * Value of the parameter
- * @return itself
- */
- public Request arg(String key, String value) {
- try {
- call = call.replace(key, URLEncoder.encode(value, UTF8.name()));
- } catch (UnsupportedEncodingException ex) {
- throw new InternalError("utf-8 missing", ex);
- }
- return this;
- }
-
- /**
- * Adds a form parameter. It will be sent in the request body.
- *
- * @param key
- * Parameter name
- * @param value
- * Parameter value
- * @return itself
- */
- public Request param(String key, String value) {
- params.add(new BasicNameValuePair(key, value));
- return this;
- }
-
- /**
- * Adds a binary form parameter. It will be sent in the request body.
- *
- * @param key
- * Parameter name
- * @param value
- * Parameter value. It will be Base64 encoded.
- * @return itself
- */
- public Request param(String key, byte[] value) {
- return param(key, BASE64.encodeToString(value));
- }
-
- /**
- * Submits the POST request.
- */
- public void submit() throws IOException {
- try {
- HttpPost httppost = new HttpPost(baseUrl + call);
- if (!params.isEmpty()) {
- httppost.setEntity(new UrlEncodedFormEntity(params, UTF8));
- }
- HttpResponse response = CLIENT.execute(httppost);
-
- EntityUtils.consume(response.getEntity());
-
- if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
- throw new IOException(response.getStatusLine().getReasonPhrase());
- }
- } catch (ClientProtocolException ex) {
- throw new IOException(ex);
+ if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ throw new IOException(response.getStatusLine().getReasonPhrase());
}
+ } catch (ClientProtocolException ex) {
+ throw new IOException(ex);
}
}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/DnsHandler.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/DnsHandler.java
deleted file mode 100644
index 6e68c630..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/DnsHandler.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2017 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it;
-
-import java.net.InetAddress;
-import java.util.Map;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.shredzone.acme4j.it.server.DnsServer;
-
-import fi.iki.elonen.NanoHTTPD.IHTTPSession;
-
-/**
- * Request handler for all {@code dns-01} related requests.
- */
-@ParametersAreNonnullByDefault
-public final class DnsHandler {
-
- public static final String ADD_A_RECORD = "/dns/add/a/:domain";
- public static final String REMOVE_A_RECORD = "/dns/remove/a/:domain";
- public static final String ADD_TXT_RECORD = "/dns/add/txt/:domain";
- public static final String REMOVE_TXT_RECORD = "/dns/remove/txt/:domain";
-
- private DnsHandler() {
- // this class cannot be instanciated.
- }
-
- /**
- * Adds an A Record.
- */
- @ParametersAreNonnullByDefault
- public static class AddARecord extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String domain = urlParams.get("domain");
- String ip = session.getParameters().get("ip").get(0);
-
- DnsServer server = BammBamm.instance().getDnsServer();
- server.addARecord(domain, InetAddress.getByName(ip));
- }
- }
-
- /**
- * Removes an A Record.
- */
- @ParametersAreNonnullByDefault
- public static class RemoveARecord extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String domain = urlParams.get("domain");
-
- DnsServer server = BammBamm.instance().getDnsServer();
- server.removeARecord(domain);
- }
- }
-
- /**
- * Adds a TXT Record.
- */
- @ParametersAreNonnullByDefault
- public static class AddTxtRecord extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String domain = urlParams.get("domain");
- String txt = session.getParameters().get("txt").get(0);
-
- DnsServer server = BammBamm.instance().getDnsServer();
- server.addTxtRecord(domain, txt);
- }
- }
-
- /**
- * Removes a TXT Record.
- */
- @ParametersAreNonnullByDefault
- public static class RemoveTxtRecord extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String domain = urlParams.get("domain");
-
- DnsServer server = BammBamm.instance().getDnsServer();
- server.removeTxtRecord(domain);
- }
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/HttpHandler.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/HttpHandler.java
deleted file mode 100644
index 2d672838..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/HttpHandler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2017 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it;
-
-import java.util.Map;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.shredzone.acme4j.it.server.HttpServer;
-
-import fi.iki.elonen.NanoHTTPD.IHTTPSession;
-
-/**
- * Request handler for all {@code http-01} related requests.
- */
-@ParametersAreNonnullByDefault
-public final class HttpHandler {
-
- public static final String ADD = "/http/add/:token";
- public static final String REMOVE = "/http/remove/:token";
-
- private HttpHandler() {
- // this class cannot be instanciated.
- }
-
- /**
- * Adds a HTTP challenge.
- */
- @ParametersAreNonnullByDefault
- public static class Add extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String token = urlParams.get("token");
- String challenge = session.getParameters().get("challenge").get(0);
-
- HttpServer server = BammBamm.instance().getHttpServer();
- server.addToken(token, challenge);
- }
- }
-
- /**
- * Removes a HTTP challenge.
- */
- @ParametersAreNonnullByDefault
- public static class Remove extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String token = urlParams.get("token");
-
- HttpServer server = BammBamm.instance().getHttpServer();
- server.removeToken(token);
- }
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/TlsAlpnHandler.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/TlsAlpnHandler.java
deleted file mode 100644
index 3f298a84..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/TlsAlpnHandler.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2018 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it;
-
-import java.io.ByteArrayInputStream;
-import java.security.KeyFactory;
-import java.security.PrivateKey;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.util.Base64;
-import java.util.Base64.Decoder;
-import java.util.Map;
-
-import org.shredzone.acme4j.it.server.TlsAlpnServer;
-
-import fi.iki.elonen.NanoHTTPD.IHTTPSession;
-
-/**
- * Request handler for all {@code tls-alpn-01} related requests.
- */
-public final class TlsAlpnHandler {
-
- public static final String ADD = "/tlsalpn/add/:alias";
- public static final String REMOVE = "/tlsalpn/remove/:alias";
-
- private TlsAlpnHandler() {
- // this class cannot be instanciated.
- }
-
- /**
- * Adds an TLS-ALPN certificate.
- */
- public static class Add extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String alias = urlParams.get("alias");
- String privateKeyEncoded = session.getParameters().get("privateKey").get(0);
- String certEncoded = session.getParameters().get("cert").get(0);
-
- Decoder base64 = Base64.getDecoder();
-
- KeyFactory kf = KeyFactory.getInstance("RSA");
- PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(
- base64.decode(privateKeyEncoded)));
-
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- X509Certificate cert = (X509Certificate) cf.generateCertificate(
- new ByteArrayInputStream(base64.decode(certEncoded)));
-
- TlsAlpnServer server = BammBamm.instance().getTlsAlpnServer();
- server.addCertificate(alias, privateKey, cert);
- }
- }
-
- /**
- * Removes an TLS-ALPN certificate.
- */
- public static class Remove extends AbstractResponder {
- @Override
- public void handle(Map urlParams, IHTTPSession session) throws Exception {
- String alias = urlParams.get("alias");
-
- TlsAlpnServer server = BammBamm.instance().getTlsAlpnServer();
- server.removeCertificate(alias);
- }
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/DnsServer.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/DnsServer.java
deleted file mode 100644
index 8a877438..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/DnsServer.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2017 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it.server;
-
-import static java.util.Collections.synchronizedMap;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xbill.DNS.ARecord;
-import org.xbill.DNS.DClass;
-import org.xbill.DNS.Flags;
-import org.xbill.DNS.Header;
-import org.xbill.DNS.Message;
-import org.xbill.DNS.Name;
-import org.xbill.DNS.Rcode;
-import org.xbill.DNS.Record;
-import org.xbill.DNS.Section;
-import org.xbill.DNS.TXTRecord;
-import org.xbill.DNS.Type;
-
-/**
- * A very simple and very stupid DNS server. It just responds to TXT and A queries of the
- * given domains, and refuses to answer anything else.
- *
- * This server can be used to validate {@code dns-01} challenges, and to direct other
- * challenges to the mock servers.
- */
-@ParametersAreNonnullByDefault
-public class DnsServer {
- private static final Logger LOG = LoggerFactory.getLogger(DnsServer.class);
- private static final int UDP_SIZE = 512;
- private static final long TTL = 300L;
-
- private final Map txtRecords = synchronizedMap(new HashMap<>());
- private final Map aRecords = synchronizedMap(new HashMap<>());
- private Thread thread = null;
- private volatile boolean running = false;
- private volatile boolean listening = false;
-
- /**
- * Adds a TXT record to the DNS server. If the domain already has a TXT record
- * attached, it will be replaced.
- *
- * @param domain
- * Domain to attach the TXT record to
- * @param txt
- * TXT record to attach
- */
- public void addTxtRecord(String domain, String txt) {
- txtRecords.put(domain.replaceAll("\\.$", ""), txt);
- }
-
- /**
- * Removes a TXT record from the domain.
- *
- * @param domain
- * Domain to remove the TXT record from
- */
- public void removeTxtRecord(String domain) {
- txtRecords.remove(domain);
- }
-
- /**
- * Adds an A record to the DNS server. If the domain already has an A record attached,
- * it will be replaced.
- *
- * @param domain
- * Domain to attach the A record to
- * @param ip
- * Target IP address
- */
- public void addARecord(String domain, InetAddress ip) {
- if (!(ip instanceof Inet4Address)) {
- throw new IllegalArgumentException("must be an IPv4 address");
- }
- aRecords.put(domain.replaceAll("\\.$", ""), ip);
- }
-
- /**
- * Removes an A record from the domain.
- *
- * @param domain
- * Domain to remove the A record from
- */
- public void removeARecord(String domain) {
- aRecords.remove(domain);
- }
-
- /**
- * Starts the DNS server.
- *
- * @param port
- * Port to listen to
- */
- public void start(int port) {
- if (thread != null) {
- throw new IllegalStateException("Server is already running");
- }
-
- running = true;
- thread = new Thread(() -> serveUDP(port));
- thread.setName("DNS server");
- thread.start();
- LOG.info("dns-01 server listening at port {}", port);
- }
-
- /**
- * Stops the DNS server.
- */
- public void stop() {
- if (thread != null) {
- running = false;
- thread.interrupt();
- thread = null;
- }
- }
-
- /**
- * Checks if the server was started up and is listening to connections.
- */
- public boolean isListening() {
- return listening;
- }
-
- /**
- * Opens an UDP socket and processes incoming messages.
- *
- * @param port
- * Port to listen at
- */
- private void serveUDP(int port) {
- try (DatagramSocket sock = new DatagramSocket(port)) {
- listening = true;
- while (running) {
- process(sock);
- }
- listening = false;
- } catch (IOException ex) {
- LOG.error("Failed to open UDP socket", ex);
- }
- }
-
- /**
- * Processes a DNS query.
- *
- * @param sock
- * Socket to listen to
- */
- private void process(DatagramSocket sock) {
- try {
- byte[] in = new byte[UDP_SIZE];
-
- // Read the question
- DatagramPacket indp = new DatagramPacket(in, UDP_SIZE);
- indp.setLength(UDP_SIZE);
- sock.receive(indp);
- Message msg = new Message(in);
- Header header = msg.getHeader();
-
- Record question = msg.getQuestion();
-
- // Prepare a response
- Message response = new Message(header.getID());
- response.getHeader().setFlag(Flags.QR);
- response.addRecord(question, Section.QUESTION);
-
- Name name = question.getName();
- boolean hasRecords = false;
-
- String txt = txtRecords.get(name.toString(true));
- if (question.getType() == Type.TXT && txt != null) {
- response.addRecord(new TXTRecord(name, DClass.IN, TTL, txt), Section.ANSWER);
- hasRecords = true;
- LOG.info("dns-01: {} {} IN TXT \"{}\"", name, TTL, txt);
- }
-
- InetAddress a = aRecords.get(name.toString(true));
- if (question.getType() == Type.A && a != null) {
- response.addRecord(new ARecord(name, DClass.IN, TTL, a), Section.ANSWER);
- hasRecords = true;
- LOG.info("dns-01: {} {} IN A {}", name, TTL, a.getHostAddress());
- }
-
- if (!hasRecords) {
- response.getHeader().setRcode(Rcode.NXDOMAIN);
- LOG.warn("dns-01: Cannot answer: {}", question);
- }
-
- // Send the response
- byte[] resp = response.toWire();
- DatagramPacket outdp = new DatagramPacket(resp, resp.length, indp.getAddress(), indp.getPort());
- sock.send(outdp);
- } catch (Exception ex) {
- LOG.error("Failed to process query", ex);
- }
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/HttpServer.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/HttpServer.java
deleted file mode 100644
index 4302f2e0..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/HttpServer.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2017 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it.server;
-
-import static java.util.Collections.synchronizedMap;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import fi.iki.elonen.NanoHTTPD;
-import fi.iki.elonen.NanoHTTPD.Response.Status;
-
-/**
- * A very simple web server that will answer at the {@code .well-known/acme-challenge}
- * path, returning the challenge to the given token.
- *
- * This server can be used to validate {@code http-01} challenges.
- */
-@ParametersAreNonnullByDefault
-public class HttpServer {
- private static final Logger LOG = LoggerFactory.getLogger(HttpServer.class);
-
- private static final String TOKEN_PATH = "/.well-known/acme-challenge/";
- private static final Pattern TOKEN_PATTERN = Pattern.compile("^" + Pattern.quote(TOKEN_PATH) + "([^/]+)$");
- private static final String TYPE_TEXT_PLAIN = "text/plain";
-
- private final Map tokenMap = synchronizedMap(new HashMap<>());
- private NanoHTTPD server;
-
- /**
- * Adds a token to the server's well-known challenges. If the token was already set,
- * the challenge will be replaced.
- *
- * @param token
- * Token the server will respond to
- * @param challenge
- * Challenge the server will respond with
- */
- public void addToken(String token, String challenge) {
- tokenMap.put(token, challenge);
- }
-
- /**
- * Removes a token from the server's well-known challenges.
- *
- * @param token
- * Token to remove
- */
- public void removeToken(String token) {
- tokenMap.remove(token);
- }
-
- /**
- * Starts the HTTP server.
- *
- * @param port
- * Port to listen at
- */
- public void start(int port) {
- if (server != null) {
- throw new IllegalStateException("Server is already running");
- }
-
- server = new NanoHTTPD(port) {
- @Override
- public Response serve(IHTTPSession session) {
- String path = session.getUri().replaceAll("//+", "/");
-
- Matcher m = TOKEN_PATTERN.matcher(path);
- if (!m.matches()) {
- return newFixedLengthResponse(Status.NOT_FOUND, TYPE_TEXT_PLAIN, "not found: "+ path + "\n");
- }
-
- String token = m.group(1);
- String content = tokenMap.get(token);
-
- if (content == null) {
- LOG.warn("http-01: unknown token " + token);
- return newFixedLengthResponse(Status.NOT_FOUND, TYPE_TEXT_PLAIN, "unknown token: "+ token + "\n");
- }
-
- LOG.info("http-01: " + token + " -> " + content);
- return newFixedLengthResponse(Status.OK, TYPE_TEXT_PLAIN, content);
- }
- };
-
- try {
- server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
- LOG.info("http-01 server listening at port {}", port);
- } catch (IOException ex) {
- LOG.error("Failed to start http-01 server", ex);
- server = null;
- throw new UncheckedIOException(ex);
- }
- }
-
- /**
- * Stops the HTTP server.
- */
- public void stop() {
- if (server != null) {
- server.stop();
- server = null;
- }
- }
-
- /**
- * Checks if the server was started up and is listening to connections.
- */
- public boolean isListening() {
- return server != null && server.wasStarted();
- }
-
-}
diff --git a/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/TlsAlpnServer.java b/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/TlsAlpnServer.java
deleted file mode 100644
index c08d8b09..00000000
--- a/acme4j-it/src/main/java/org/shredzone/acme4j/it/server/TlsAlpnServer.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * acme4j - Java ACME client
- *
- * Copyright (C) 2018 Richard "Shred" Körber
- * http://acme4j.shredzone.org
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-package org.shredzone.acme4j.it.server;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.eclipse.jetty.alpn.ALPN;
-import org.shredzone.acme4j.challenge.TlsAlpn01Challenge;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A very simple TLS-ALPN server. It waits for a connection and performs a TLS handshake
- * returning the matching certificate to the requested domain.
- *
- * This server can be used to validate {@code tls-alpn-01} challenges.
- */
-public class TlsAlpnServer {
- private static final Logger LOG = LoggerFactory.getLogger(TlsAlpnServer.class);
- private static final char[] PASSWORD = "shibboleet".toCharArray();
-
- private KeyStore keyStore = null;
- private Thread thread = null;
- private volatile boolean running = false;
- private volatile boolean listening = false;
-
- /**
- * Adds a certificate to the set of known certificates.
- *
- * The certificate's SAN is used for SNI.
- *
- * @param alias
- * Internal alias
- * @param privateKey
- * Private key to be used with this certificate
- * @param cert
- * {@link X509Certificate} to be added
- */
- public void addCertificate(String alias, PrivateKey privateKey, X509Certificate cert) {
- initKeyStore();
-
- try {
- keyStore.setKeyEntry(alias, privateKey, PASSWORD, new Certificate[] {cert});
- } catch (KeyStoreException ex) {
- throw new IllegalArgumentException("Failed to add certificate " + alias, ex);
- }
- }
-
- /**
- * Removes a certificate.
- *
- * @param alias
- * Internal alias of the certificate to remove
- */
- public void removeCertificate(String alias) {
- initKeyStore();
-
- try {
- keyStore.deleteEntry(alias);
- } catch (KeyStoreException ex) {
- throw new IllegalArgumentException("Failed to remove certificate " + alias, ex);
- }
- }
-
- /**
- * Starts the TlsAlpn server.
- *
- * @param port
- * Port to listen to
- */
- public void start(int port) {
- if (thread != null) {
- throw new IllegalStateException("Server is already running");
- }
-
- running = true;
- thread = new Thread(() -> serve(port));
- thread.setName("tls-alpn server");
- thread.start();
- LOG.info("tls-alpn server listening at port {}", port);
- }
-
- /**
- * Stops the TlsAlpn server.
- */
- public void stop() {
- if (thread != null) {
- running = false;
- thread.interrupt();
- thread = null;
- }
- }
-
- /**
- * Checks if the server was started up and is listening to connections.
- */
- public boolean isListening() {
- return listening;
- }
-
- /**
- * Opens an SSL server socket and processes incoming requests.
- *
- * @param port
- * Port to listen at
- */
- private void serve(int port) {
- SSLContext sslContext = createSSLContext();
- SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
-
- try (SSLServerSocket sslServerSocket = (SSLServerSocket)
- sslServerSocketFactory.createServerSocket(port)){
- listening = true;
- while (running) {
- process(sslServerSocket);
- }
- } catch (IOException ex) {
- LOG.error("Failed to create socket on port {}", port, ex);
- }
-
- listening = false;
- }
-
- /**
- * Accept and process an incoming request. Only the TLS handshake is used here.
- * Incoming data is just consumed, and the socket is closed after that.
- *
- * @param sslServerSocket
- * {@link SSLServerSocket} to accept connections from
- */
- private void process(SSLServerSocket sslServerSocket) {
- try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept()) {
- ALPN.put(sslSocket, new ALPN.ServerProvider() {
- @Override
- public void unsupported() {
- ALPN.remove(sslSocket);
- }
-
- @Override
- public String select(List protocols) {
- ALPN.remove(sslSocket);
- if (protocols.contains(TlsAlpn01Challenge.ACME_TLS_1_PROTOCOL)) {
- return TlsAlpn01Challenge.ACME_TLS_1_PROTOCOL;
- } else {
- return null;
- }
- }
- });
-
- sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
- sslSocket.startHandshake();
-
- SSLSession sslSession = sslSocket.getSession();
- X509Certificate cert = (X509Certificate) sslSession.getLocalCertificates()[0];
- LOG.info("tls-alpn: {}", domainsToString(cert));
-
- try (InputStream in = sslSocket.getInputStream()) {
- while (in.read() >= 0); //NOSONAR: intentional empty statement
- }
- } catch (Exception ex) {
- LOG.error("Failed to process request", ex);
- }
- }
-
- /**
- * Lazily initializes the {@link KeyStore} instance to be used. The key store is empty
- * after initialization.
- */
- private void initKeyStore() {
- if (keyStore == null) {
- try {
- keyStore = KeyStore.getInstance("JKS");
- keyStore.load(null, null);
- } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
- | IOException ex) {
- throw new IllegalStateException("Failed to create key store", ex);
- }
- }
- }
-
- /**
- * Creates a {@link SSLContext} that uses the internal {@link KeyStore} for key and
- * trust management.
- *
- * @return {@link SSLContext} instance
- */
- private SSLContext createSSLContext() {
- initKeyStore();
-
- try {
- KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("NewSunX509");
- keyManagerFactory.init(keyStore, PASSWORD);
- KeyManager[] km = keyManagerFactory.getKeyManagers();
-
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
- trustManagerFactory.init(keyStore);
- TrustManager[] tm = trustManagerFactory.getTrustManagers();
-
- SSLContext sslContext = SSLContext.getInstance("TLSv1");
- sslContext.init(km, tm, null);
-
- return sslContext;
- } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException
- | UnrecoverableKeyException ex) {
- throw new IllegalStateException("Could not create SSLContext", ex);
- }
- }
-
- /**
- * Extracts all SANs of the given certificate and returns them as a string.
- *
- * @param cert
- * {@link X509Certificate} to read the SANs from
- * @return String of all SAN names joined together and separated by comma
- */
- private String domainsToString(X509Certificate cert) {
- try {
- return cert.getSubjectAlternativeNames().stream()
- .filter(c -> ((Number) c.get(0)).intValue() == GeneralName.dNSName)
- .map(c -> (String) c.get(1))
- .collect(Collectors.joining(", "));
- } catch (CertificateParsingException ex) {
- throw new IllegalArgumentException("bad certificate", ex);
- }
- }
-
-}
diff --git a/acme4j-it/src/main/resources/bammbamm.properties b/acme4j-it/src/main/resources/bammbamm.properties
deleted file mode 100644
index 1473fd6f..00000000
--- a/acme4j-it/src/main/resources/bammbamm.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-
-# Port where BammBamm is listening for new connections
-app.port = 14001
-
-# DNS server port
-dns.port = 53
-
-# HTTP server port
-http.port = 5002
-
-# TLS-ALPN server port
-tlsAlpn.port = 5001
diff --git a/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/OrderIT.java b/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/OrderIT.java
index dd24573e..3c6bc375 100644
--- a/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/OrderIT.java
+++ b/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/OrderIT.java
@@ -43,7 +43,6 @@ import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeServerException;
import org.shredzone.acme4j.it.BammBammClient;
import org.shredzone.acme4j.util.CSRBuilder;
-import org.shredzone.acme4j.util.CertificateUtils;
/**
* Tests a complete certificate order with different challenges.
@@ -63,10 +62,8 @@ public class OrderIT extends PebbleITBase {
Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE);
assertThat(challenge, is(notNullValue()));
- client.dnsAddARecord(TEST_DOMAIN, getBammBammHostname());
client.httpAddToken(challenge.getToken(), challenge.getAuthorization());
- cleanup(() -> client.dnsRemoveARecord(TEST_DOMAIN));
cleanup(() -> client.httpRemoveToken(challenge.getToken()));
return challenge;
@@ -105,20 +102,10 @@ public class OrderIT extends PebbleITBase {
TlsAlpn01Challenge challenge = auth.findChallenge(TlsAlpn01Challenge.TYPE);
assertThat(challenge, is(notNullValue()));
- KeyPair challengeKey = createKeyPair();
-
- X509Certificate cert = CertificateUtils.createTlsAlpn01Certificate(
- challengeKey,
- auth.getIdentifier().getDomain(),
- challenge.getAcmeValidation());
-
- client.dnsAddARecord(TEST_DOMAIN, getBammBammHostname());
client.tlsAlpnAddCertificate(
auth.getIdentifier().getDomain(),
- challengeKey.getPrivate(),
- cert);
+ challenge.getAuthorization());
- cleanup(() -> client.dnsRemoveARecord(TEST_DOMAIN));
cleanup(() -> client.tlsAlpnRemoveCertificate(auth.getIdentifier().getDomain()));
return challenge;
@@ -136,10 +123,8 @@ public class OrderIT extends PebbleITBase {
Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE);
assertThat(challenge, is(notNullValue()));
- client.dnsAddARecord(TEST_DOMAIN, getBammBammHostname());
client.httpAddToken(challenge.getToken(), challenge.getAuthorization());
- cleanup(() -> client.dnsRemoveARecord(TEST_DOMAIN));
cleanup(() -> client.httpRemoveToken(challenge.getToken()));
return challenge;
diff --git a/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/PebbleITBase.java b/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/PebbleITBase.java
index b904ad4b..d2caf5ce 100644
--- a/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/PebbleITBase.java
+++ b/acme4j-it/src/test/java/org/shredzone/acme4j/it/pebble/PebbleITBase.java
@@ -37,13 +37,15 @@ import org.shredzone.acme4j.util.KeyPairUtils;
* Pebble ACME test server at
* localhost port 14000. The host and port can be changed via the system property
* {@code pebbleHost} and {@code pebblePort} respectively.
+ *
+ * Also, a running pebble-challtestsrv is required to listen on localhost port 8055. The
+ * server's base URL can be changed via the system property {@code bammbammUrl}.
*/
public abstract class PebbleITBase {
private final String pebbleHost = System.getProperty("pebbleHost", "localhost");
private final int pebblePort = Integer.parseInt(System.getProperty("pebblePort", "14000"));
- private final String bammbammUrl = System.getProperty("bammbammUrl", "http://localhost:14001");
- private final String bammbammHostname = System.getProperty("bammbammHostname", "bammbamm");
+ private final String bammbammUrl = System.getProperty("bammbammUrl", "http://localhost:8055");
private BammBammClient bammBammClient;
@@ -78,13 +80,6 @@ public abstract class PebbleITBase {
return bammBammClient;
}
- /**
- * @return Hostname or IP address of the BammBamm server.
- */
- protected String getBammBammHostname() {
- return bammbammHostname;
- }
-
/**
* Creates a fresh key pair.
*
diff --git a/acme4j-it/src/test/pebble/pebble-config.json b/acme4j-it/src/test/pebble/pebble-config.json
deleted file mode 100644
index a2d7f7b6..00000000
--- a/acme4j-it/src/test/pebble/pebble-config.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "pebble": {
- "listenAddress": "0.0.0.0:14000",
- "certificate": "/go/src/github.com/letsencrypt/pebble/test/certs/localhost/cert.pem",
- "privateKey": "/go/src/github.com/letsencrypt/pebble/test/certs/localhost/key.pem",
- "httpPort": 5002,
- "tlsPort": 5001
- }
-}
diff --git a/pom.xml b/pom.xml
index 344b18f8..95b424ae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,10 +52,8 @@
1.60
- 2.1.84.5.60.6.4
- 2.3.11.7.25utf-8utf-8