001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2015 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.connector;
015
016import java.net.URL;
017import java.security.KeyPair;
018import java.security.cert.X509Certificate;
019import java.time.Instant;
020import java.time.ZonedDateTime;
021import java.util.Collection;
022import java.util.List;
023import java.util.Optional;
024
025import edu.umd.cs.findbugs.annotations.Nullable;
026import org.shredzone.acme4j.Login;
027import org.shredzone.acme4j.Session;
028import org.shredzone.acme4j.exception.AcmeException;
029import org.shredzone.acme4j.exception.AcmeRetryAfterException;
030import org.shredzone.acme4j.toolbox.JSON;
031import org.shredzone.acme4j.toolbox.JSONBuilder;
032
033/**
034 * Connects to the ACME server and offers different methods for invoking the API.
035 * <p>
036 * The actual way of communicating with the ACME server is intentionally left open.
037 * Implementations could use other means than HTTP, or could mock the communication for
038 * unit testing.
039 */
040public interface Connection extends AutoCloseable {
041
042    /**
043     * Resets the session nonce, by fetching a new one.
044     *
045     * @param session
046     *            {@link Session} instance to fetch a nonce for
047     */
048    void resetNonce(Session session) throws AcmeException;
049
050    /**
051     * Sends a simple GET request.
052     * <p>
053     * If the response code was not HTTP status 200, an {@link AcmeException} matching
054     * the error is raised.
055     *
056     * @param url
057     *            {@link URL} to send the request to.
058     * @param session
059     *            {@link Session} instance to be used for tracking
060     * @param ifModifiedSince
061     *            {@link ZonedDateTime} to be sent as "If-Modified-Since" header, or
062     *            {@code null} if this header is not to be used
063     * @return HTTP status that was returned
064     */
065    int sendRequest(URL url, Session session, @Nullable ZonedDateTime ifModifiedSince)
066            throws AcmeException;
067
068    /**
069     * Sends a signed POST-as-GET request for a certificate resource. Requires a
070     * {@link Login} for the session and {@link KeyPair}. The {@link Login} account
071     * location is sent in a "kid" protected header.
072     * <p>
073     * If the server does not return a 200 class status code, an {@link AcmeException} is
074     * raised matching the error.
075     *
076     * @param url
077     *            {@link URL} to send the request to.
078     * @param login
079     *            {@link Login} instance to be used for signing and tracking.
080     * @return HTTP 200 class status that was returned
081     */
082    int sendCertificateRequest(URL url, Login login) throws AcmeException;
083
084    /**
085     * Sends a signed POST-as-GET request. Requires a {@link Login} for the session and
086     * {@link KeyPair}. The {@link Login} account location is sent in a "kid" protected
087     * header.
088     * <p>
089     * If the server does not return a 200 class status code, an {@link AcmeException} is
090     * raised matching the error.
091     *
092     * @param url
093     *            {@link URL} to send the request to.
094     * @param login
095     *            {@link Login} instance to be used for signing and tracking.
096     * @return HTTP 200 class status that was returned
097     */
098    int sendSignedPostAsGetRequest(URL url, Login login) throws AcmeException;
099
100    /**
101     * Sends a signed POST request. Requires a {@link Login} for the session and
102     * {@link KeyPair}. The {@link Login} account location is sent in a "kid" protected
103     * header.
104     * <p>
105     * If the server does not return a 200 class status code, an {@link AcmeException} is
106     * raised matching the error.
107     *
108     * @param url
109     *            {@link URL} to send the request to.
110     * @param claims
111     *            {@link JSONBuilder} containing claims.
112     * @param login
113     *            {@link Login} instance to be used for signing and tracking.
114     * @return HTTP 200 class status that was returned
115     */
116    int sendSignedRequest(URL url, JSONBuilder claims, Login login) throws AcmeException;
117
118    /**
119     * Sends a signed POST request. Only requires a {@link Session}. The {@link KeyPair}
120     * is sent in a "jwk" protected header field.
121     * <p>
122     * If the server does not return a 200 class status code, an {@link AcmeException} is
123     * raised matching the error.
124     *
125     * @param url
126     *            {@link URL} to send the request to.
127     * @param claims
128     *            {@link JSONBuilder} containing claims.
129     * @param session
130     *            {@link Session} instance to be used for tracking.
131     * @param keypair
132     *            {@link KeyPair} to be used for signing.
133     * @return HTTP 200 class status that was returned
134     */
135    int sendSignedRequest(URL url, JSONBuilder claims, Session session, KeyPair keypair)
136                throws AcmeException;
137
138    /**
139     * Reads a server response as JSON object.
140     *
141     * @return The JSON response.
142     */
143    JSON readJsonResponse() throws AcmeException;
144
145    /**
146     * Reads a certificate and its chain of issuers.
147     *
148     * @return List of X.509 certificate and chain that was read.
149     */
150    List<X509Certificate> readCertificates() throws AcmeException;
151
152    /**
153     * Returns the Retry-After header if present.
154     *
155     * @since 3.0.0
156     */
157    Optional<Instant> getRetryAfter();
158
159    /**
160     * Throws an {@link AcmeRetryAfterException} if the last status was HTTP Accepted and
161     * a Retry-After header was received.
162     *
163     * @param message
164     *            Message to be sent along with the {@link AcmeRetryAfterException}
165     * @deprecated Prefer to use {@link #getRetryAfter()}.
166     */
167    @Deprecated
168    default void handleRetryAfter(String message) throws AcmeException {
169        var retryAfter = getRetryAfter();
170        if (retryAfter.isPresent()) {
171            throw new AcmeRetryAfterException(message, retryAfter.get());
172        }
173    }
174
175    /**
176     * Gets the nonce from the nonce header.
177     *
178     * @return Base64 encoded nonce, or empty if no nonce header was set
179     */
180    Optional<String> getNonce();
181
182    /**
183     * Gets a location from the {@code Location} header.
184     * <p>
185     * Relative links are resolved against the last request's URL.
186     *
187     * @return Location {@link URL}
188     * @throws org.shredzone.acme4j.exception.AcmeProtocolException if the location
189     * header is missing
190     */
191    URL getLocation();
192
193    /**
194     * Returns the content of the last-modified header, if present.
195     *
196     * @return Date in the Last-Modified header, or empty if the server did not provide
197     * this information.
198     * @since 2.10
199     */
200    Optional<ZonedDateTime> getLastModified();
201
202    /**
203     * Returns the expiration date of the resource, if present.
204     *
205     * @return Expiration date, either from the Cache-Control or Expires header. If empty,
206     * the server did not provide an expiration date, or forbid caching.
207     * @since 2.10
208     */
209    Optional<ZonedDateTime> getExpiration();
210
211    /**
212     * Gets one or more relation links from the header. The result is expected to be a
213     * URL.
214     * <p>
215     * Relative links are resolved against the last request's URL.
216     *
217     * @param relation
218     *         Link relation
219     * @return Collection of links. Empty if there was no such relation.
220     */
221    Collection<URL> getLinks(String relation);
222
223    /**
224     * Closes the {@link Connection}, releasing all resources.
225     */
226    @Override
227    void close();
228
229}