mirror of https://github.com/shred/acme4j
Return external account binding key identifier
parent
d02746156d
commit
210b2aa453
|
@ -54,6 +54,7 @@ public class Account extends AcmeJsonResource {
|
||||||
private static final String KEY_ORDERS = "orders";
|
private static final String KEY_ORDERS = "orders";
|
||||||
private static final String KEY_CONTACT = "contact";
|
private static final String KEY_CONTACT = "contact";
|
||||||
private static final String KEY_STATUS = "status";
|
private static final String KEY_STATUS = "status";
|
||||||
|
private static final String KEY_EXTERNAL_ACCOUNT_BINDING = "externalAccountBinding";
|
||||||
|
|
||||||
protected Account(Login login) {
|
protected Account(Login login) {
|
||||||
super(login, login.getAccountLocation());
|
super(login, login.getAccountLocation());
|
||||||
|
@ -91,6 +92,30 @@ public class Account extends AcmeJsonResource {
|
||||||
return getJSON().get(KEY_STATUS).asStatus();
|
return getJSON().get(KEY_STATUS).asStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the account is bound to an external non-ACME account.
|
||||||
|
*
|
||||||
|
* @since 2.8
|
||||||
|
*/
|
||||||
|
public boolean hasExternalAccountBinding() {
|
||||||
|
return getJSON().contains(KEY_EXTERNAL_ACCOUNT_BINDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key identifier of the external non-ACME account. If this account is
|
||||||
|
* not bound to an external account, {@code null} is returned instead.
|
||||||
|
*
|
||||||
|
* @since 2.8
|
||||||
|
*/
|
||||||
|
@CheckForNull
|
||||||
|
public String getKeyIdentifier() {
|
||||||
|
return getJSON().get(KEY_EXTERNAL_ACCOUNT_BINDING)
|
||||||
|
.optional().map(Value::asObject)
|
||||||
|
.map(j -> j.get("protected")).map(Value::asEncodedObject)
|
||||||
|
.map(j -> j.get("kid")).map(Value::asString)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Iterator} of all {@link Order} belonging to this {@link Account}.
|
* Returns an {@link Iterator} of all {@link Order} belonging to this {@link Account}.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -347,6 +348,21 @@ public final class JSON implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value as JSON object that was Base64 URL encoded.
|
||||||
|
*
|
||||||
|
* @since 2.8
|
||||||
|
*/
|
||||||
|
public JSON asEncodedObject() {
|
||||||
|
required();
|
||||||
|
try {
|
||||||
|
byte[] raw = AcmeUtils.base64UrlDecode(val.toString());
|
||||||
|
return new JSON(path, JsonUtil.parseJson(new String(raw, StandardCharsets.UTF_8)));
|
||||||
|
} catch (IllegalArgumentException | JoseException ex) {
|
||||||
|
throw new AcmeProtocolException(path + ": expected an encoded object", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as {@link Problem}.
|
* Returns the value as {@link Problem}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
*/
|
*/
|
||||||
package org.shredzone.acme4j;
|
package org.shredzone.acme4j;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
|
import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
|
||||||
import static org.shredzone.acme4j.toolbox.TestUtils.url;
|
import static org.shredzone.acme4j.toolbox.TestUtils.url;
|
||||||
|
@ -100,6 +99,8 @@ public class AccountBuilderTest {
|
||||||
Account account = login.getAccount();
|
Account account = login.getAccount();
|
||||||
assertThat(account.getTermsOfServiceAgreed(), is(true));
|
assertThat(account.getTermsOfServiceAgreed(), is(true));
|
||||||
assertThat(account.getLocation(), is(locationUrl));
|
assertThat(account.getLocation(), is(locationUrl));
|
||||||
|
assertThat(account.hasExternalAccountBinding(), is(false));
|
||||||
|
assertThat(account.getKeyIdentifier(), is(nullValue()));
|
||||||
|
|
||||||
provider.close();
|
provider.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,8 @@ public class AccountTest {
|
||||||
assertThat(account.getContacts(), hasSize(1));
|
assertThat(account.getContacts(), hasSize(1));
|
||||||
assertThat(account.getContacts().get(0), is(URI.create("mailto:foo2@example.com")));
|
assertThat(account.getContacts().get(0), is(URI.create("mailto:foo2@example.com")));
|
||||||
assertThat(account.getStatus(), is(Status.VALID));
|
assertThat(account.getStatus(), is(Status.VALID));
|
||||||
|
assertThat(account.hasExternalAccountBinding(), is(true));
|
||||||
|
assertThat(account.getKeyIdentifier(), is("NCC-1701"));
|
||||||
|
|
||||||
Iterator<Order> orderIt = account.getOrders();
|
Iterator<Order> orderIt = account.getOrders();
|
||||||
assertThat(orderIt, not(nullValue()));
|
assertThat(orderIt, not(nullValue()));
|
||||||
|
|
|
@ -112,7 +112,6 @@ public class JSONBuilderTest {
|
||||||
* Test JWK.
|
* Test JWK.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testKey() throws IOException, JoseException {
|
public void testKey() throws IOException, JoseException {
|
||||||
KeyPair keyPair = TestUtils.createKeyPair();
|
KeyPair keyPair = TestUtils.createKeyPair();
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class JSONTest {
|
||||||
|
|
||||||
assertThat(json.keySet(), containsInAnyOrder(
|
assertThat(json.keySet(), containsInAnyOrder(
|
||||||
"text", "number", "boolean", "uri", "url", "date", "array",
|
"text", "number", "boolean", "uri", "url", "date", "array",
|
||||||
"collect", "status", "binary", "duration", "problem"));
|
"collect", "status", "binary", "duration", "problem", "encoded"));
|
||||||
assertThat(json.contains("text"), is(true));
|
assertThat(json.contains("text"), is(true));
|
||||||
assertThat(json.contains("music"), is(false));
|
assertThat(json.contains("music"), is(false));
|
||||||
assertThat(json.get("text"), is(notNullValue()));
|
assertThat(json.get("text"), is(notNullValue()));
|
||||||
|
@ -233,6 +233,9 @@ public class JSONTest {
|
||||||
JSON sub = array.get(3).asObject();
|
JSON sub = array.get(3).asObject();
|
||||||
assertThat(sub.get("test").asString(), is("ok"));
|
assertThat(sub.get("test").asString(), is("ok"));
|
||||||
|
|
||||||
|
JSON encodedSub = json.get("encoded").asEncodedObject();
|
||||||
|
assertThat(encodedSub.toString(), is(sameJSONAs("{\"key\":\"value\"}")));
|
||||||
|
|
||||||
Problem problem = json.get("problem").asProblem(BASE_URL);
|
Problem problem = json.get("problem").asProblem(BASE_URL);
|
||||||
assertThat(problem, is(notNullValue()));
|
assertThat(problem, is(notNullValue()));
|
||||||
assertThat(problem.getType(), is(URI.create("urn:ietf:params:acme:error:rateLimited")));
|
assertThat(problem.getType(), is(URI.create("urn:ietf:params:acme:error:rateLimited")));
|
||||||
|
@ -294,6 +297,13 @@ public class JSONTest {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asEncodedObject();
|
||||||
|
fail("asEncodedObject did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
json.get("none").asStatus();
|
json.get("none").asStatus();
|
||||||
fail("asStatus did not fail");
|
fail("asStatus did not fail");
|
||||||
|
@ -344,6 +354,13 @@ public class JSONTest {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("text").asEncodedObject();
|
||||||
|
fail("no exception was thrown");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
json.get("text").asArray();
|
json.get("text").asArray();
|
||||||
fail("no exception was thrown");
|
fail("no exception was thrown");
|
||||||
|
|
|
@ -14,5 +14,6 @@
|
||||||
"type": "urn:ietf:params:acme:error:rateLimited",
|
"type": "urn:ietf:params:acme:error:rateLimited",
|
||||||
"detail": "too many requests",
|
"detail": "too many requests",
|
||||||
"instance": "/documents/errors.html"
|
"instance": "/documents/errors.html"
|
||||||
}
|
},
|
||||||
|
"encoded": "eyJrZXkiOiJ2YWx1ZSJ9"
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,10 @@
|
||||||
"mailto:foo2@example.com"
|
"mailto:foo2@example.com"
|
||||||
],
|
],
|
||||||
"termsOfServiceAgreed": true,
|
"termsOfServiceAgreed": true,
|
||||||
"orders": "https://example.com/acme/acct/1/orders"
|
"orders": "https://example.com/acme/acct/1/orders",
|
||||||
|
"externalAccountBinding": {
|
||||||
|
"protected": "eyJ1cmwiOiJodHRwOi8vZXhhbXBsZS5jb20vYWNtZS9yZXNvdXJjZSIsImtpZCI6Ik5DQy0xNzAxIiwiYWxnIjoiSFMyNTYifQ",
|
||||||
|
"payload": "eyJrdHkiOiJSU0EiLCJuIjoicFpzVEtZNDF5X0N3Z0owVlg3Qm1tR3NfN1Vwcm1YUU1HUGNuU2JCZUpBalpIQTlTeXlKS2FXdjRmTlVkQklBWDNZMlFvWml4ajUwblFMeUx2Mm5nM3B2RW9STDBzeDlaSGdwNW5kQWpwSWlWUV84VjAxVFRZQ0VEVWM5aWk3YmpWa2dGQWI0VmFsWkdGSlo1NFBjQ25BSHZYaTVnMEVMT1J6R2NUdVJxSFZBVWNrTVYyb3RyMGcwdV81YldNbTZFTUFiQnJHUUNnVUdqYlpRSGphdmExWS01dEhYWmtQQmFoSjJMdktScU1tSlVscjBhbkt1Skp0SlVHMDNESllBeEFCdjhZQWFYRkJuR3c2a0tKUnBVRkFDNTVyeTRzcDRrR3kwTnJLMlRWV21aVzlrU3RuaVJ2NFJhSkdJOWFaR1l3UXkya1V5a2liQk5tV0VRVWxJd0l3IiwiZSI6IkFRQUIifQ",
|
||||||
|
"signature": "skPdpjTgx8zIGsNRtvv4zNlfp-uidFDgCMY3Z3ONLgw"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue