diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java index 058715cf..d340dacb 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java @@ -71,7 +71,7 @@ public class Certificate extends AcmeResource { if (certChain == null) { LOG.debug("download"); try (Connection conn = connect()) { - conn.sendRequest(getLocation(), getSession()); + conn.sendCertificateRequest(getLocation(), getSession()); alternates = new ArrayList<>(conn.getLinks("alternate")); certChain = new ArrayList<>(conn.readCertificates()); } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java index 2d53bb96..092e56d9 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java @@ -57,6 +57,19 @@ public interface Connection extends AutoCloseable { */ void sendRequest(URL url, Session session) throws AcmeException; + /** + * Sends a request for a certificate resource. + *
+ * If the response code was not {@link HttpURLConnection#HTTP_OK}, an + * {@link AcmeException} matching the error is raised. + * + * @param url + * {@link URL} to send the request to. + * @param session + * {@link Session} instance to be used for tracking + */ + void sendCertificateRequest(URL url, Session session) throws AcmeException; + /** * Sends a signed POST request. Requires a {@link Login} for the session and * {@link KeyPair}. The {@link Login} account location is sent in a "kid" protected diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java index fce470ef..ee5900dd 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java @@ -78,6 +78,9 @@ public class DefaultConnection implements Connection { private static final String REPLAY_NONCE_HEADER = "Replay-Nonce"; private static final String RETRY_AFTER_HEADER = "Retry-After"; private static final String DEFAULT_CHARSET = "utf-8"; + private static final String MIME_JSON = "application/json"; + private static final String MIME_JSON_PROBLEM = "application/problem+json"; + private static final String MIME_CERTIFICATE_CHAIN = "application/pem-certificate-chain"; private static final Pattern BASE64URL_PATTERN = Pattern.compile("[0-9A-Za-z_-]+"); @@ -134,6 +137,15 @@ public class DefaultConnection implements Connection { @Override public void sendRequest(URL url, Session session) throws AcmeException { + sendRequest(url, session, MIME_JSON); + } + + @Override + public void sendCertificateRequest(URL url, Session session) throws AcmeException { + sendRequest(url, session, MIME_CERTIFICATE_CHAIN); + } + + private void sendRequest(URL url, Session session, String accept) throws AcmeException { Objects.requireNonNull(url, "url"); Objects.requireNonNull(session, "session"); assertConnectionIsClosed(); @@ -143,6 +155,7 @@ public class DefaultConnection implements Connection { try { conn = httpConnector.openConnection(url, session.getProxy()); conn.setRequestMethod("GET"); + conn.setRequestProperty(ACCEPT_HEADER, accept); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.setDoOutput(false); @@ -207,8 +220,7 @@ public class DefaultConnection implements Connection { } String contentType = AcmeUtils.getContentType(conn.getHeaderField(CONTENT_TYPE_HEADER)); - if (!("application/json".equals(contentType) - || "application/problem+json".equals(contentType))) { + if (!(MIME_JSON.equals(contentType) || MIME_JSON_PROBLEM.equals(contentType))) { throw new AcmeProtocolException("Unexpected content type: " + contentType); } @@ -233,7 +245,7 @@ public class DefaultConnection implements Connection { assertConnectionIsOpen(); String contentType = AcmeUtils.getContentType(conn.getHeaderField(CONTENT_TYPE_HEADER)); - if (!("application/pem-certificate-chain".equals(contentType))) { + if (!(MIME_CERTIFICATE_CHAIN.equals(contentType))) { throw new AcmeProtocolException("Unexpected content type: " + contentType); } @@ -330,7 +342,7 @@ public class DefaultConnection implements Connection { conn = httpConnector.openConnection(url, session.getProxy()); conn.setRequestMethod("POST"); - conn.setRequestProperty(ACCEPT_HEADER, "application/json"); + conn.setRequestProperty(ACCEPT_HEADER, MIME_JSON); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.setRequestProperty(CONTENT_TYPE_HEADER, "application/jose+json"); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java index eb2c0144..44221e8b 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java @@ -55,7 +55,7 @@ public class CertificateTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public void sendCertificateRequest(URL url, Session session) { assertThat(url, is(locationUrl)); assertThat(session, is(notNullValue())); } @@ -124,7 +124,7 @@ public class CertificateTest { private boolean certRequested = false; @Override - public void sendRequest(URL url, Session session) { + public void sendCertificateRequest(URL url, Session session) { assertThat(url, is(locationUrl)); assertThat(session, is(notNullValue())); certRequested = true; @@ -171,7 +171,7 @@ public class CertificateTest { private boolean certRequested = false; @Override - public void sendRequest(URL url, Session session) { + public void sendCertificateRequest(URL url, Session session) { assertThat(url, is(locationUrl)); assertThat(session, is(notNullValue())); certRequested = true; diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java index 5ae7595a..55dea37b 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java @@ -653,6 +653,29 @@ public class DefaultConnectionTest { } verify(mockUrlConnection).setRequestMethod("GET"); + verify(mockUrlConnection).setRequestProperty("Accept", "application/json"); + verify(mockUrlConnection).setRequestProperty("Accept-Charset", "utf-8"); + verify(mockUrlConnection).setRequestProperty("Accept-Language", "ja-JP"); + verify(mockUrlConnection).setDoOutput(false); + verify(mockUrlConnection).connect(); + verify(mockUrlConnection).getResponseCode(); + verify(mockUrlConnection, atLeast(0)).getHeaderFields(); + verifyNoMoreInteractions(mockUrlConnection); + } + + /** + * Test certificate GET requests. + */ + @Test + public void testSendCertificateRequest() throws Exception { + when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + + try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { + conn.sendCertificateRequest(requestUrl, session); + } + + verify(mockUrlConnection).setRequestMethod("GET"); + verify(mockUrlConnection).setRequestProperty("Accept", "application/pem-certificate-chain"); verify(mockUrlConnection).setRequestProperty("Accept-Charset", "utf-8"); verify(mockUrlConnection).setRequestProperty("Accept-Language", "ja-JP"); verify(mockUrlConnection).setDoOutput(false); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java index 2bfe67ee..f3821134 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DummyConnection.java @@ -41,6 +41,11 @@ public class DummyConnection implements Connection { throw new UnsupportedOperationException(); } + @Override + public void sendCertificateRequest(URL url, Session session) throws AcmeException { + throw new UnsupportedOperationException(); + } + @Override public int sendSignedRequest(URL url, JSONBuilder claims, Login login) throws AcmeException {