mirror of https://github.com/shred/acme4j
Challenge can have multiple errors
parent
dcdf240804
commit
dfb40edc12
|
@ -13,9 +13,13 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j.challenge;
|
package org.shredzone.acme4j.challenge;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.shredzone.acme4j.AcmeResource;
|
import org.shredzone.acme4j.AcmeResource;
|
||||||
|
@ -27,6 +31,7 @@ import org.shredzone.acme4j.exception.AcmeException;
|
||||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
|
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
|
||||||
import org.shredzone.acme4j.util.JSON;
|
import org.shredzone.acme4j.util.JSON;
|
||||||
|
import org.shredzone.acme4j.util.JSON.Array;
|
||||||
import org.shredzone.acme4j.util.JSONBuilder;
|
import org.shredzone.acme4j.util.JSONBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -48,7 +53,7 @@ public class Challenge extends AcmeResource {
|
||||||
protected static final String KEY_URL = "url";
|
protected static final String KEY_URL = "url";
|
||||||
protected static final String KEY_STATUS = "status";
|
protected static final String KEY_STATUS = "status";
|
||||||
protected static final String KEY_VALIDATED = "validated";
|
protected static final String KEY_VALIDATED = "validated";
|
||||||
protected static final String KEY_ERROR = "error";
|
protected static final String KEY_ERRORS = "errors";
|
||||||
|
|
||||||
private JSON data = JSON.empty();
|
private JSON data = JSON.empty();
|
||||||
|
|
||||||
|
@ -120,10 +125,27 @@ public class Challenge extends AcmeResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the reason why the challenge failed, if returned by the server.
|
* Returns a list of reasons why the challenge has failed in the past, if returned by
|
||||||
|
* the server. New errors are always appended to the end of the list.
|
||||||
*/
|
*/
|
||||||
public Problem getError() {
|
public List<Problem> getErrors() {
|
||||||
return data.get(KEY_ERROR).asProblem(getLocation());
|
URL location = getLocation();
|
||||||
|
return Collections.unmodifiableList(data.get(KEY_ERRORS).asArray().stream()
|
||||||
|
.map(it -> it.asProblem(location))
|
||||||
|
.collect(toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last reason why the challenge has failed, if returned by the server.
|
||||||
|
* {@code null} if there are no errors.
|
||||||
|
*/
|
||||||
|
public Problem getLastError() {
|
||||||
|
Array errors = data.get(KEY_ERRORS).asArray();
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
return errors.get(errors.size() - 1).asProblem(getLocation());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,10 +26,12 @@ import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.jose4j.lang.JoseException;
|
import org.jose4j.lang.JoseException;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.shredzone.acme4j.Problem;
|
||||||
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.AcmeException;
|
import org.shredzone.acme4j.exception.AcmeException;
|
||||||
|
@ -111,14 +113,26 @@ public class ChallengeTest {
|
||||||
assertThat(challenge.getStatus(), is(Status.INVALID));
|
assertThat(challenge.getStatus(), is(Status.INVALID));
|
||||||
assertThat(challenge.getLocation(), is(url("http://example.com/challenge/123")));
|
assertThat(challenge.getLocation(), is(url("http://example.com/challenge/123")));
|
||||||
assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z")));
|
assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z")));
|
||||||
assertThat(challenge.getError(), is(notNullValue()));
|
|
||||||
assertThat(challenge.getError().getType(), is(URI.create("urn:ietf:params:acme:error:connection")));
|
|
||||||
assertThat(challenge.getError().getDetail(), is("connection refused"));
|
|
||||||
assertThat(challenge.getError().getInstance(), is(URI.create("http://example.com/documents/error.html")));
|
|
||||||
assertThat(challenge.getJSON().get("type").asString(), is("generic-01"));
|
assertThat(challenge.getJSON().get("type").asString(), is("generic-01"));
|
||||||
assertThat(challenge.getJSON().get("url").asURL(), is(url("http://example.com/challenge/123")));
|
assertThat(challenge.getJSON().get("url").asURL(), is(url("http://example.com/challenge/123")));
|
||||||
assertThat(challenge.getJSON().get("not-present").asString(), is(nullValue()));
|
assertThat(challenge.getJSON().get("not-present").asString(), is(nullValue()));
|
||||||
assertThat(challenge.getJSON().get("not-present-url").asURL(), is(nullValue()));
|
assertThat(challenge.getJSON().get("not-present-url").asURL(), is(nullValue()));
|
||||||
|
|
||||||
|
List<Problem> errors = challenge.getErrors();
|
||||||
|
assertThat(errors, is(notNullValue()));
|
||||||
|
assertThat(errors, hasSize(2));
|
||||||
|
assertThat(errors.get(0).getType(), is(URI.create("urn:ietf:params:acme:error:connection")));
|
||||||
|
assertThat(errors.get(0).getDetail(), is("connection refused"));
|
||||||
|
assertThat(errors.get(0).getInstance(), is(URI.create("http://example.com/documents/error.html")));
|
||||||
|
assertThat(errors.get(1).getType(), is(URI.create("urn:ietf:params:acme:error:incorrectResponse")));
|
||||||
|
assertThat(errors.get(1).getDetail(), is("bad token"));
|
||||||
|
assertThat(errors.get(1).getInstance(), is(URI.create("http://example.com/documents/faq.html")));
|
||||||
|
|
||||||
|
Problem lastError = challenge.getLastError();
|
||||||
|
assertThat(lastError, is(notNullValue()));
|
||||||
|
assertThat(lastError.getType(), is(URI.create("urn:ietf:params:acme:error:incorrectResponse")));
|
||||||
|
assertThat(lastError.getDetail(), is("bad token"));
|
||||||
|
assertThat(lastError.getInstance(), is(URI.create("http://example.com/documents/faq.html")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
"status": "invalid",
|
"status": "invalid",
|
||||||
"url": "http://example.com/challenge/123",
|
"url": "http://example.com/challenge/123",
|
||||||
"validated": "2015-12-12T17:19:36.336785823Z",
|
"validated": "2015-12-12T17:19:36.336785823Z",
|
||||||
"error": {
|
"errors": [
|
||||||
|
{
|
||||||
"type": "urn:ietf:params:acme:error:connection",
|
"type": "urn:ietf:params:acme:error:connection",
|
||||||
"detail": "connection refused",
|
"detail": "connection refused",
|
||||||
"instance": "/documents/error.html"
|
"instance": "/documents/error.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "urn:ietf:params:acme:error:incorrectResponse",
|
||||||
|
"detail": "bad token",
|
||||||
|
"instance": "/documents/faq.html"
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue