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