001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2017 Richard "Shred" Körber
005 *   http://acme4j.shredzone.org
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
013 */
014package org.shredzone.acme4j.it.pebble;
015
016import static org.assertj.core.api.Assertions.assertThat;
017
018import java.net.URI;
019import java.net.URL;
020import java.security.KeyPair;
021import java.util.ArrayList;
022import java.util.List;
023
024import org.junit.jupiter.api.AfterEach;
025import org.shredzone.acme4j.Authorization;
026import org.shredzone.acme4j.Order;
027import org.shredzone.acme4j.exception.AcmeException;
028import org.shredzone.acme4j.exception.AcmeLazyLoadingException;
029import org.shredzone.acme4j.it.BammBammClient;
030import org.shredzone.acme4j.util.KeyPairUtils;
031
032/**
033 * Superclass for all Pebble related integration tests.
034 * <p>
035 * These tests require a running
036 * <a href="https://github.com/letsencrypt/pebble">Pebble</a> ACME test server at
037 * localhost port 14000. The host and port can be changed via the system property
038 * {@code pebbleHost} and {@code pebblePort} respectively.
039 * <p>
040 * Also, a running pebble-challtestsrv is required to listen on localhost port 8055. The
041 * server's base URL can be changed via the system property {@code bammbammUrl}.
042 */
043public abstract class PebbleITBase {
044    private final String pebbleHost = System.getProperty("pebbleHost", "localhost");
045    private final int pebblePort = Integer.parseInt(System.getProperty("pebblePort", "14000"));
046
047    private final String bammbammUrl = System.getProperty("bammbammUrl", "http://localhost:8055");
048
049    private BammBammClient bammBammClient;
050
051    private final List<CleanupCallback> cleanup = new ArrayList<>();
052
053    @AfterEach
054    public void performCleanup() throws Exception {
055        for (var callback : cleanup) {
056            callback.cleanup();
057        }
058        cleanup.clear();
059    }
060
061    protected void cleanup(CleanupCallback callback) {
062        cleanup.add(callback);
063    }
064
065    /**
066     * @return The {@link URI} of the pebble server to test against.
067     */
068    protected URI pebbleURI() {
069        return URI.create("acme://pebble/" + pebbleHost + ":" + pebblePort);
070    }
071
072    /**
073     * @return {@link BammBammClient} singleton instance.
074     */
075    protected BammBammClient getBammBammClient() {
076        if (bammBammClient == null) {
077            bammBammClient = new BammBammClient(bammbammUrl);
078        }
079        return bammBammClient;
080    }
081
082    /**
083     * Creates a fresh key pair.
084     *
085     * @return Created {@link KeyPair}, guaranteed to be unknown to the Pebble server
086     */
087    protected KeyPair createKeyPair() {
088        return KeyPairUtils.createKeyPair(2048);
089    }
090
091    /**
092     * Asserts that the given {@link URL} is not {@code null} and refers to the Pebble
093     * server.
094     *
095     * @param url
096     *            {@link URL} to assert
097     */
098    protected void assertIsPebbleUrl(URL url) {
099        assertThat(url).isNotNull();
100        assertThat(url.getProtocol()).isEqualTo("https");
101        assertThat(url.getHost()).isEqualTo(pebbleHost);
102        assertThat(url.getPort()).isEqualTo(pebblePort);
103        assertThat(url.getPath()).isNotEmpty();
104    }
105
106    /**
107     * Safely updates the authorization, catching checked exceptions.
108     *
109     * @param auth
110     *            {@link Authorization} to update
111     */
112    protected void updateAuth(Authorization auth) {
113        try {
114            auth.update();
115        } catch (AcmeException ex) {
116            throw new AcmeLazyLoadingException(auth, ex);
117        }
118    }
119
120    /**
121     * Safely updates the order, catching checked exceptions.
122     *
123     * @param order
124     *            {@link Order} to update
125     */
126    protected void updateOrder(Order order) {
127        try {
128            order.update();
129        } catch (AcmeException ex) {
130            throw new AcmeLazyLoadingException(order, ex);
131        }
132    }
133
134    @FunctionalInterface
135    public interface CleanupCallback {
136        void cleanup() throws Exception;
137    }
138
139}