Return external account binding key identifier

pull/81/head
Richard Körber 2019-04-28 17:25:47 +02:00
parent d02746156d
commit 210b2aa453
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
8 changed files with 72 additions and 6 deletions

View File

@ -54,6 +54,7 @@ public class Account extends AcmeJsonResource {
private static final String KEY_ORDERS = "orders";
private static final String KEY_CONTACT = "contact";
private static final String KEY_STATUS = "status";
private static final String KEY_EXTERNAL_ACCOUNT_BINDING = "externalAccountBinding";
protected Account(Login login) {
super(login, login.getAccountLocation());
@ -91,6 +92,30 @@ public class Account extends AcmeJsonResource {
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}.
* <p>

View File

@ -27,6 +27,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
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}.
*

View File

@ -13,8 +13,7 @@
*/
package org.shredzone.acme4j;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
import static org.shredzone.acme4j.toolbox.TestUtils.url;
@ -100,6 +99,8 @@ public class AccountBuilderTest {
Account account = login.getAccount();
assertThat(account.getTermsOfServiceAgreed(), is(true));
assertThat(account.getLocation(), is(locationUrl));
assertThat(account.hasExternalAccountBinding(), is(false));
assertThat(account.getKeyIdentifier(), is(nullValue()));
provider.close();
}

View File

@ -115,6 +115,8 @@ public class AccountTest {
assertThat(account.getContacts(), hasSize(1));
assertThat(account.getContacts().get(0), is(URI.create("mailto:foo2@example.com")));
assertThat(account.getStatus(), is(Status.VALID));
assertThat(account.hasExternalAccountBinding(), is(true));
assertThat(account.getKeyIdentifier(), is("NCC-1701"));
Iterator<Order> orderIt = account.getOrders();
assertThat(orderIt, not(nullValue()));

View File

@ -112,7 +112,6 @@ public class JSONBuilderTest {
* Test JWK.
*/
@Test
@SuppressWarnings("unchecked")
public void testKey() throws IOException, JoseException {
KeyPair keyPair = TestUtils.createKeyPair();

View File

@ -105,7 +105,7 @@ public class JSONTest {
assertThat(json.keySet(), containsInAnyOrder(
"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("music"), is(false));
assertThat(json.get("text"), is(notNullValue()));
@ -233,6 +233,9 @@ public class JSONTest {
JSON sub = array.get(3).asObject();
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);
assertThat(problem, is(notNullValue()));
assertThat(problem.getType(), is(URI.create("urn:ietf:params:acme:error:rateLimited")));
@ -294,6 +297,13 @@ public class JSONTest {
// expected
}
try {
json.get("none").asEncodedObject();
fail("asEncodedObject did not fail");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("none").asStatus();
fail("asStatus did not fail");
@ -344,6 +354,13 @@ public class JSONTest {
// expected
}
try {
json.get("text").asEncodedObject();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asArray();
fail("no exception was thrown");

View File

@ -14,5 +14,6 @@
"type": "urn:ietf:params:acme:error:rateLimited",
"detail": "too many requests",
"instance": "/documents/errors.html"
}
},
"encoded": "eyJrZXkiOiJ2YWx1ZSJ9"
}

View File

@ -4,5 +4,10 @@
"mailto:foo2@example.com"
],
"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"
}
}