mirror of https://github.com/shred/acme4j
Increase unit test coverage
parent
b3fc9a732c
commit
0a288fa290
|
@ -17,7 +17,9 @@ import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -162,7 +164,7 @@ public class Challenge extends AcmeResource {
|
||||||
* JSON map containing the challenge data
|
* JSON map containing the challenge data
|
||||||
*/
|
*/
|
||||||
public void unmarshall(Map<String, Object> map) {
|
public void unmarshall(Map<String, Object> map) {
|
||||||
String type = map.get(KEY_TYPE).toString();
|
String type = (String) map.get(KEY_TYPE);
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new IllegalArgumentException("map does not contain a type");
|
throw new IllegalArgumentException("map does not contain a type");
|
||||||
}
|
}
|
||||||
|
@ -187,6 +189,22 @@ public class Challenge extends AcmeResource {
|
||||||
return (T) data.get(key);
|
return (T) data.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an {@link URL} value from the challenge state.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* Key
|
||||||
|
* @return Value, or {@code null} if not set
|
||||||
|
*/
|
||||||
|
protected URL getUrl(String key) {
|
||||||
|
try {
|
||||||
|
String value = get(key);
|
||||||
|
return value != null ? new URL(value) : null;
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
throw new AcmeProtocolException(key + ": invalid URL", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback that is invoked when the challenge is supposed to compute its
|
* Callback that is invoked when the challenge is supposed to compute its
|
||||||
* authorization data.
|
* authorization data.
|
||||||
|
|
|
@ -13,11 +13,9 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.challenge;
|
package org.shredzone.acme4j.challenge;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import org.shredzone.acme4j.Session;
|
import org.shredzone.acme4j.Session;
|
||||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the {@value TYPE} challenge.
|
* Implements the {@value TYPE} challenge.
|
||||||
|
@ -45,11 +43,7 @@ public class OutOfBand01Challenge extends Challenge {
|
||||||
* challenge.
|
* challenge.
|
||||||
*/
|
*/
|
||||||
public URL getValidationUrl() {
|
public URL getValidationUrl() {
|
||||||
try {
|
return getUrl("href");
|
||||||
return new URL((String) get("href"));
|
|
||||||
} catch (MalformedURLException ex) {
|
|
||||||
throw new AcmeProtocolException("Invalid validation URL", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,13 @@ public class HttpConnector {
|
||||||
USER_AGENT = agent.toString();
|
USER_AGENT = agent.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default User-Agent to be used.
|
||||||
|
*/
|
||||||
|
public static String defaultUserAgent() {
|
||||||
|
return USER_AGENT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a {@link HttpURLConnection} to the given {@link URI}.
|
* Opens a {@link HttpURLConnection} to the given {@link URI}.
|
||||||
*
|
*
|
||||||
|
@ -58,11 +65,24 @@ public class HttpConnector {
|
||||||
*/
|
*/
|
||||||
public HttpURLConnection openConnection(URI uri) throws IOException {
|
public HttpURLConnection openConnection(URI uri) throws IOException {
|
||||||
HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection();
|
HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection();
|
||||||
|
configure(conn);
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the new {@link HttpURLConnection}.
|
||||||
|
* <p>
|
||||||
|
* This implementation sets reasonable timeouts, forbids caching, and sets an user
|
||||||
|
* agent.
|
||||||
|
*
|
||||||
|
* @param conn
|
||||||
|
* {@link HttpURLConnection} to configure.
|
||||||
|
*/
|
||||||
|
protected void configure(HttpURLConnection conn) {
|
||||||
conn.setConnectTimeout(TIMEOUT);
|
conn.setConnectTimeout(TIMEOUT);
|
||||||
conn.setReadTimeout(TIMEOUT);
|
conn.setReadTimeout(TIMEOUT);
|
||||||
conn.setUseCaches(false);
|
conn.setUseCaches(false);
|
||||||
conn.setRequestProperty("User-Agent", USER_AGENT);
|
conn.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
return conn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,19 @@ public class AcmeResourceTest {
|
||||||
assertThat(restored.getSession(), is(session));
|
assertThat(restored.getSession(), is(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a rebind attempt fails.
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testRebind() throws Exception {
|
||||||
|
Session session = TestUtils.session();
|
||||||
|
AcmeResource resource = new DummyResource(session);
|
||||||
|
assertThat(resource.getSession(), is(session));
|
||||||
|
|
||||||
|
Session session2 = TestUtils.session();
|
||||||
|
resource.rebind(session2); // fails to rebind to another session
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimum implementation of {@link AcmeResource}.
|
* Minimum implementation of {@link AcmeResource}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -195,4 +195,12 @@ public class CertificateTest {
|
||||||
provider.close();
|
provider.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that numeric revocation reasons are correctly translated.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRevocationReason() {
|
||||||
|
assertThat(RevocationReason.code(1), is(RevocationReason.KEY_COMPROMISE));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,10 @@ import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -98,7 +100,7 @@ public class ChallengeTest {
|
||||||
* Test that after unmarshalling, the challenge properties are set correctly.
|
* Test that after unmarshalling, the challenge properties are set correctly.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testUnmarshall() throws URISyntaxException {
|
public void testUnmarshall() throws URISyntaxException, MalformedURLException {
|
||||||
Challenge challenge = new Challenge(session);
|
Challenge challenge = new Challenge(session);
|
||||||
|
|
||||||
// Test default values
|
// Test default values
|
||||||
|
@ -115,6 +117,17 @@ public class ChallengeTest {
|
||||||
assertThat(challenge.getStatus(), is(Status.VALID));
|
assertThat(challenge.getStatus(), is(Status.VALID));
|
||||||
assertThat(challenge.getLocation(), is(new URI("http://example.com/challenge/123")));
|
assertThat(challenge.getLocation(), is(new URI("http://example.com/challenge/123")));
|
||||||
assertThat(challenge.getValidated(), is(TimestampParser.parse("2015-12-12T17:19:36.336785823Z")));
|
assertThat(challenge.getValidated(), is(TimestampParser.parse("2015-12-12T17:19:36.336785823Z")));
|
||||||
|
assertThat((String) challenge.get("type"), is("generic-01"));
|
||||||
|
assertThat(challenge.getUrl("uri"), is(new URL("http://example.com/challenge/123")));
|
||||||
|
assertThat(challenge.get("not-present"), is(nullValue()));
|
||||||
|
assertThat(challenge.getUrl("not-present-url"), is(nullValue()));
|
||||||
|
|
||||||
|
try {
|
||||||
|
challenge.getUrl("type");
|
||||||
|
fail("bad URL is not detected");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,6 +280,65 @@ public class ChallengeTest {
|
||||||
provider.close();
|
provider.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that null is handled properly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNullChallenge() throws Exception {
|
||||||
|
try {
|
||||||
|
Challenge.bind(session, null);
|
||||||
|
fail("locationUri accepts null");
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Challenge.bind(null, locationUri);
|
||||||
|
fail("session accepts null");
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an exception is thrown on a bad location URI.
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testBadBind() throws Exception {
|
||||||
|
TestableConnectionProvider provider = new TestableConnectionProvider() {
|
||||||
|
@Override
|
||||||
|
public void sendRequest(URI uri, Session session) {
|
||||||
|
assertThat(uri, is(locationUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int accept(int... httpStatus) throws AcmeException {
|
||||||
|
assertThat(httpStatus, isIntArrayContainingInAnyOrder(
|
||||||
|
HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_ACCEPTED));
|
||||||
|
return HttpURLConnection.HTTP_ACCEPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> readJsonResponse() {
|
||||||
|
return getJsonAsMap("updateRegistrationResponse");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Session session = provider.createSession();
|
||||||
|
Challenge.bind(session, locationUri);
|
||||||
|
|
||||||
|
provider.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that unmarshalling something different like a challenge fails.
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testBadUnmarshall() {
|
||||||
|
Challenge challenge = new Challenge(session);
|
||||||
|
challenge.unmarshall(TestUtils.getJsonAsMap("updateRegistrationResponse"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that challenge serialization works correctly.
|
* Test that challenge serialization works correctly.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.shredzone.acme4j.Session;
|
import org.shredzone.acme4j.Session;
|
||||||
import org.shredzone.acme4j.Status;
|
import org.shredzone.acme4j.Status;
|
||||||
|
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
import org.shredzone.acme4j.util.ClaimBuilder;
|
import org.shredzone.acme4j.util.ClaimBuilder;
|
||||||
import org.shredzone.acme4j.util.TestUtils;
|
import org.shredzone.acme4j.util.TestUtils;
|
||||||
|
|
||||||
|
@ -62,4 +63,14 @@ public class HttpChallengeTest {
|
||||||
+ KEY_AUTHORIZATION + "\"}").allowingExtraUnexpectedFields());
|
+ KEY_AUTHORIZATION + "\"}").allowingExtraUnexpectedFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an exception is thrown if there is no token.
|
||||||
|
*/
|
||||||
|
@Test(expected = AcmeProtocolException.class)
|
||||||
|
public void testNoTokenSet() {
|
||||||
|
Http01Challenge challenge = new Http01Challenge(session);
|
||||||
|
challenge.unmarshall(TestUtils.getJsonAsMap("httpNoTokenChallenge"));
|
||||||
|
challenge.getToken();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ package org.shredzone.acme4j.connector;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
@ -29,6 +31,24 @@ import org.junit.experimental.categories.Category;
|
||||||
*/
|
*/
|
||||||
public class HttpConnectorTest {
|
public class HttpConnectorTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a HTTP connection can be opened.
|
||||||
|
* <p>
|
||||||
|
* This is just a mock to check that the parameters are properly set.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testMockOpenConnection() throws IOException, URISyntaxException {
|
||||||
|
HttpURLConnection conn = mock(HttpURLConnection.class);
|
||||||
|
|
||||||
|
HttpConnector connector = new HttpConnector();
|
||||||
|
connector.configure(conn);
|
||||||
|
|
||||||
|
verify(conn).setConnectTimeout(anyInt());
|
||||||
|
verify(conn).setReadTimeout(anyInt());
|
||||||
|
verify(conn).setUseCaches(false);
|
||||||
|
verify(conn).setRequestProperty("User-Agent", HttpConnector.defaultUserAgent());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if a HTTP connection can be opened.
|
* Test if a HTTP connection can be opened.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -45,4 +65,14 @@ public class HttpConnectorTest {
|
||||||
assertThat(conn.getResponseCode(), is(HttpURLConnection.HTTP_OK));
|
assertThat(conn.getResponseCode(), is(HttpURLConnection.HTTP_OK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the user agent is correct.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUserAgent() {
|
||||||
|
String userAgent = HttpConnector.defaultUserAgent();
|
||||||
|
assertThat(userAgent.contains("acme4j/"), is(true));
|
||||||
|
assertThat(userAgent.contains("Java/"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AcmeAgreementRequiredException}.
|
||||||
|
*/
|
||||||
|
public class AcmeAgreementRequiredExceptionTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that parameters are correctly returned.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAcmeAgreementRequiredException() {
|
||||||
|
String type = "urn:ietf:params:acme:error:agreementRequired";
|
||||||
|
String detail = "Agreement is required";
|
||||||
|
URI agreementUri = URI.create("http://example.com/agreement.pdf");
|
||||||
|
URI instanceUri = URI.create("http://example.com/howToAgree.html");
|
||||||
|
|
||||||
|
AcmeAgreementRequiredException ex
|
||||||
|
= new AcmeAgreementRequiredException(type, detail, agreementUri, instanceUri);
|
||||||
|
|
||||||
|
assertThat(ex.getType(), is(type));
|
||||||
|
assertThat(ex.getMessage(), is(detail));
|
||||||
|
assertThat(ex.getAgreementUri(), is(agreementUri));
|
||||||
|
assertThat(ex.getInstance(), is(instanceUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that optional parameters are null-safe.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNullAcmeAgreementRequiredException() {
|
||||||
|
String type = "urn:ietf:params:acme:error:agreementRequired";
|
||||||
|
String detail = "Agreement is required";
|
||||||
|
|
||||||
|
AcmeAgreementRequiredException ex
|
||||||
|
= new AcmeAgreementRequiredException(type, detail, null, null);
|
||||||
|
|
||||||
|
assertThat(ex.getType(), is(type));
|
||||||
|
assertThat(ex.getMessage(), is(detail));
|
||||||
|
assertThat(ex.getAgreementUri(), nullValue());
|
||||||
|
assertThat(ex.getInstance(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AcmeConflictException}.
|
||||||
|
*/
|
||||||
|
public class AcmeConflictExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAcmeConflictException() {
|
||||||
|
String msg = "Account already exists";
|
||||||
|
URI locationUri = URI.create("http://example.com/location/123");
|
||||||
|
|
||||||
|
AcmeConflictException ex
|
||||||
|
= new AcmeConflictException(msg, locationUri);
|
||||||
|
|
||||||
|
assertThat(ex.getMessage(), is(msg));
|
||||||
|
assertThat(ex.getLocation(), is(locationUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AcmeException}.
|
||||||
|
*/
|
||||||
|
public class AcmeExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAcmeException() {
|
||||||
|
AcmeException ex = new AcmeException();
|
||||||
|
assertThat(ex.getMessage(), nullValue());
|
||||||
|
assertThat(ex.getCause(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessageAcmeException() {
|
||||||
|
String message = "Failure";
|
||||||
|
AcmeException ex = new AcmeException(message);
|
||||||
|
assertThat(ex.getMessage(), is(message));
|
||||||
|
assertThat(ex.getCause(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCausedAcmeException() {
|
||||||
|
String message = "Failure";
|
||||||
|
IOException cause = new IOException("No network");
|
||||||
|
|
||||||
|
AcmeException ex = new AcmeException(message, cause);
|
||||||
|
assertThat(ex.getMessage(), is(message));
|
||||||
|
assertThat(ex.getCause(), is((Throwable) cause));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AcmeNetworkException}.
|
||||||
|
*/
|
||||||
|
public class AcmeNetworkExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAcmeNetworkException() {
|
||||||
|
IOException cause = new IOException("Network not reachable");
|
||||||
|
|
||||||
|
AcmeNetworkException ex = new AcmeNetworkException(cause);
|
||||||
|
|
||||||
|
assertThat(ex.getMessage(), notNullValue());
|
||||||
|
assertThat(ex.getCause(), is((Throwable) cause));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AcmeProtocolException}.
|
||||||
|
*/
|
||||||
|
public class AcmeProtocolExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAcmeProtocolException() {
|
||||||
|
String msg = "Bad content";
|
||||||
|
AcmeProtocolException ex = new AcmeProtocolException(msg);
|
||||||
|
assertThat(ex, is(instanceOf(RuntimeException.class)));
|
||||||
|
assertThat(ex.getMessage(), is(msg));
|
||||||
|
assertThat(ex.getCause(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCausedAcmeProtocolException() {
|
||||||
|
String message = "Bad content";
|
||||||
|
NumberFormatException cause = new NumberFormatException("Not a number: abc");
|
||||||
|
AcmeProtocolException ex = new AcmeProtocolException(message, cause);
|
||||||
|
assertThat(ex.getMessage(), is(message));
|
||||||
|
assertThat(ex.getCause(), is((Throwable) cause));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.exception;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link AcmeRateLimitExceededException}.
|
||||||
|
*/
|
||||||
|
public class AcmeRateLimitExceededExceptionTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that parameters are correctly returned.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAcmeRateLimitExceededException() {
|
||||||
|
String type = "urn:ietf:params:acme:error:rateLimited";
|
||||||
|
String detail = "Too many requests per minute";
|
||||||
|
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
|
||||||
|
Collection<URI> documents = Arrays.asList(
|
||||||
|
URI.create("http://example.com/doc1.html"),
|
||||||
|
URI.create("http://example.com/doc2.html"));
|
||||||
|
|
||||||
|
AcmeRateLimitExceededException ex
|
||||||
|
= new AcmeRateLimitExceededException(type, detail, retryAfter, documents);
|
||||||
|
|
||||||
|
assertThat(ex.getType(), is(type));
|
||||||
|
assertThat(ex.getMessage(), is(detail));
|
||||||
|
assertThat(ex.getRetryAfter(), is(retryAfter));
|
||||||
|
assertThat(ex.getDocuments(), containsInAnyOrder(documents.toArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that optional parameters are null-safe.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNullAcmeRateLimitExceededException() {
|
||||||
|
String type = "urn:ietf:params:acme:error:rateLimited";
|
||||||
|
String detail = "Too many requests per minute";
|
||||||
|
|
||||||
|
AcmeRateLimitExceededException ex
|
||||||
|
= new AcmeRateLimitExceededException(type, detail, null, null);
|
||||||
|
|
||||||
|
assertThat(ex.getType(), is(type));
|
||||||
|
assertThat(ex.getMessage(), is(detail));
|
||||||
|
assertThat(ex.getRetryAfter(), nullValue());
|
||||||
|
assertThat(ex.getDocuments(), nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,9 +13,12 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.util;
|
package org.shredzone.acme4j.util;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.shredzone.acme4j.util.TimestampParser.parse;
|
import static org.shredzone.acme4j.util.TimestampParser.parse;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -99,6 +102,17 @@ public class TimestampParserTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that constructor is private.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrivateConstructor() throws Exception {
|
||||||
|
Constructor<TimestampParser> constructor = TimestampParser.class.getDeclaredConstructor();
|
||||||
|
assertThat(Modifier.isPrivate(constructor.getModifiers()), is(true));
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
constructor.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches the given time.
|
* Matches the given time.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -218,6 +218,12 @@ httpChallenge = \
|
||||||
"token": "rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ" \
|
"token": "rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ" \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpNoTokenChallenge = \
|
||||||
|
{ \
|
||||||
|
"type":"http-01", \
|
||||||
|
"status":"pending" \
|
||||||
|
}
|
||||||
|
|
||||||
tlsSniChallenge = \
|
tlsSniChallenge = \
|
||||||
{ \
|
{ \
|
||||||
"type":"tls-sni-01", \
|
"type":"tls-sni-01", \
|
||||||
|
|
|
@ -20,6 +20,9 @@ import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
|
@ -57,13 +60,9 @@ public class CertificateUtilsTest {
|
||||||
@Test
|
@Test
|
||||||
public void testReadWriteX509Certificate() throws IOException, CertificateException {
|
public void testReadWriteX509Certificate() throws IOException, CertificateException {
|
||||||
// Read a demonstration certificate
|
// Read a demonstration certificate
|
||||||
X509Certificate original;
|
X509Certificate original = createCertificate();
|
||||||
try (InputStream cert = getClass().getResourceAsStream("/cert.pem")) {
|
|
||||||
original = (X509Certificate) certificateFactory.generateCertificate(cert);
|
|
||||||
}
|
|
||||||
assertThat(original, is(notNullValue()));
|
|
||||||
|
|
||||||
// Write to StringWriter
|
// Write to Byte Array
|
||||||
byte[] pem;
|
byte[] pem;
|
||||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||||
CertificateUtils.writeX509Certificate(original, out);
|
CertificateUtils.writeX509Certificate(original, out);
|
||||||
|
@ -83,6 +82,43 @@ public class CertificateUtilsTest {
|
||||||
assertThat(original.getEncoded(), is(equalTo(written.getEncoded())));
|
assertThat(original.getEncoded(), is(equalTo(written.getEncoded())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if
|
||||||
|
* {@link CertificateUtils#writeX509CertificateChain(java.io.Writer, X509Certificate, X509Certificate...)}
|
||||||
|
* writes a correct chain.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testWriteX509CertificateChain() throws IOException, CertificateException {
|
||||||
|
X509Certificate leaf = createCertificate();
|
||||||
|
X509Certificate chain1 = createCertificate();
|
||||||
|
X509Certificate chain2 = createCertificate();
|
||||||
|
|
||||||
|
String out;
|
||||||
|
try (StringWriter w = new StringWriter()) {
|
||||||
|
CertificateUtils.writeX509CertificateChain(w, leaf);
|
||||||
|
out = w.toString();
|
||||||
|
}
|
||||||
|
assertThat(countCertificates(out), is(1));
|
||||||
|
|
||||||
|
try (StringWriter w = new StringWriter()) {
|
||||||
|
CertificateUtils.writeX509CertificateChain(w, leaf, chain1);
|
||||||
|
out = w.toString();
|
||||||
|
}
|
||||||
|
assertThat(countCertificates(out), is(2));
|
||||||
|
|
||||||
|
try (StringWriter w = new StringWriter()) {
|
||||||
|
CertificateUtils.writeX509CertificateChain(w, leaf, chain1, chain2);
|
||||||
|
out = w.toString();
|
||||||
|
}
|
||||||
|
assertThat(countCertificates(out), is(3));
|
||||||
|
|
||||||
|
try (StringWriter w = new StringWriter()) {
|
||||||
|
CertificateUtils.writeX509CertificateChain(w, leaf, chain1, null, chain2);
|
||||||
|
out = w.toString();
|
||||||
|
}
|
||||||
|
assertThat(countCertificates(out), is(3));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if {@link CertificateUtils#createTlsSniCertificate(KeyPair, String)} creates a
|
* Test if {@link CertificateUtils#createTlsSniCertificate(KeyPair, String)} creates a
|
||||||
* good certificate.
|
* good certificate.
|
||||||
|
@ -155,6 +191,48 @@ public class CertificateUtilsTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a test certificates.
|
||||||
|
*/
|
||||||
|
private X509Certificate createCertificate() throws IOException, CertificateException {
|
||||||
|
X509Certificate original;
|
||||||
|
try (InputStream cert = getClass().getResourceAsStream("/cert.pem")) {
|
||||||
|
original = (X509Certificate) certificateFactory.generateCertificate(cert);
|
||||||
|
}
|
||||||
|
assertThat(original, is(notNullValue()));
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that constructor is private.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrivateConstructor() throws Exception {
|
||||||
|
Constructor<CertificateUtils> constructor = CertificateUtils.class.getDeclaredConstructor();
|
||||||
|
assertThat(Modifier.isPrivate(constructor.getModifiers()), is(true));
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
constructor.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts number of certificates in a PEM string.
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* String containing certificates in PEM format
|
||||||
|
* @return Number of certificates found
|
||||||
|
*/
|
||||||
|
private int countCertificates(String str) {
|
||||||
|
int count = 0;
|
||||||
|
int pos = 0;
|
||||||
|
while (true) {
|
||||||
|
pos = str.indexOf("-----BEGIN CERTIFICATE-----", pos);
|
||||||
|
if (pos < 0) break;
|
||||||
|
count++;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts all DNSName SANs from a certificate.
|
* Extracts all DNSName SANs from a certificate.
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,6 +19,8 @@ import static org.junit.Assert.assertThat;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
@ -131,4 +133,15 @@ public class KeyPairUtilsTest {
|
||||||
assertThat(pair.getPrivate().getEncoded(), is(equalTo(readPair.getPrivate().getEncoded())));
|
assertThat(pair.getPrivate().getEncoded(), is(equalTo(readPair.getPrivate().getEncoded())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that constructor is private.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrivateConstructor() throws Exception {
|
||||||
|
Constructor<KeyPairUtils> constructor = KeyPairUtils.class.getDeclaredConstructor();
|
||||||
|
assertThat(Modifier.isPrivate(constructor.getModifiers()), is(true));
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
constructor.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue