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 + latest true src/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} alias bammbamm - 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.httpcomponents httpclient 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.8 4.5.6 0.6.4 - 2.3.1 1.7.25 utf-8 utf-8