Avoid unnecessary de/encoding of nonces

pull/61/head
Richard Körber 2018-03-06 22:10:08 +01:00
parent 189d2d94a8
commit 69a23e7bf6
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
8 changed files with 27 additions and 30 deletions

View File

@ -40,8 +40,7 @@ public class Session {
private final URI serverUri; private final URI serverUri;
private final AcmeProvider provider; private final AcmeProvider provider;
private byte[] nonce; private String nonce;
private JSON directoryJson;
private Locale locale = Locale.getDefault(); private Locale locale = Locale.getDefault();
protected Instant directoryCacheExpiry; protected Instant directoryCacheExpiry;
@ -101,16 +100,16 @@ public class Session {
} }
/** /**
* Gets the last nonce, or {@code null} if the session is new. * Gets the last base64 encoded nonce, or {@code null} if the session is new.
*/ */
public byte[] getNonce() { public String getNonce() {
return nonce; return nonce;
} }
/** /**
* Sets the nonce received by the server. * Sets the base64 encoded nonce received by the server.
*/ */
public void setNonce(byte[] nonce) { public void setNonce(String nonce) {
this.nonce = nonce; this.nonce = nonce;
} }

View File

@ -117,9 +117,9 @@ public interface Connection extends AutoCloseable {
/** /**
* Gets the nonce from the nonce header. * Gets the nonce from the nonce header.
* *
* @return Nonce, or {@code null} if no nonce header was set * @return Base64 encoded nonce, or {@code null} if no nonce header was set
*/ */
byte[] getNonce(); String getNonce();
/** /**
* Gets a location from the {@code Location} header. * Gets a location from the {@code Location} header.

View File

@ -37,7 +37,6 @@ import java.util.Optional;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.jose4j.base64url.Base64Url;
import org.jose4j.jwk.PublicJsonWebKey; import org.jose4j.jwk.PublicJsonWebKey;
import org.jose4j.jws.JsonWebSignature; import org.jose4j.jws.JsonWebSignature;
import org.jose4j.lang.JoseException; import org.jose4j.lang.JoseException;
@ -112,7 +111,7 @@ public class DefaultConnection implements Connection {
throwAcmeException(); throwAcmeException();
} }
byte[] nonce = getNonce(); String nonce = getNonce();
if (nonce == null) { if (nonce == null) {
throw new AcmeProtocolException("Server did not provide a nonce"); throw new AcmeProtocolException("Server did not provide a nonce");
} }
@ -247,12 +246,12 @@ public class DefaultConnection implements Connection {
} }
@Override @Override
public byte[] getNonce() { public String getNonce() {
assertConnectionIsOpen(); assertConnectionIsOpen();
String nonceHeader = conn.getHeaderField(REPLAY_NONCE_HEADER); String nonceHeader = conn.getHeaderField(REPLAY_NONCE_HEADER);
if (nonceHeader == null || nonceHeader.trim().isEmpty()) { if (nonceHeader == null || nonceHeader.trim().isEmpty()) {
return null; //NOSONAR: consistent with other getters return null;
} }
if (!BASE64URL_PATTERN.matcher(nonceHeader).matches()) { if (!BASE64URL_PATTERN.matcher(nonceHeader).matches()) {
@ -261,7 +260,7 @@ public class DefaultConnection implements Connection {
LOG.debug("Replay Nonce: {}", nonceHeader); LOG.debug("Replay Nonce: {}", nonceHeader);
return Base64Url.decode(nonceHeader); return nonceHeader;
} }
@Override @Override
@ -323,7 +322,7 @@ public class DefaultConnection implements Connection {
final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic()); final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic());
JsonWebSignature jws = new JsonWebSignature(); JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toString()); jws.setPayload(claims.toString());
jws.getHeaders().setObjectHeaderValue("nonce", Base64Url.encode(session.getNonce())); jws.getHeaders().setObjectHeaderValue("nonce", session.getNonce());
jws.getHeaders().setObjectHeaderValue("url", url); jws.getHeaders().setObjectHeaderValue("url", url);
if (accountLocation == null) { if (accountLocation == null) {
jws.getHeaders().setJwkHeaderValue("jwk", jwk); jws.getHeaders().setJwkHeaderValue("jwk", jwk);

View File

@ -54,7 +54,7 @@ public abstract class AbstractAcmeProvider implements AcmeProvider {
conn.sendRequest(resolve(serverUri), session); conn.sendRequest(resolve(serverUri), session);
// use nonce header if there is one, saves a HEAD request... // use nonce header if there is one, saves a HEAD request...
byte[] nonce = conn.getNonce(); String nonce = conn.getNonce();
if (nonce != null) { if (nonce != null) {
session.setNonce(nonce); session.setNonce(nonce);
} }

View File

@ -76,9 +76,8 @@ public class SessionTest {
Session session = new Session(serverUri); Session session = new Session(serverUri);
assertThat(session.getNonce(), is(nullValue())); assertThat(session.getNonce(), is(nullValue()));
byte[] data = "foo-nonce-bar".getBytes(); session.setNonce(DUMMY_NONCE);
session.setNonce(data); assertThat(session.getNonce(), is(equalTo(DUMMY_NONCE)));
assertThat(session.getNonce(), is(equalTo(data)));
assertThat(session.getServerUri(), is(serverUri)); assertThat(session.getServerUri(), is(serverUri));
} }

View File

@ -119,7 +119,7 @@ public class DefaultConnectionTest {
@Test @Test
public void testGetNonceFromHeader() { public void testGetNonceFromHeader() {
when(mockUrlConnection.getHeaderField("Replay-Nonce")) when(mockUrlConnection.getHeaderField("Replay-Nonce"))
.thenReturn(Base64Url.encode(TestUtils.DUMMY_NONCE)); .thenReturn(TestUtils.DUMMY_NONCE);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection; conn.conn = mockUrlConnection;
@ -175,7 +175,7 @@ public class DefaultConnectionTest {
assertThat(session.getNonce(), is(nullValue())); assertThat(session.getNonce(), is(nullValue()));
when(mockUrlConnection.getHeaderField("Replay-Nonce")) when(mockUrlConnection.getHeaderField("Replay-Nonce"))
.thenReturn(Base64Url.encode(TestUtils.DUMMY_NONCE)); .thenReturn(TestUtils.DUMMY_NONCE);
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) { try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.resetNonce(session); conn.resetNonce(session);
@ -660,8 +660,8 @@ public class DefaultConnectionTest {
*/ */
@Test @Test
public void testSendSignedRequest() throws Exception { public void testSendSignedRequest() throws Exception {
final byte[] nonce1 = "foo-nonce-1-foo".getBytes(); final String nonce1 = Base64Url.encode("foo-nonce-1-foo".getBytes());
final byte[] nonce2 = "foo-nonce-2-foo".getBytes(); final String nonce2 = Base64Url.encode("foo-nonce-2-foo".getBytes());
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
@ -679,7 +679,7 @@ public class DefaultConnectionTest {
} }
@Override @Override
public byte[] getNonce() { public String getNonce() {
assertThat(session, is(sameInstance(DefaultConnectionTest.this.session))); assertThat(session, is(sameInstance(DefaultConnectionTest.this.session)));
if (session.getNonce() == nonce1) { if (session.getNonce() == nonce1) {
return nonce2; return nonce2;
@ -714,7 +714,7 @@ public class DefaultConnectionTest {
StringBuilder expectedHeader = new StringBuilder(); StringBuilder expectedHeader = new StringBuilder();
expectedHeader.append('{'); expectedHeader.append('{');
expectedHeader.append("\"nonce\":\"").append(Base64Url.encode(nonce1)).append("\","); expectedHeader.append("\"nonce\":\"").append(nonce1).append("\",");
expectedHeader.append("\"url\":\"").append(requestUrl).append("\","); expectedHeader.append("\"url\":\"").append(requestUrl).append("\",");
expectedHeader.append("\"alg\":\"RS256\","); expectedHeader.append("\"alg\":\"RS256\",");
expectedHeader.append("\"kid\":\"").append(accountUrl).append('"'); expectedHeader.append("\"kid\":\"").append(accountUrl).append('"');
@ -735,8 +735,8 @@ public class DefaultConnectionTest {
*/ */
@Test @Test
public void testSendSignedRequestNoKid() throws Exception { public void testSendSignedRequestNoKid() throws Exception {
final byte[] nonce1 = "foo-nonce-1-foo".getBytes(); final String nonce1 = Base64Url.encode("foo-nonce-1-foo".getBytes());
final byte[] nonce2 = "foo-nonce-2-foo".getBytes(); final String nonce2 = Base64Url.encode("foo-nonce-2-foo".getBytes());
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
@ -754,7 +754,7 @@ public class DefaultConnectionTest {
} }
@Override @Override
public byte[] getNonce() { public String getNonce() {
assertThat(session, is(sameInstance(DefaultConnectionTest.this.session))); assertThat(session, is(sameInstance(DefaultConnectionTest.this.session)));
if (session.getNonce() == nonce1) { if (session.getNonce() == nonce1) {
return nonce2; return nonce2;
@ -789,7 +789,7 @@ public class DefaultConnectionTest {
StringBuilder expectedHeader = new StringBuilder(); StringBuilder expectedHeader = new StringBuilder();
expectedHeader.append('{'); expectedHeader.append('{');
expectedHeader.append("\"nonce\":\"").append(Base64Url.encode(nonce1)).append("\","); expectedHeader.append("\"nonce\":\"").append(nonce1).append("\",");
expectedHeader.append("\"url\":\"").append(requestUrl).append("\","); expectedHeader.append("\"url\":\"").append(requestUrl).append("\",");
expectedHeader.append("\"alg\":\"RS256\","); expectedHeader.append("\"alg\":\"RS256\",");
expectedHeader.append("\"jwk\":{"); expectedHeader.append("\"jwk\":{");

View File

@ -69,7 +69,7 @@ public class DummyConnection implements Connection {
} }
@Override @Override
public byte[] getNonce() { public String getNonce() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -73,7 +73,7 @@ public final class TestUtils {
public static final String ACME_SERVER_URI = "https://example.com/acme"; public static final String ACME_SERVER_URI = "https://example.com/acme";
public static final String ACCOUNT_URL = "https://example.com/acme/account/1"; public static final String ACCOUNT_URL = "https://example.com/acme/account/1";
public static final byte[] DUMMY_NONCE = "foo-nonce-foo".getBytes(); public static final String DUMMY_NONCE = Base64Url.encode("foo-nonce-foo".getBytes());
private TestUtils() { private TestUtils() {