Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/main/java/org/tomitribe/auth/signatures/Signature.java
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,19 @@ private static String normalize(String authorization) {

@Override
public String toString() {
Object alg;
if (SigningAlgorithm.HS2019.equals(signingAlgorithm)) {
// When the signing algorithm is set to 'hs2019', the value of the algorithm
// field must be set to 'hs2019'. The specific crypto algorithm is not
// serialized in the 'Authorization' header, the server must derive the value
// from the keyId.
alg = signingAlgorithm;
} else {
alg = algorithm;
}
return "Signature " +
"keyId=\"" + keyId + '\"' +
",algorithm=\"" + algorithm + '\"' +
",algorithm=\"" + alg + '\"' +
",headers=\"" + Join.join(" ", headers) + '\"' +
",signature=\"" + signature + '\"';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,12 @@ public void nonAlphaNumericsIgnored() throws Exception {
public void unsupportedAlgorithmException() throws Exception {
Algorithm.get("HmacMD256");
}

@Test
public void getSigningAlgorithm() throws Exception {
for (final SigningAlgorithm algorithm : SigningAlgorithm.values()) {
SigningAlgorithm s = SigningAlgorithm.get(algorithm.getAlgorithmName());
assertEquals(algorithm, s);
}
}
}
10 changes: 5 additions & 5 deletions src/test/java/org/tomitribe/auth/signatures/SignatureTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ public void nullSigningAlgorithm() {

@Test
public void nullHeaders() {
final Signature signature = new Signature("somekey", SigningAlgorithm.HS2019.getAlgorithmName(), "hmac-sha256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList());
final Signature signature = new Signature("somekey", SigningAlgorithm.HMAC_SHA256.getAlgorithmName(), "hmac-sha256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList());
assertEquals(1, signature.getHeaders().size()); // should contain at least the Date which is required
assertEquals("date", signature.getHeaders().get(0).toLowerCase());
}


@Test
public void roundTripTest() throws Exception {
final Signature expected = new Signature("somekey", SigningAlgorithm.HS2019.getAlgorithmName(), "hmac-sha256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList("date", "accept"));
final Signature expected = new Signature("somekey", SigningAlgorithm.HMAC_SHA256.getAlgorithmName(), "hmac-sha256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList("date", "accept"));
final Signature actual = Signature.fromString(expected.toString(), null);

assertSignature(expected, actual);
Expand Down Expand Up @@ -202,7 +202,7 @@ public void whitespaceTolerance() throws Exception {
@Test
public void orderTolerance() throws Exception {

final Signature expected = new Signature("hmac-key-1", SigningAlgorithm.HS2019.getAlgorithmName(), "hmac-sha256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList("date", "accept"));
final Signature expected = new Signature("hmac-key-1", SigningAlgorithm.HMAC_SHA256.getAlgorithmName(), "hmac-sha256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList("date", "accept"));

final List<String> input = Arrays.asList(
"keyId=\"hmac-key-1\"",
Expand All @@ -227,7 +227,7 @@ public void orderTolerance() throws Exception {
@Test
public void caseNormalization() throws Exception {

final Signature signature = new Signature("hmac-key-1", SigningAlgorithm.HS2019.getAlgorithmName(), "hMaC-ShA256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList("dAte", "aCcEpt"));
final Signature signature = new Signature("hmac-key-1", SigningAlgorithm.HMAC_SHA256.getAlgorithmName(), "hMaC-ShA256", null, "yT/NrPI9mKB5R7FTLRyFWvB+QLQOEAvbGmauC0tI+Jg=", Arrays.asList("dAte", "aCcEpt"));

assertEquals("hmac-key-1", signature.getKeyId());
assertEquals("hmac-sha256", signature.getAlgorithm().toString());
Expand Down Expand Up @@ -324,7 +324,7 @@ public void trailingCommaTolerance() throws Exception {
@Test
public void testToString() throws Exception {

final Signature signature = new Signature("hmac-key-1", SigningAlgorithm.HS2019.getAlgorithmName(), "hmac-sha256", null, "Base64(HMAC-SHA256(signing string))", Arrays.asList("(request-target)", "host", "date", "digest", "content-length"));
final Signature signature = new Signature("hmac-key-1", SigningAlgorithm.HMAC_SHA256.getAlgorithmName(), "hmac-sha256", null, "Base64(HMAC-SHA256(signing string))", Arrays.asList("(request-target)", "host", "date", "digest", "content-length"));

String authorization = "Signature keyId=\"hmac-key-1\"," +
"algorithm=\"hmac-sha256\"," +
Expand Down
87 changes: 86 additions & 1 deletion src/test/java/org/tomitribe/auth/signatures/SignerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import org.junit.Test;

import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.security.Key;
import java.security.PrivateKey;
import java.security.Provider;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -246,8 +248,91 @@ public void testSign1() throws Exception {
}
}

/**
* Test the 'algorithm' field in the 'Authorization' header has the expected value.
*
* @throws Exception when a unit test fails.
*/
@Test
public void testAlgorithFieldInAuthorizationHeader() throws Exception {
final Map<String, String> headers = new HashMap<String, String>();
headers.put("Host", "example.org");
headers.put("Date", "Tue, 07 Jun 2014 20:51:35 GMT");
headers.put("Content-Type", "application/json");
headers.put("Digest", "SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=");
headers.put("Accept", "*/*");
headers.put("Content-Length", "18");

final String ecPrivateKeyPem =
"-----BEGIN EC PRIVATE KEY-----\n" +
"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAwMH6qcFB3MyllyHKe\n" +
"4mqAFWS2gbD4XWzKtCnSmj2b1A==\n" +
"-----END EC PRIVATE KEY-----\n";

final String rsaPrivateKeyPem =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF\n" +
"NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F\n" +
"UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB\n" +
"AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA\n" +
"QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK\n" +
"kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg\n" +
"f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u\n" +
"412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc\n" +
"mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7\n" +
"kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA\n" +
"gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW\n" +
"G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI\n" +
"7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA==\n" +
"-----END RSA PRIVATE KEY-----\n";

{
// Create a signature with the RSA SHA-256 algorithm.
// The signing algorithm is set to RSA_SHA256, hence the value of the
// 'algorithm' field in the Authorization header must be 'rsa-sha256'.
final Signature signature = new Signature("my-key",
SigningAlgorithm.RSA_SHA256,
Algorithm.RSA_SHA256, null, null,
Arrays.asList("(request-target)", "host", "date", "digest", "content-length"));
PrivateKey privateKey = PEM.readPrivateKey(new ByteArrayInputStream(rsaPrivateKeyPem.getBytes()));
final Signer signer = new Signer(privateKey, signature);
Signature s = signer.sign("POST", "", headers);
assertTrue(s.toString().contains("algorithm=\"rsa-sha256\""));
}
{
// Create a signature with the RSA SHA-256 algorithm.
// But this time the signing algorithm is set to HS2019, hence the value of the
// 'algorithm' field in the Authorization header must be 'hs2019'.
// The actual value of the algorithm is not serialized on the wire, the server
// must derive the value from the keyId (out-of-band).
final Signature signature = new Signature("my-key",
SigningAlgorithm.HS2019,
Algorithm.RSA_SHA256, null, null,
Arrays.asList("(request-target)", "host", "date", "digest", "content-length"));
PrivateKey privateKey = PEM.readPrivateKey(new ByteArrayInputStream(rsaPrivateKeyPem.getBytes()));
final Signer signer = new Signer(privateKey, signature);
Signature s = signer.sign("POST", "", headers);
assertTrue(s.toString().contains("algorithm=\"hs2019\""));
}
{
// Create a signature with the ECDSA SHA256 algorithm.
// The signing algorithm is set to HS2019, hence the value of the
// 'algorithm' field in the Authorization header must be 'hs2019'.
// The actual value of the algorithm is not serialized on the wire, the server
// must derive the value from the keyId (out-of-band).
final Signature signature = new Signature("my-key",
SigningAlgorithm.HS2019,
Algorithm.ECDSA_SHA256, null, null,
Arrays.asList("(request-target)", "host", "date", "digest", "content-length"));
PrivateKey privateKey = PEM.readPrivateKey(new ByteArrayInputStream(ecPrivateKeyPem.getBytes()));
final Signer signer = new Signer(privateKey, signature);
Signature s = signer.sign("POST", "", headers);
assertTrue(s.toString().contains("algorithm=\"hs2019\""));
}
}

@Test
public void testCreateSingingString() throws Exception {
public void testCreateSigningString() throws Exception {
{
final String method = "POST";
final String uri = "/foo";
Expand Down