From 1297ca4de277124c92f52c87ab63a4476409ecad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Wed, 26 Sep 2018 19:24:20 +0200 Subject: [PATCH] Send POST-as-GET requests --- .../shredzone/acme4j/AcmeJsonResource.java | 2 +- .../org/shredzone/acme4j/Certificate.java | 2 +- .../acme4j/connector/Connection.java | 31 +++- .../acme4j/connector/DefaultConnection.java | 57 ++++--- .../acme4j/connector/ResourceIterator.java | 2 +- .../org/shredzone/acme4j/AccountTest.java | 3 +- .../shredzone/acme4j/AuthorizationTest.java | 12 +- .../org/shredzone/acme4j/CertificateTest.java | 15 +- .../java/org/shredzone/acme4j/OrderTest.java | 12 +- .../acme4j/challenge/ChallengeTest.java | 7 +- .../connector/DefaultConnectionTest.java | 146 +++++++++++++++--- .../acme4j/connector/DummyConnection.java | 7 +- .../connector/ResourceIteratorTest.java | 5 +- 13 files changed, 226 insertions(+), 75 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java b/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java index 1842e1d1..173ded70 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java @@ -116,7 +116,7 @@ public abstract class AcmeJsonResource extends AcmeResource { String resourceType = getClass().getSimpleName(); LOG.debug("update {}", resourceType); try (Connection conn = connect()) { - conn.sendRequest(getLocation(), getSession()); + conn.sendSignedPostAsGetRequest(getLocation(), getLogin()); JSON json = conn.readJsonResponse(); if (json != null) { setJSON(json); 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 d340dacb..261c75ca 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.sendCertificateRequest(getLocation(), getSession()); + conn.sendCertificateRequest(getLocation(), getLogin()); 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 092e56d9..2d5cb9d7 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 @@ -58,17 +58,36 @@ public interface Connection extends AutoCloseable { void sendRequest(URL url, Session session) throws AcmeException; /** - * Sends a request for a certificate resource. + * Sends a signed POST-as-GET request for a certificate resource. Requires a + * {@link Login} for the session and {@link KeyPair}. The {@link Login} account + * location is sent in a "kid" protected header. *

- * If the response code was not {@link HttpURLConnection#HTTP_OK}, an - * {@link AcmeException} matching the error is raised. + * If the server does not return a 200 class status code, an {@link AcmeException} is + * raised matching the error. * * @param url * {@link URL} to send the request to. - * @param session - * {@link Session} instance to be used for tracking + * @param login + * {@link Login} instance to be used for signing and tracking. + * @return HTTP 200 class status that was returned */ - void sendCertificateRequest(URL url, Session session) throws AcmeException; + int sendCertificateRequest(URL url, Login login) throws AcmeException; + + /** + * Sends a signed POST-as-GET request. Requires a {@link Login} for the session and + * {@link KeyPair}. The {@link Login} account location is sent in a "kid" protected + * header. + *

+ * If the server does not return a 200 class status code, an {@link AcmeException} is + * raised matching the error. + * + * @param url + * {@link URL} to send the request to. + * @param login + * {@link Login} instance to be used for signing and tracking. + * @return HTTP 200 class status that was returned + */ + int sendSignedPostAsGetRequest(URL url, Login login) throws AcmeException; /** * Sends a signed POST request. Requires a {@link Login} for the session and 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 ee5900dd..ca1f034f 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 @@ -137,15 +137,6 @@ 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(); @@ -155,7 +146,7 @@ public class DefaultConnection implements Connection { try { conn = httpConnector.openConnection(url, session.getProxy()); conn.setRequestMethod("GET"); - conn.setRequestProperty(ACCEPT_HEADER, accept); + conn.setRequestProperty(ACCEPT_HEADER, MIME_JSON); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.setDoOutput(false); @@ -174,30 +165,43 @@ public class DefaultConnection implements Connection { } } + @Override + public int sendCertificateRequest(URL url, Login login) throws AcmeException { + return sendSignedRequest(url, null, login.getSession(), login.getKeyPair(), + login.getAccountLocation(), MIME_CERTIFICATE_CHAIN); + } + + @Override + public int sendSignedPostAsGetRequest(URL url, Login login) throws AcmeException { + return sendSignedRequest(url, null, login.getSession(), login.getKeyPair(), + login.getAccountLocation(), MIME_JSON); + } + @Override public int sendSignedRequest(URL url, JSONBuilder claims, Login login) throws AcmeException { - return sendSignedRequest(url, claims, login.getSession(), login.getKeyPair(), login.getAccountLocation()); + return sendSignedRequest(url, claims, login.getSession(), login.getKeyPair(), + login.getAccountLocation(), MIME_JSON); } @Override public int sendSignedRequest(URL url, JSONBuilder claims, Session session, KeyPair keypair) throws AcmeException { - return sendSignedRequest(url, claims, session, keypair, null); + return sendSignedRequest(url, claims, session, keypair, null, MIME_JSON); } - private int sendSignedRequest(URL url, JSONBuilder claims, Session session, KeyPair keypair, @Nullable URL accountLocation) - throws AcmeException { + private int sendSignedRequest(URL url, @Nullable JSONBuilder claims, Session session, + KeyPair keypair, @Nullable URL accountLocation, String accept) throws AcmeException { Objects.requireNonNull(url, "url"); - Objects.requireNonNull(claims, "claims"); Objects.requireNonNull(session, "session"); Objects.requireNonNull(keypair, "keypair"); + Objects.requireNonNull(accept, "accept"); assertConnectionIsClosed(); AcmeException lastException = null; for (int attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { try { - return performRequest(url, claims, session, keypair, accountLocation); + return performRequest(url, claims, session, keypair, accountLocation, accept); } catch (AcmeServerException ex) { if (!BAD_NONCE_ERROR.equals(ex.getType())) { throw ex; @@ -322,7 +326,8 @@ public class DefaultConnection implements Connection { * @param url * {@link URL} to send the request to. * @param claims - * {@link JSONBuilder} containing claims. Must not be {@code null}. + * {@link JSONBuilder} containing claims. {@code null} for POST-as-GET + * request. * @param session * {@link Session} instance to be used for signing and tracking * @param keypair @@ -330,19 +335,23 @@ public class DefaultConnection implements Connection { * @param accountLocation * If set, the account location is set as "kid" header. If {@code null}, * the public key is set as "jwk" header. + * @param accept + * Accept header * @return HTTP 200 class status that was returned */ - private int performRequest(URL url, JSONBuilder claims, Session session, KeyPair keypair, - @Nullable URL accountLocation) + private int performRequest(URL url, @Nullable JSONBuilder claims, Session session, + KeyPair keypair, @Nullable URL accountLocation, String accept) throws AcmeException { try { if (session.getNonce() == null) { resetNonce(session); } + String claimJson = claims != null ? claims.toString() : ""; + conn = httpConnector.openConnection(url, session.getProxy()); conn.setRequestMethod("POST"); - conn.setRequestProperty(ACCEPT_HEADER, MIME_JSON); + conn.setRequestProperty(ACCEPT_HEADER, accept); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.setRequestProperty(CONTENT_TYPE_HEADER, "application/jose+json"); @@ -350,7 +359,7 @@ public class DefaultConnection implements Connection { final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic()); JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toString()); + jws.setPayload(claimJson); jws.getHeaders().setObjectHeaderValue("nonce", session.getNonce()); jws.getHeaders().setObjectHeaderValue("url", url); if (accountLocation == null) { @@ -364,8 +373,10 @@ public class DefaultConnection implements Connection { jws.sign(); if (LOG.isDebugEnabled()) { - LOG.debug("POST {}", url); - LOG.debug(" Payload: {}", claims.toString()); + LOG.debug("{} {}", claims != null ? "POST" : "POST-as-GET", url); + if (claims != null) { + LOG.debug(" Payload: {}", claimJson); + } LOG.debug(" JWS Header: {}", jws.getHeaders().getFullHeaderAsJsonString()); } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java index 9357ffb9..c3d68b80 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/ResourceIterator.java @@ -145,7 +145,7 @@ public class ResourceIterator implements Iterator { private void readAndQueue() throws AcmeException { Session session = login.getSession(); try (Connection conn = session.provider().connect()) { - conn.sendRequest(nextUrl, session); + conn.sendSignedPostAsGetRequest(nextUrl, login); JSON json = conn.readJsonResponse(); if (json != null) { diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java index b9e549e5..ada081c5 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AccountTest.java @@ -72,12 +72,13 @@ public class AccountTest { } @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { if (url("https://example.com/acme/acct/1/orders").equals(url)) { jsonResponse = new JSONBuilder() .array("orders", Arrays.asList("https://example.com/acme/order/1")) .toJSON(); } + return HttpURLConnection.HTTP_OK; } @Override diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java index 57182390..871c8123 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java @@ -92,8 +92,9 @@ public class AuthorizationTest { public void testUpdate() throws Exception { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -138,8 +139,9 @@ public class AuthorizationTest { public void testWildcard() throws Exception { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -181,9 +183,10 @@ public class AuthorizationTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { requestWasSent.set(true); assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -230,8 +233,9 @@ public class AuthorizationTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override 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 44221e8b..128f5f24 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/CertificateTest.java @@ -55,9 +55,10 @@ public class CertificateTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendCertificateRequest(URL url, Session session) { + public int sendCertificateRequest(URL url, Login login) { assertThat(url, is(locationUrl)); - assertThat(session, is(notNullValue())); + assertThat(login, is(notNullValue())); + return HttpURLConnection.HTTP_OK; } @Override @@ -124,10 +125,11 @@ public class CertificateTest { private boolean certRequested = false; @Override - public void sendCertificateRequest(URL url, Session session) { + public int sendCertificateRequest(URL url, Login login) { assertThat(url, is(locationUrl)); - assertThat(session, is(notNullValue())); + assertThat(login, is(notNullValue())); certRequested = true; + return HttpURLConnection.HTTP_OK; } @Override @@ -171,10 +173,11 @@ public class CertificateTest { private boolean certRequested = false; @Override - public void sendCertificateRequest(URL url, Session session) { + public int sendCertificateRequest(URL url, Login login) { assertThat(url, is(locationUrl)); - assertThat(session, is(notNullValue())); + assertThat(login, is(notNullValue())); certRequested = true; + return HttpURLConnection.HTTP_OK; } @Override diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java index 9272807f..9003ba4e 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/OrderTest.java @@ -48,8 +48,9 @@ public class OrderTest { public void testUpdate() throws Exception { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -109,9 +110,10 @@ public class OrderTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { requestWasSent.set(true); assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -156,8 +158,9 @@ public class OrderTest { private boolean isFinalized = false; @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -215,8 +218,9 @@ public class OrderTest { public void testRecurrentUpdate() throws Exception { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java index 54fcb9e5..605c52af 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ChallengeTest.java @@ -28,7 +28,6 @@ import java.time.Instant; import org.junit.Test; import org.shredzone.acme4j.Login; import org.shredzone.acme4j.Problem; -import org.shredzone.acme4j.Session; import org.shredzone.acme4j.Status; import org.shredzone.acme4j.exception.AcmeException; import org.shredzone.acme4j.exception.AcmeProtocolException; @@ -126,8 +125,9 @@ public class ChallengeTest { public void testUpdate() throws Exception { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override @@ -162,8 +162,9 @@ public class ChallengeTest { TestableConnectionProvider provider = new TestableConnectionProvider() { @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { assertThat(url, is(locationUrl)); + return HttpURLConnection.HTTP_OK; } @Override 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 55dea37b..43bad46f 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 @@ -663,28 +663,6 @@ public class DefaultConnectionTest { 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); - verify(mockUrlConnection).connect(); - verify(mockUrlConnection).getResponseCode(); - verify(mockUrlConnection, atLeast(0)).getHeaderFields(); - verifyNoMoreInteractions(mockUrlConnection); - } - /** * Test signed POST requests. */ @@ -760,6 +738,130 @@ public class DefaultConnectionTest { assertThat(jws.verifySignature(), is(true)); } + /** + * Test signed POST-as-GET requests. + */ + @Test + public void testSendSignedPostAsGetRequest() throws Exception { + final String nonce1 = Base64Url.encode("foo-nonce-1-foo".getBytes()); + final String nonce2 = Base64Url.encode("foo-nonce-2-foo".getBytes()); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + when(mockUrlConnection.getOutputStream()).thenReturn(outputStream); + + try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) { + @Override + public void resetNonce(Session session) { + assertThat(session, is(sameInstance(DefaultConnectionTest.this.session))); + if (session.getNonce() == null) { + session.setNonce(nonce1); + } else { + fail("unknown nonce"); + } + } + + @Override + public String getNonce() { + assertThat(session, is(sameInstance(DefaultConnectionTest.this.session))); + if (session.getNonce() == nonce1) { + return nonce2; + } else { + fail("unknown nonce"); + return null; + } + } + }) { + conn.sendSignedPostAsGetRequest(requestUrl, login); + } + + verify(mockUrlConnection).setRequestMethod("POST"); + verify(mockUrlConnection).setRequestProperty("Accept", "application/json"); + verify(mockUrlConnection).setRequestProperty("Accept-Charset", "utf-8"); + verify(mockUrlConnection).setRequestProperty("Accept-Language", "ja-JP"); + verify(mockUrlConnection).setRequestProperty("Content-Type", "application/jose+json"); + verify(mockUrlConnection).connect(); + verify(mockUrlConnection).setDoOutput(true); + verify(mockUrlConnection).setFixedLengthStreamingMode(outputStream.toByteArray().length); + verify(mockUrlConnection).getResponseCode(); + verify(mockUrlConnection).getOutputStream(); + verify(mockUrlConnection, atLeast(0)).getHeaderFields(); + verifyNoMoreInteractions(mockUrlConnection); + + JSON data = JSON.parse(new String(outputStream.toByteArray(), "utf-8")); + String encodedHeader = data.get("protected").asString(); + String encodedSignature = data.get("signature").asString(); + String encodedPayload = data.get("payload").asString(); + + StringBuilder expectedHeader = new StringBuilder(); + expectedHeader.append('{'); + expectedHeader.append("\"nonce\":\"").append(nonce1).append("\","); + expectedHeader.append("\"url\":\"").append(requestUrl).append("\","); + expectedHeader.append("\"alg\":\"RS256\","); + expectedHeader.append("\"kid\":\"").append(accountUrl).append('"'); + expectedHeader.append('}'); + + assertThat(Base64Url.decodeToUtf8String(encodedHeader), sameJSONAs(expectedHeader.toString())); + assertThat(Base64Url.decodeToUtf8String(encodedPayload), is("")); + assertThat(encodedSignature, not(isEmptyOrNullString())); + + JsonWebSignature jws = new JsonWebSignature(); + jws.setCompactSerialization(CompactSerializer.serialize(encodedHeader, encodedPayload, encodedSignature)); + jws.setKey(login.getKeyPair().getPublic()); + assertThat(jws.verifySignature(), is(true)); + } + + /** + * Test certificate POST-as-GET requests. + */ + @Test + public void testSendCertificateRequest() throws Exception { + final String nonce1 = Base64Url.encode("foo-nonce-1-foo".getBytes()); + final String nonce2 = Base64Url.encode("foo-nonce-2-foo".getBytes()); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + when(mockUrlConnection.getOutputStream()).thenReturn(outputStream); + + try (DefaultConnection conn = new DefaultConnection(mockHttpConnection) { + @Override + public void resetNonce(Session session) { + assertThat(session, is(sameInstance(DefaultConnectionTest.this.session))); + if (session.getNonce() == null) { + session.setNonce(nonce1); + } else { + fail("unknown nonce"); + } + } + + @Override + public String getNonce() { + assertThat(session, is(sameInstance(DefaultConnectionTest.this.session))); + if (session.getNonce() == nonce1) { + return nonce2; + } else { + fail("unknown nonce"); + return null; + } + } + }) { + conn.sendCertificateRequest(requestUrl, login); + } + + verify(mockUrlConnection).setRequestMethod("POST"); + verify(mockUrlConnection).setRequestProperty("Accept", "application/pem-certificate-chain"); + verify(mockUrlConnection).setRequestProperty("Accept-Charset", "utf-8"); + verify(mockUrlConnection).setRequestProperty("Accept-Language", "ja-JP"); + verify(mockUrlConnection).setRequestProperty("Content-Type", "application/jose+json"); + verify(mockUrlConnection).setDoOutput(true); + verify(mockUrlConnection).connect(); + verify(mockUrlConnection).setFixedLengthStreamingMode(outputStream.toByteArray().length); + verify(mockUrlConnection).getResponseCode(); + verify(mockUrlConnection).getOutputStream(); + verify(mockUrlConnection, atLeast(0)).getHeaderFields(); + verifyNoMoreInteractions(mockUrlConnection); + } + /** * Test signed POST requests without KeyIdentifier. */ 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 f3821134..3c3c0294 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 @@ -42,7 +42,12 @@ public class DummyConnection implements Connection { } @Override - public void sendCertificateRequest(URL url, Session session) throws AcmeException { + public int sendCertificateRequest(URL url, Login login) throws AcmeException { + throw new UnsupportedOperationException(); + } + + @Override + public int sendSignedPostAsGetRequest(URL url, Login login) throws AcmeException { throw new UnsupportedOperationException(); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java index 7d3170c7..c9904981 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/ResourceIteratorTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertThat; import static org.shredzone.acme4j.toolbox.TestUtils.url; import java.io.IOException; +import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -31,7 +32,6 @@ import org.junit.Before; import org.junit.Test; import org.shredzone.acme4j.Authorization; import org.shredzone.acme4j.Login; -import org.shredzone.acme4j.Session; import org.shredzone.acme4j.provider.TestableConnectionProvider; import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSONBuilder; @@ -134,9 +134,10 @@ public class ResourceIteratorTest { private int ix; @Override - public void sendRequest(URL url, Session session) { + public int sendSignedPostAsGetRequest(URL url, Login login) { ix = pageURLs.indexOf(url); assertThat(ix, is(greaterThanOrEqualTo(0))); + return HttpURLConnection.HTTP_OK; } @Override