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}