From 81534d0053e69f1517359f67b851c7d4997a7c9a Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Mon, 28 Feb 2022 15:47:26 +0530 Subject: [PATCH 001/134] Replace deprecated assertThat method in tests --- .../java/com/auth0/jwt/ClockImplTest.java | 2 +- .../java/com/auth0/jwt/JWTCreatorTest.java | 2 +- .../java/com/auth0/jwt/JWTDecoderTest.java | 33 +++++++-------- lib/src/test/java/com/auth0/jwt/JWTTest.java | 2 +- .../java/com/auth0/jwt/JWTVerifierTest.java | 2 +- .../java/com/auth0/jwt/TokenUtilsTest.java | 2 +- .../auth0/jwt/algorithms/AlgorithmTest.java | 2 +- .../jwt/algorithms/CryptoTestHelper.java | 2 +- .../jwt/algorithms/ECDSAAlgorithmTest.java | 42 +++++++++---------- .../ECDSABouncyCastleProviderTests.java | 2 +- .../jwt/algorithms/HMACAlgorithmTest.java | 8 ++-- .../jwt/algorithms/NoneAlgorithmTest.java | 2 +- .../jwt/algorithms/RSAAlgorithmTest.java | 3 +- .../com/auth0/jwt/impl/ClaimsHolderTest.java | 2 +- .../jwt/impl/HeaderDeserializerTest.java | 2 +- .../com/auth0/jwt/impl/JsonNodeClaimTest.java | 2 +- .../com/auth0/jwt/impl/NullClaimTest.java | 2 +- .../jwt/impl/PayloadDeserializerTest.java | 2 +- .../auth0/jwt/impl/PayloadSerializerTest.java | 2 +- 19 files changed, 56 insertions(+), 60 deletions(-) diff --git a/lib/src/test/java/com/auth0/jwt/ClockImplTest.java b/lib/src/test/java/com/auth0/jwt/ClockImplTest.java index 0eec07d7..0feb7c40 100644 --- a/lib/src/test/java/com/auth0/jwt/ClockImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/ClockImplTest.java @@ -7,7 +7,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.*; +import static org.hamcrest.MatcherAssert.assertThat; public class ClockImplTest { diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index eabc2f31..0cbafc35 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -16,7 +16,7 @@ import java.util.*; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 5cfe069e..77ac4d18 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -6,7 +6,6 @@ import com.auth0.jwt.interfaces.DecodedJWT; import org.hamcrest.collection.IsCollectionWithSize; import org.hamcrest.core.IsCollectionContaining; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -244,24 +243,24 @@ public void shouldNotGetNullClaimIfClaimIsEmptyObject() throws Exception { public void shouldGetCustomClaimOfTypeInteger() throws Exception { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); - Assert.assertThat(jwt.getClaim("name").asInt(), is(123)); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asInt(), is(123)); } @Test public void shouldGetCustomClaimOfTypeDouble() throws Exception { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); - Assert.assertThat(jwt.getClaim("name").asDouble(), is(23.45)); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asDouble(), is(23.45)); } @Test public void shouldGetCustomClaimOfTypeBoolean() throws Exception { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); - Assert.assertThat(jwt.getClaim("name").asBoolean(), is(true)); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asBoolean(), is(true)); } @Test @@ -269,35 +268,35 @@ public void shouldGetCustomClaimOfTypeDate() throws Exception { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; Date date = new Date(1478891521000L); DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); - Assert.assertThat(jwt.getClaim("name").asDate().getTime(), is(date.getTime())); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asDate().getTime(), is(date.getTime())); } @Test public void shouldGetCustomArrayClaimOfTypeString() throws Exception { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); - Assert.assertThat(jwt.getClaim("name").asArray(String.class), arrayContaining("text", "123", "true")); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asArray(String.class), arrayContaining("text", "123", "true")); } @Test public void shouldGetCustomArrayClaimOfTypeInteger() throws Exception { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); - Assert.assertThat(jwt.getClaim("name").asArray(Integer.class), arrayContaining(1, 2, 3)); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asArray(Integer.class), arrayContaining(1, 2, 3)); } @Test public void shouldGetCustomMapClaim() throws Exception { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjp7InN0cmluZyI6InZhbHVlIiwibnVtYmVyIjoxLCJib29sZWFuIjp0cnVlfX0.-8aIaXd2-rp1lLuDEQmCeisCBX9X_zbqdPn2llGxNoc"; DecodedJWT jwt = JWT.decode(token); - Assert.assertThat(jwt, is(notNullValue())); + assertThat(jwt, is(notNullValue())); Map map = jwt.getClaim("name").asMap(); - Assert.assertThat(map, hasEntry("string", (Object) "value")); - Assert.assertThat(map, hasEntry("number", (Object) 1)); - Assert.assertThat(map, hasEntry("boolean", (Object) true)); + assertThat(map, hasEntry("string", (Object) "value")); + assertThat(map, hasEntry("number", (Object) 1)); + assertThat(map, hasEntry("boolean", (Object) true)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index bcf62e05..6004e142 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -18,7 +18,7 @@ import java.util.Date; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 131b389e..99e8b104 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -18,7 +18,7 @@ import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class JWTVerifierTest { diff --git a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java index 4bea9b44..a9ad8cbe 100644 --- a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java +++ b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java @@ -6,7 +6,7 @@ import org.junit.rules.ExpectedException; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; public class TokenUtilsTest { diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java index 50430017..d2e26e9a 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java @@ -12,7 +12,7 @@ import java.security.interfaces.*; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.withSettings; import static org.mockito.ArgumentMatchers.any; diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java b/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java index 25b08d70..ef8e65e8 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java @@ -6,7 +6,7 @@ import java.util.regex.Pattern; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; public abstract class CryptoTestHelper { diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index 39c9dabf..8dd00ca3 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -6,7 +6,6 @@ import com.auth0.jwt.interfaces.ECDSAKeyProvider; import org.hamcrest.Matchers; import org.hamcrest.collection.IsIn; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -27,14 +26,13 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.isA; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@SuppressWarnings("deprecation") public class ECDSAAlgorithmTest { private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; @@ -1136,10 +1134,10 @@ public void shouldDecodeECDSA512DER() throws Exception { //Test Helpers static void assertValidJOSESignature(byte[] joseSignature, int numberSize, boolean withRPadding, boolean withSPadding) { - Assert.assertThat(joseSignature, is(Matchers.notNullValue())); - Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); + assertThat(joseSignature, is(Matchers.notNullValue())); + assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); - Assert.assertThat(joseSignature.length, is(numberSize * 2)); + assertThat(joseSignature.length, is(numberSize * 2)); byte[] rCopy = Arrays.copyOfRange(joseSignature, 0, numberSize); byte[] sCopy = Arrays.copyOfRange(joseSignature, numberSize, numberSize * 2); @@ -1154,12 +1152,12 @@ static void assertValidJOSESignature(byte[] joseSignature, int numberSize, boole if (withSPadding) { sNumber[0] = (byte) 0; } - Assert.assertThat(Arrays.equals(rNumber, rCopy), is(true)); - Assert.assertThat(Arrays.equals(sNumber, sCopy), is(true)); + assertThat(Arrays.equals(rNumber, rCopy), is(true)); + assertThat(Arrays.equals(sNumber, sCopy), is(true)); } static byte[] createDERSignature(int numberSize, boolean withRPadding, boolean withSPadding) { - Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); + assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); int rLength = withRPadding ? numberSize - 1 : numberSize; int sLength = withSPadding ? numberSize - 1 : numberSize; @@ -1202,7 +1200,7 @@ static byte[] createDERSignature(int numberSize, boolean withRPadding, boolean w } static byte[] createJOSESignature(int numberSize, boolean withRPadding, boolean withSPadding) { - Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); + assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); byte[] rNumber = new byte[numberSize]; byte[] sNumber = new byte[numberSize]; @@ -1221,8 +1219,8 @@ static byte[] createJOSESignature(int numberSize, boolean withRPadding, boolean } static void assertValidDERSignature(byte[] derSignature, int numberSize, boolean withRPadding, boolean withSPadding) { - Assert.assertThat(derSignature, is(Matchers.notNullValue())); - Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); + assertThat(derSignature, is(Matchers.notNullValue())); + assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); int rLength = withRPadding ? numberSize - 1 : numberSize; int sLength = withSPadding ? numberSize - 1 : numberSize; @@ -1230,24 +1228,24 @@ static void assertValidDERSignature(byte[] derSignature, int numberSize, boolean int offset = 0; //Start sequence - Assert.assertThat(derSignature[offset++], is((byte) 0x30)); + assertThat(derSignature[offset++], is((byte) 0x30)); if (totalLength > 0x7f) { //Add sign before sequence length totalLength++; - Assert.assertThat(derSignature[offset++], is((byte) 0x81)); + assertThat(derSignature[offset++], is((byte) 0x81)); } //Sequence length - Assert.assertThat(derSignature[offset++], is((byte) (totalLength - offset))); + assertThat(derSignature[offset++], is((byte) (totalLength - offset))); //R number - Assert.assertThat(derSignature[offset++], is((byte) 0x02)); - Assert.assertThat(derSignature[offset++], is((byte) rLength)); + assertThat(derSignature[offset++], is((byte) 0x02)); + assertThat(derSignature[offset++], is((byte) rLength)); byte[] rCopy = Arrays.copyOfRange(derSignature, offset, offset + rLength); offset += rLength; //S number - Assert.assertThat(derSignature[offset++], is((byte) 0x02)); - Assert.assertThat(derSignature[offset++], is((byte) sLength)); + assertThat(derSignature[offset++], is((byte) 0x02)); + assertThat(derSignature[offset++], is((byte) sLength)); byte[] sCopy = Arrays.copyOfRange(derSignature, offset, offset + sLength); @@ -1255,9 +1253,9 @@ static void assertValidDERSignature(byte[] derSignature, int numberSize, boolean byte[] sNumber = new byte[sLength]; Arrays.fill(rNumber, (byte) 0x11); Arrays.fill(sNumber, (byte) 0x22); - Assert.assertThat(Arrays.equals(rNumber, rCopy), is(true)); - Assert.assertThat(Arrays.equals(sNumber, sCopy), is(true)); - Assert.assertThat(derSignature.length, is(totalLength)); + assertThat(Arrays.equals(rNumber, rCopy), is(true)); + assertThat(Arrays.equals(sNumber, sCopy), is(true)); + assertThat(derSignature.length, is(totalLength)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java index 68fe6e50..675baeff 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java @@ -25,7 +25,7 @@ import static com.auth0.jwt.algorithms.ECDSAAlgorithmTest.*; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java index fd5aed71..ded62aff 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java @@ -19,8 +19,8 @@ import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignatureValue; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertArrayEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @@ -36,8 +36,8 @@ public class HMACAlgorithmTest { @Test public void shouldGetStringBytes() throws Exception { String text = "abcdef123456!@#$%^"; - byte[] expectedBytes = text.getBytes("UTF-8"); - assertTrue(Arrays.equals(expectedBytes, HMACAlgorithm.getSecretBytes(text))); + byte[] expectedBytes = text.getBytes(StandardCharsets.UTF_8); + assertArrayEquals(expectedBytes, HMACAlgorithm.getSecretBytes(text)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java index 9c528f68..f4946dfa 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java @@ -8,7 +8,7 @@ import org.junit.rules.ExpectedException; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; public class NoneAlgorithmTest { diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java index a4902781..d7a062af 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java @@ -17,7 +17,7 @@ import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -25,7 +25,6 @@ import static org.mockito.Mockito.when; import static com.auth0.jwt.algorithms.CryptoTestHelper.*; -@SuppressWarnings("deprecation") public class RSAAlgorithmTest { private static final String PRIVATE_KEY_FILE = "src/test/resources/rsa-private.pem"; diff --git a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java b/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java index 87cc9800..faa48948 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java @@ -7,7 +7,7 @@ import java.util.Map; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; public class ClaimsHolderTest { diff --git a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java index dffcab50..fce6b26b 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java @@ -23,7 +23,7 @@ import java.util.Map; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java index 84d0be4b..430490a4 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java @@ -27,7 +27,7 @@ import static org.hamcrest.Matchers.*; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class JsonNodeClaimTest { diff --git a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java index b15f3dad..8cca7b53 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java @@ -5,7 +5,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; public class NullClaimTest { private NullClaim claim; diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 9a82878e..5d44216e 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -22,7 +22,7 @@ import java.util.*; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java index 3ebc29dd..d990978d 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java @@ -12,7 +12,7 @@ import java.util.*; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; public class PayloadSerializerTest { From 0b2331bf08db796760669ca1a14503c373c3a0c9 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Tue, 1 Mar 2022 07:20:18 -0600 Subject: [PATCH 002/134] Remove apiDiff check for v4 development --- .circleci/config.yml | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b649d2fc..a299cb9d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,15 +23,15 @@ commands: name: Upload Coverage when: on_success command: bash <(curl -s https://codecov.io/bash) -Z -C $CIRCLE_SHA1 - run-api-diff: - steps: - # run apiDiff task - - run: ./gradlew apiDiff - - store_artifacts: - path: lib/build/reports/apiDiff/apiDiff.txt - - store_artifacts: - path: lib/build/reports/apiDiff/apiDiff.html - +# TODO re-enable once 4.0.0 is released +# run-api-diff: +# steps: +# # run apiDiff task +# - run: ./gradlew apiDiff +# - store_artifacts: +# path: lib/build/reports/apiDiff/apiDiff.txt +# - store_artifacts: +# path: lib/build/reports/apiDiff/apiDiff.html jobs: build: docker: @@ -43,21 +43,21 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms512m -Xmx1024m" TERM: dumb - api-diff: - docker: - - image: openjdk:11.0-jdk - steps: - - checkout-and-build - - run-api-diff - environment: - GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - TERM: dumb +# api-diff: +# docker: +# - image: openjdk:11.0-jdk +# steps: +# - checkout-and-build +# - run-api-diff +# environment: +# GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' +# _JAVA_OPTIONS: "-Xms512m -Xmx1024m" +# TERM: dumb workflows: build-and-test: jobs: - build - api-diff: - jobs: - - api-diff +# api-diff: +# jobs: +# - api-diff \ No newline at end of file From 1ccecd40417bb7e4da9cf94aa612a8ad4d0086fa Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 2 Mar 2022 12:27:18 -0600 Subject: [PATCH 003/134] [SDK-3160] Replace com.auth0.jwt.interfaces.Clock with java.time.Clock (#532) --- .../main/java/com/auth0/jwt/JWTVerifier.java | 9 +- lib/src/test/java/com/auth0/jwt/JWTTest.java | 28 +++---- .../java/com/auth0/jwt/JWTVerifierTest.java | 83 +++++-------------- 3 files changed, 38 insertions(+), 82 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 17f182c2..9a7ea2b2 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -6,12 +6,11 @@ import com.auth0.jwt.impl.NullClaim; import com.auth0.jwt.impl.PublicClaims; import com.auth0.jwt.interfaces.Claim; -import com.auth0.jwt.interfaces.Clock; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; import java.util.*; -import java.util.stream.Collectors; +import java.time.Clock; /** * The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, but also its signature matches. @@ -200,7 +199,7 @@ public Verification withArrayClaim(String name, Long... items) throws IllegalArg @Override public JWTVerifier build() { - return this.build(new ClockImpl()); + return this.build(Clock.systemUTC()); } /** @@ -208,7 +207,7 @@ public JWTVerifier build() { * ONLY FOR TEST PURPOSES. * * @param clock the instance that will handle the current time. - * @return a new JWTVerifier instance with a custom Clock. + * @return a new JWTVerifier instance with a custom {@link java.time.Clock} */ public JWTVerifier build(Clock clock) { addLeewayToDateClaims(); @@ -405,7 +404,7 @@ private void assertValidStringClaim(String claimName, String value, String expec } private void assertValidDateClaim(Date date, long leeway, boolean shouldBeFuture) { - Date today = new Date(clock.getToday().getTime()); + Date today = new Date(clock.millis()); today.setTime(today.getTime() / 1000 * 1000); // truncate millis if (shouldBeFuture) { assertDateIsFuture(date, leeway, today); diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index 6004e142..20bb384b 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -1,7 +1,6 @@ package com.auth0.jwt; import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.interfaces.Clock; import com.auth0.jwt.interfaces.DecodedJWT; import org.hamcrest.collection.IsCollectionWithSize; import org.hamcrest.core.IsCollectionContaining; @@ -14,6 +13,9 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAKey; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; import java.util.Base64; import java.util.Date; @@ -36,7 +38,6 @@ public class JWTTest { private static final String PRIVATE_KEY_FILE_EC_384 = "src/test/resources/ec384-key-private.pem"; private static final String PRIVATE_KEY_FILE_EC_512 = "src/test/resources/ec512-key-private.pem"; - @Rule public ExpectedException exception = ExpectedException.none(); @@ -274,9 +275,8 @@ public void shouldGetStringAudience() throws Exception { @Test public void shouldGetExpirationTime() throws Exception { - Date expectedDate = new Date(1477592 * 1000); - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(expectedDate); + long seconds = 1477592L; + Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); String token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0Nzc1OTJ9.x_ZjkPkKYUV5tdvc0l8go6D_z2kez1MQcOxokXrDc3k"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); @@ -287,14 +287,13 @@ public void shouldGetExpirationTime() throws Exception { assertThat(jwt, is(notNullValue())); assertThat(jwt.getExpiresAt(), is(instanceOf(Date.class))); assertThat(jwt.getExpiresAt(), is(notNullValue())); - assertThat(jwt.getExpiresAt(), is(equalTo(expectedDate))); + assertThat(jwt.getExpiresAt(), is(equalTo(new Date(seconds * 1000)))); } @Test - public void shouldGetNotBefore() throws Exception { - Date expectedDate = new Date(1477592 * 1000); - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(expectedDate); + public void shouldGetNotBefore() { + long seconds = 1477592; + Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTJ9.mWYSOPoNXstjKbZkKrqgkwPOQWEx3F3gMm6PMcfuJd8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); @@ -305,14 +304,13 @@ public void shouldGetNotBefore() throws Exception { assertThat(jwt, is(notNullValue())); assertThat(jwt.getNotBefore(), is(instanceOf(Date.class))); assertThat(jwt.getNotBefore(), is(notNullValue())); - assertThat(jwt.getNotBefore(), is(equalTo(expectedDate))); + assertThat(jwt.getNotBefore(), is(equalTo(new Date(seconds * 1000)))); } @Test public void shouldGetIssuedAt() throws Exception { - Date expectedDate = new Date(1477592 * 1000); - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(expectedDate); + long seconds = 1477592; + Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); String token = "eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.5o1CKlLFjKKcddZzoarQ37pq7qZqNPav3sdZ_bsZaD4"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); @@ -323,7 +321,7 @@ public void shouldGetIssuedAt() throws Exception { assertThat(jwt, is(notNullValue())); assertThat(jwt.getIssuedAt(), is(instanceOf(Date.class))); assertThat(jwt.getIssuedAt(), is(notNullValue())); - assertThat(jwt.getIssuedAt(), is(equalTo(expectedDate))); + assertThat(jwt.getIssuedAt(), is(equalTo(new Date(seconds * 1000)))); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 99e8b104..48b0ab4f 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -4,13 +4,16 @@ import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.InvalidClaimException; import com.auth0.jwt.exceptions.TokenExpiredException; -import com.auth0.jwt.interfaces.Clock; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -23,7 +26,10 @@ public class JWTVerifierTest { - private static final long DATE_TOKEN_MS_VALUE = 1477592 * 1000; + private Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); + private Clock mockOneSecondEarlier = Clock.offset(mockNow, Duration.ofSeconds(-1)); + private Clock mockOneSecondLater = Clock.offset(mockNow, Duration.ofSeconds(1)); + @Rule public ExpectedException exception = ExpectedException.none(); @@ -450,7 +456,7 @@ public void shouldThrowOnInvalidCustomClaimValue() throws Exception { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; Map map = new HashMap<>(); map.put("name", new Object()); - JWTVerifier verifier = new JWTVerifier(Algorithm.HMAC256("secret"), map, new ClockImpl()); + JWTVerifier verifier = new JWTVerifier(Algorithm.HMAC256("secret"), map, Clock.systemUTC()); verifier.verify(token); } @@ -658,48 +664,25 @@ public void shouldThrowOnNegativeCustomLeeway() throws Exception { .acceptLeeway(-1); } - @Test - public void shouldNotModifyOriginalClockDateWhenVerifying() throws Exception { - Clock clock = mock(Clock.class); - Date clockDate = spy(new Date(DATE_TOKEN_MS_VALUE)); - when(clock.getToday()).thenReturn(clockDate); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - JWTVerifier verifier = verification - .build(clock); - - DecodedJWT jwt = verifier.verify(token); - assertThat(jwt, is(notNullValue())); - - verify(clockDate, never()).setTime(anyLong()); - } - // Expires At @Test public void shouldValidateExpiresAtWithLeeway() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE + 1000)); - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) .acceptExpiresAt(2); DecodedJWT jwt = verification - .build(clock) + .build(mockOneSecondLater) .verify(token); assertThat(jwt, is(notNullValue())); } @Test - public void shouldValidateExpiresAtIfPresent() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE)); - + public void shouldValidateExpiresAtIfPresent() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification - .build(clock) + .build(mockNow) .verify(token); assertThat(jwt, is(notNullValue())); @@ -709,13 +692,11 @@ public void shouldValidateExpiresAtIfPresent() throws Exception { public void shouldThrowOnInvalidExpiresAtIfPresent() throws Exception { exception.expect(TokenExpiredException.class); exception.expectMessage(startsWith("The Token has expired on")); - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE + 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); verification - .build(clock) + .build(mockOneSecondLater) .verify(token); } @@ -731,14 +712,11 @@ public void shouldThrowOnNegativeExpiresAtLeeway() throws Exception { // Not before @Test public void shouldValidateNotBeforeWithLeeway() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) .acceptNotBefore(2); DecodedJWT jwt = verification - .build(clock) + .build(mockOneSecondEarlier) .verify(token); assertThat(jwt, is(notNullValue())); @@ -748,25 +726,20 @@ public void shouldValidateNotBeforeWithLeeway() throws Exception { public void shouldThrowOnInvalidNotBeforeIfPresent() throws Exception { exception.expect(InvalidClaimException.class); exception.expectMessage(startsWith("The Token can't be used before")); - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); verification - .build(clock) + .build(mockOneSecondEarlier) .verify(token); } @Test public void shouldValidateNotBeforeIfPresent() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE)); - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification - .build(clock) + .build(mockNow) .verify(token); assertThat(jwt, is(notNullValue())); @@ -784,27 +757,21 @@ public void shouldThrowOnNegativeNotBeforeLeeway() throws Exception { // Issued At with future date @Test(expected = InvalidClaimException.class) public void shouldThrowOnFutureIssuedAt() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification.build(clock).verify(token); + DecodedJWT jwt = verification.build(mockOneSecondEarlier).verify(token); assertThat(jwt, is(notNullValue())); } // Issued At with future date and ignore flag @Test public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); verification.ignoreIssuedAt(); - DecodedJWT jwt = verification.build(clock).verify(token); + DecodedJWT jwt = verification.build(mockOneSecondEarlier).verify(token); assertThat(jwt, is(notNullValue())); } @@ -812,27 +779,22 @@ public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() throws Exception { public void shouldThrowOnInvalidIssuedAtIfPresent() throws Exception { exception.expect(InvalidClaimException.class); exception.expectMessage(startsWith("The Token can't be used before")); - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); verification - .build(clock) + .build(mockOneSecondEarlier) .verify(token); } @Test public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVerification() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 10000)); - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) .acceptIssuedAt(1) .ignoreIssuedAt(); DecodedJWT jwt = verification - .build(clock) + .build(mockOneSecondEarlier) .verify(token); assertThat(jwt, is(notNullValue())); @@ -840,13 +802,10 @@ public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVe @Test public void shouldValidateIssuedAtIfPresent() throws Exception { - Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE)); - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification - .build(clock) + .build(mockNow) .verify(token); assertThat(jwt, is(notNullValue())); From 1697ccb886268a0038514a97b0430d2c07538144 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 3 Mar 2022 10:36:47 -0600 Subject: [PATCH 004/134] remove unneccesary throws clause from tests (#535) --- .../com/auth0/jwt/ConcurrentVerifyTest.java | 6 +- .../java/com/auth0/jwt/JWTCreatorTest.java | 76 +++++------ .../java/com/auth0/jwt/JWTDecoderTest.java | 64 ++++----- lib/src/test/java/com/auth0/jwt/JWTTest.java | 48 +++---- .../java/com/auth0/jwt/JWTVerifierTest.java | 125 +++++++++--------- .../java/com/auth0/jwt/TokenUtilsTest.java | 8 +- .../auth0/jwt/algorithms/AlgorithmTest.java | 120 ++++++++--------- .../jwt/algorithms/ECDSAAlgorithmTest.java | 20 +-- .../ECDSABouncyCastleProviderTests.java | 24 ++-- .../jwt/algorithms/HMACAlgorithmTest.java | 36 ++--- .../jwt/algorithms/NoneAlgorithmTest.java | 8 +- .../jwt/algorithms/RSAAlgorithmTest.java | 19 ++- .../com/auth0/jwt/impl/BasicHeaderTest.java | 26 ++-- .../com/auth0/jwt/impl/ClaimsHolderTest.java | 4 +- .../jwt/impl/HeaderDeserializerTest.java | 8 +- .../com/auth0/jwt/impl/JWTParserTest.java | 18 +-- .../com/auth0/jwt/impl/JsonNodeClaimTest.java | 80 +++++------ .../com/auth0/jwt/impl/NullClaimTest.java | 24 ++-- .../jwt/impl/PayloadDeserializerTest.java | 30 ++--- .../com/auth0/jwt/impl/PayloadImplTest.java | 42 +++--- 20 files changed, 393 insertions(+), 393 deletions(-) diff --git a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java index f4de1f71..02666222 100644 --- a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java +++ b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java @@ -38,12 +38,12 @@ public class ConcurrentVerifyTest { private static ExecutorService executor; @BeforeClass - public static void beforeAll() throws Exception { + public static void beforeAll() { executor = Executors.newFixedThreadPool(THREAD_COUNT); } @AfterClass - public static void afterAll() throws Exception { + public static void afterAll() { executor.shutdown(); } @@ -68,7 +68,7 @@ private static class VerifyTask implements Callable { } @Override - public DecodedJWT call() throws Exception { + public DecodedJWT call() { DecodedJWT jwt = null; try { jwt = verifier.verify(token); diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 0cbafc35..2a8812bd 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -31,7 +31,7 @@ public class JWTCreatorTest { public ExpectedException exception = ExpectedException.none(); @Test - public void shouldThrowWhenRequestingSignWithoutAlgorithm() throws Exception { + public void shouldThrowWhenRequestingSignWithoutAlgorithm() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Algorithm cannot be null"); JWTCreator.init() @@ -40,7 +40,7 @@ public void shouldThrowWhenRequestingSignWithoutAlgorithm() throws Exception { @SuppressWarnings("Convert2Diamond") @Test - public void shouldAddHeaderClaim() throws Exception { + public void shouldAddHeaderClaim() { Map header = new HashMap(); header.put("asd", 123); String signed = JWTCreator.init() @@ -54,7 +54,7 @@ public void shouldAddHeaderClaim() throws Exception { } @Test - public void shouldReturnBuilderIfNullMapIsProvided() throws Exception { + public void shouldReturnBuilderIfNullMapIsProvided() { String signed = JWTCreator.init() .withHeader(null) .sign(Algorithm.HMAC256("secret")); @@ -63,7 +63,7 @@ public void shouldReturnBuilderIfNullMapIsProvided() throws Exception { } @Test - public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws Exception { + public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { Map header = new HashMap(); header.put(PublicClaims.KEY_ID, "xyz"); @@ -79,7 +79,7 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws } @Test - public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() throws Exception { + public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { Map header = new HashMap(); header.put(PublicClaims.KEY_ID, "xyz"); @@ -95,7 +95,7 @@ public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() throws Exce } @Test - public void shouldRemoveHeaderIfTheValueIsNull() throws Exception { + public void shouldRemoveHeaderIfTheValueIsNull() { Map header = new HashMap(); header.put(PublicClaims.KEY_ID, null); header.put("test2", "isSet"); @@ -113,7 +113,7 @@ public void shouldRemoveHeaderIfTheValueIsNull() throws Exception { } @Test - public void shouldAddKeyId() throws Exception { + public void shouldAddKeyId() { String signed = JWTCreator.init() .withKeyId("56a8bd44da435300010000015f5ed") .sign(Algorithm.HMAC256("secret")); @@ -224,7 +224,7 @@ public void shouldNotOverwriteKeyIdIfAddedFromECDSAAlgorithms() throws Exception } @Test - public void shouldAddIssuer() throws Exception { + public void shouldAddIssuer() { String signed = JWTCreator.init() .withIssuer("auth0") .sign(Algorithm.HMAC256("secret")); @@ -234,7 +234,7 @@ public void shouldAddIssuer() throws Exception { } @Test - public void shouldAddSubject() throws Exception { + public void shouldAddSubject() { String signed = JWTCreator.init() .withSubject("1234567890") .sign(Algorithm.HMAC256("secret")); @@ -244,7 +244,7 @@ public void shouldAddSubject() throws Exception { } @Test - public void shouldAddAudience() throws Exception { + public void shouldAddAudience() { String signed = JWTCreator.init() .withAudience("Mark") .sign(Algorithm.HMAC256("secret")); @@ -262,7 +262,7 @@ public void shouldAddAudience() throws Exception { } @Test - public void shouldAddExpiresAt() throws Exception { + public void shouldAddExpiresAt() { String signed = JWTCreator.init() .withExpiresAt(new Date(1477592000)) .sign(Algorithm.HMAC256("secret")); @@ -272,7 +272,7 @@ public void shouldAddExpiresAt() throws Exception { } @Test - public void shouldAddNotBefore() throws Exception { + public void shouldAddNotBefore() { String signed = JWTCreator.init() .withNotBefore(new Date(1477592000)) .sign(Algorithm.HMAC256("secret")); @@ -282,7 +282,7 @@ public void shouldAddNotBefore() throws Exception { } @Test - public void shouldAddIssuedAt() throws Exception { + public void shouldAddIssuedAt() { String signed = JWTCreator.init() .withIssuedAt(new Date(1477592000)) .sign(Algorithm.HMAC256("secret")); @@ -292,7 +292,7 @@ public void shouldAddIssuedAt() throws Exception { } @Test - public void shouldAddJWTId() throws Exception { + public void shouldAddJWTId() { String signed = JWTCreator.init() .withJWTId("jwt_id_123") .sign(Algorithm.HMAC256("secret")); @@ -302,7 +302,7 @@ public void shouldAddJWTId() throws Exception { } @Test - public void shouldRemoveClaimWhenPassingNull() throws Exception { + public void shouldRemoveClaimWhenPassingNull() { String signed = JWTCreator.init() .withIssuer("iss") .withIssuer(null) @@ -313,7 +313,7 @@ public void shouldRemoveClaimWhenPassingNull() throws Exception { } @Test - public void shouldSetCorrectAlgorithmInTheHeader() throws Exception { + public void shouldSetCorrectAlgorithmInTheHeader() { String signed = JWTCreator.init() .sign(Algorithm.HMAC256("secret")); @@ -324,7 +324,7 @@ public void shouldSetCorrectAlgorithmInTheHeader() throws Exception { } @Test - public void shouldSetDefaultTypeInTheHeader() throws Exception { + public void shouldSetDefaultTypeInTheHeader() { String signed = JWTCreator.init() .sign(Algorithm.HMAC256("secret")); @@ -335,7 +335,7 @@ public void shouldSetDefaultTypeInTheHeader() throws Exception { } @Test - public void shouldSetCustomTypeInTheHeader() throws Exception { + public void shouldSetCustomTypeInTheHeader() { Map header = Collections.singletonMap("typ", "passport"); String signed = JWTCreator.init() .withHeader(header) @@ -348,7 +348,7 @@ public void shouldSetCustomTypeInTheHeader() throws Exception { } @Test - public void shouldSetEmptySignatureIfAlgorithmIsNone() throws Exception { + public void shouldSetEmptySignatureIfAlgorithmIsNone() { String signed = JWTCreator.init() .sign(Algorithm.none()); assertThat(signed, is(notNullValue())); @@ -356,7 +356,7 @@ public void shouldSetEmptySignatureIfAlgorithmIsNone() throws Exception { } @Test - public void shouldThrowOnNullCustomClaimName() throws Exception { + public void shouldThrowOnNullCustomClaimName() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Custom Claim's name can't be null."); JWTCreator.init() @@ -364,7 +364,7 @@ public void shouldThrowOnNullCustomClaimName() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeString() throws Exception { + public void shouldAcceptCustomClaimOfTypeString() { String jwt = JWTCreator.init() .withClaim("name", "value") .sign(Algorithm.HMAC256("secret")); @@ -375,7 +375,7 @@ public void shouldAcceptCustomClaimOfTypeString() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeInteger() throws Exception { + public void shouldAcceptCustomClaimOfTypeInteger() { String jwt = JWTCreator.init() .withClaim("name", 123) .sign(Algorithm.HMAC256("secret")); @@ -386,7 +386,7 @@ public void shouldAcceptCustomClaimOfTypeInteger() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeLong() throws Exception { + public void shouldAcceptCustomClaimOfTypeLong() { String jwt = JWTCreator.init() .withClaim("name", Long.MAX_VALUE) .sign(Algorithm.HMAC256("secret")); @@ -397,7 +397,7 @@ public void shouldAcceptCustomClaimOfTypeLong() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeDouble() throws Exception { + public void shouldAcceptCustomClaimOfTypeDouble() { String jwt = JWTCreator.init() .withClaim("name", 23.45) .sign(Algorithm.HMAC256("secret")); @@ -408,7 +408,7 @@ public void shouldAcceptCustomClaimOfTypeDouble() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeBoolean() throws Exception { + public void shouldAcceptCustomClaimOfTypeBoolean() { String jwt = JWTCreator.init() .withClaim("name", true) .sign(Algorithm.HMAC256("secret")); @@ -419,7 +419,7 @@ public void shouldAcceptCustomClaimOfTypeBoolean() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeDate() throws Exception { + public void shouldAcceptCustomClaimOfTypeDate() { Date date = new Date(1478891521000L); String jwt = JWTCreator.init() .withClaim("name", date) @@ -431,7 +431,7 @@ public void shouldAcceptCustomClaimOfTypeDate() throws Exception { } @Test - public void shouldAcceptCustomArrayClaimOfTypeString() throws Exception { + public void shouldAcceptCustomArrayClaimOfTypeString() { String jwt = JWTCreator.init() .withArrayClaim("name", new String[]{"text", "123", "true"}) .sign(Algorithm.HMAC256("secret")); @@ -442,7 +442,7 @@ public void shouldAcceptCustomArrayClaimOfTypeString() throws Exception { } @Test - public void shouldAcceptCustomArrayClaimOfTypeInteger() throws Exception { + public void shouldAcceptCustomArrayClaimOfTypeInteger() { String jwt = JWTCreator.init() .withArrayClaim("name", new Integer[]{1, 2, 3}) .sign(Algorithm.HMAC256("secret")); @@ -453,7 +453,7 @@ public void shouldAcceptCustomArrayClaimOfTypeInteger() throws Exception { } @Test - public void shouldAcceptCustomArrayClaimOfTypeLong() throws Exception { + public void shouldAcceptCustomArrayClaimOfTypeLong() { String jwt = JWTCreator.init() .withArrayClaim("name", new Long[]{1L, 2L, 3L}) .sign(Algorithm.HMAC256("secret")); @@ -464,7 +464,7 @@ public void shouldAcceptCustomArrayClaimOfTypeLong() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeMap() throws Exception { + public void shouldAcceptCustomClaimOfTypeMap() { Map data = new HashMap<>(); data.put("test1", "abc"); data.put("test2", "def"); @@ -478,7 +478,7 @@ public void shouldAcceptCustomClaimOfTypeMap() throws Exception { } @Test - public void shouldRefuseCustomClaimOfTypeUserPojo() throws Exception { + public void shouldRefuseCustomClaimOfTypeUserPojo() { Map data = new HashMap<>(); data.put("test1", new UserPojo("Michael", 255)); @@ -598,7 +598,7 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { } @Test - public void shouldAcceptCustomClaimForNullListItem() throws Exception { + public void shouldAcceptCustomClaimForNullListItem() { Map data = new HashMap<>(); data.put("test1", Arrays.asList("a", null, "c")); @@ -642,7 +642,7 @@ public void shouldAcceptCustomClaimWithNullListAndRemoveClaim() throws Exception } @Test - public void shouldRefuseCustomClaimForNullMapValue() throws Exception { + public void shouldRefuseCustomClaimForNullMapValue() { Map data = new HashMap<>(); data.put("subKey", null); @@ -654,7 +654,7 @@ public void shouldRefuseCustomClaimForNullMapValue() throws Exception { } @Test - public void shouldRefuseCustomClaimForNullMapKey() throws Exception { + public void shouldRefuseCustomClaimForNullMapKey() { Map data = new HashMap<>(); data.put(null, "subValue"); @@ -667,7 +667,7 @@ public void shouldRefuseCustomClaimForNullMapKey() throws Exception { @SuppressWarnings({"unchecked", "rawtypes"}) @Test - public void shouldRefuseCustomMapClaimForNonStringKey() throws Exception { + public void shouldRefuseCustomMapClaimForNonStringKey() { Map data = new HashMap<>(); data.put(new Object(), "value"); @@ -679,7 +679,7 @@ public void shouldRefuseCustomMapClaimForNonStringKey() throws Exception { } @Test - public void shouldRefuseCustomListClaimForUnknownListElement() throws Exception { + public void shouldRefuseCustomListClaimForUnknownListElement() { List list = Arrays.asList(new UserPojo("Michael", 255)); exception.expect(IllegalArgumentException.class); @@ -690,7 +690,7 @@ public void shouldRefuseCustomListClaimForUnknownListElement() throws Exception } @Test - public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() throws Exception { + public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() { List list = Arrays.asList(new UserPojo("Michael", 255)); Map data = new HashMap<>(); @@ -704,7 +704,7 @@ public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() thro } @Test - public void shouldRefuseCustomListClaimForUnknownArrayType() throws Exception { + public void shouldRefuseCustomListClaimForUnknownArrayType() { List list = new ArrayList<>(); list.add(new Object[]{"test"}); diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 77ac4d18..536c2dbb 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -24,7 +24,7 @@ public class JWTDecoderTest { public ExpectedException exception = ExpectedException.none(); @Test - public void getSubject() throws Exception { + public void getSubject() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"); assertThat(jwt.getSubject(), is(notNullValue())); assertThat(jwt.getSubject(), is("1234567890")); @@ -32,7 +32,7 @@ public void getSubject() throws Exception { // Exceptions @Test - public void shouldThrowIfTheContentIsNotProperlyEncoded() throws Exception { + public void shouldThrowIfTheContentIsNotProperlyEncoded() { exception.expect(JWTDecodeException.class); exception.expectMessage(startsWith("The string '")); exception.expectMessage(endsWith("' doesn't have a valid JSON format.")); @@ -40,21 +40,21 @@ public void shouldThrowIfTheContentIsNotProperlyEncoded() throws Exception { } @Test - public void shouldThrowIfLessThan3Parts() throws Exception { + public void shouldThrowIfLessThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 2."); JWT.decode("two.parts"); } @Test - public void shouldThrowIfMoreThan3Parts() throws Exception { + public void shouldThrowIfMoreThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 4."); JWT.decode("this.has.four.parts"); } @Test - public void shouldThrowIfPayloadHasInvalidJSONFormat() throws Exception { + public void shouldThrowIfPayloadHasInvalidJSONFormat() { String validJson = "{}"; String invalidJson = "}{"; exception.expect(JWTDecodeException.class); @@ -63,7 +63,7 @@ public void shouldThrowIfPayloadHasInvalidJSONFormat() throws Exception { } @Test - public void shouldThrowIfHeaderHasInvalidJSONFormat() throws Exception { + public void shouldThrowIfHeaderHasInvalidJSONFormat() { String validJson = "{}"; String invalidJson = "}{"; exception.expect(JWTDecodeException.class); @@ -92,7 +92,7 @@ public void shouldThrowWhenPayloadNotValidBase64() { // Parts @Test - public void shouldGetStringToken() throws Exception { + public void shouldGetStringToken() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getToken(), is(notNullValue())); @@ -100,21 +100,21 @@ public void shouldGetStringToken() throws Exception { } @Test - public void shouldGetHeader() throws Exception { + public void shouldGetHeader() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getHeader(), is("eyJhbGciOiJIUzI1NiJ9")); } @Test - public void shouldGetPayload() throws Exception { + public void shouldGetPayload() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getPayload(), is("e30")); } @Test - public void shouldGetSignature() throws Exception { + public void shouldGetSignature() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getSignature(), is("XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); @@ -123,21 +123,21 @@ public void shouldGetSignature() throws Exception { // Public PublicClaims @Test - public void shouldGetIssuer() throws Exception { + public void shouldGetIssuer() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIERvZSJ9.SgXosfRR_IwCgHq5lF3tlM-JHtpucWCRSaVuoHTbWbQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getIssuer(), is("John Doe")); } @Test - public void shouldGetSubject() throws Exception { + public void shouldGetSubject() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJUb2szbnMifQ.RudAxkslimoOY3BLl2Ghny3BrUKu9I1ZrXzCZGDJtNs"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getSubject(), is("Tok3ns")); } @Test - public void shouldGetArrayAudience() throws Exception { + public void shouldGetArrayAudience() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(3))); @@ -145,7 +145,7 @@ public void shouldGetArrayAudience() throws Exception { } @Test - public void shouldGetStringAudience() throws Exception { + public void shouldGetStringAudience() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(1))); @@ -153,7 +153,7 @@ public void shouldGetStringAudience() throws Exception { } @Test - public void shouldGetExpirationTime() throws Exception { + public void shouldGetExpirationTime() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzY3MjcwODZ9.L9dcPHEDQew2u9MkDCORFkfDGcSOsgoPqNY-LUMLEHg"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getExpiresAt(), is(instanceOf(Date.class))); @@ -164,7 +164,7 @@ public void shouldGetExpirationTime() throws Exception { } @Test - public void shouldGetNotBefore() throws Exception { + public void shouldGetNotBefore() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0NzY3MjcwODZ9.tkpD3iCPQPVqjnjpDVp2bJMBAgpVCG9ZjlBuMitass0"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getNotBefore(), is(instanceOf(Date.class))); @@ -175,7 +175,7 @@ public void shouldGetNotBefore() throws Exception { } @Test - public void shouldGetIssuedAt() throws Exception { + public void shouldGetIssuedAt() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NzY3MjcwODZ9.KPjGoW665E8V5_27Jugab8qSTxLk2cgquhPCBfAP0_w"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getIssuedAt(), is(instanceOf(Date.class))); @@ -186,28 +186,28 @@ public void shouldGetIssuedAt() throws Exception { } @Test - public void shouldGetId() throws Exception { + public void shouldGetId() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTY3ODkwIn0.m3zgEfVUFOd-CvL3xG5BuOWLzb0zMQZCqiVNQQOPOvA"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getId(), is("1234567890")); } @Test - public void shouldGetContentType() throws Exception { + public void shouldGetContentType() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsImN0eSI6ImF3ZXNvbWUifQ.e30.AIm-pJDOaAyct9qKMlN-lQieqNDqc3d4erqUZc5SHAs"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getContentType(), is("awesome")); } @Test - public void shouldGetType() throws Exception { + public void shouldGetType() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.e30.WdFmrzx8b9v_a-r6EHC2PTAaWywgm_8LiP8RBRhYwkI"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getType(), is("JWS")); } @Test - public void shouldGetAlgorithm() throws Exception { + public void shouldGetAlgorithm() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAlgorithm(), is("HS256")); @@ -216,7 +216,7 @@ public void shouldGetAlgorithm() throws Exception { //Private PublicClaims @Test - public void shouldGetMissingClaimIfClaimDoesNotExist() throws Exception { + public void shouldGetMissingClaimIfClaimDoesNotExist() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.K17vlwhE8FCMShdl1_65jEYqsQqBOVMPUU9IgG-QlTM"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("notExisting"), is(notNullValue())); @@ -224,7 +224,7 @@ public void shouldGetMissingClaimIfClaimDoesNotExist() throws Exception { } @Test - public void shouldGetValidClaim() throws Exception { + public void shouldGetValidClaim() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJvYmplY3QiOnsibmFtZSI6ImpvaG4ifX0.lrU1gZlOdlmTTeZwq0VI-pZx2iV46UWYd5-lCjy6-c4"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("object"), is(notNullValue())); @@ -232,7 +232,7 @@ public void shouldGetValidClaim() throws Exception { } @Test - public void shouldNotGetNullClaimIfClaimIsEmptyObject() throws Exception { + public void shouldNotGetNullClaimIfClaimIsEmptyObject() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJvYmplY3QiOnt9fQ.d3nUeeL_69QsrHL0ZWij612LHEQxD8EZg1rNoY3a4aI"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("object"), is(notNullValue())); @@ -240,7 +240,7 @@ public void shouldNotGetNullClaimIfClaimIsEmptyObject() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeInteger() throws Exception { + public void shouldGetCustomClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); @@ -248,7 +248,7 @@ public void shouldGetCustomClaimOfTypeInteger() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeDouble() throws Exception { + public void shouldGetCustomClaimOfTypeDouble() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); @@ -256,7 +256,7 @@ public void shouldGetCustomClaimOfTypeDouble() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeBoolean() throws Exception { + public void shouldGetCustomClaimOfTypeBoolean() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); @@ -264,7 +264,7 @@ public void shouldGetCustomClaimOfTypeBoolean() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeDate() throws Exception { + public void shouldGetCustomClaimOfTypeDate() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; Date date = new Date(1478891521000L); DecodedJWT jwt = JWT.decode(token); @@ -273,7 +273,7 @@ public void shouldGetCustomClaimOfTypeDate() throws Exception { } @Test - public void shouldGetCustomArrayClaimOfTypeString() throws Exception { + public void shouldGetCustomArrayClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); @@ -281,7 +281,7 @@ public void shouldGetCustomArrayClaimOfTypeString() throws Exception { } @Test - public void shouldGetCustomArrayClaimOfTypeInteger() throws Exception { + public void shouldGetCustomArrayClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); @@ -289,7 +289,7 @@ public void shouldGetCustomArrayClaimOfTypeInteger() throws Exception { } @Test - public void shouldGetCustomMapClaim() throws Exception { + public void shouldGetCustomMapClaim() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjp7InN0cmluZyI6InZhbHVlIiwibnVtYmVyIjoxLCJib29sZWFuIjp0cnVlfX0.-8aIaXd2-rp1lLuDEQmCeisCBX9X_zbqdPn2llGxNoc"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); @@ -300,7 +300,7 @@ public void shouldGetCustomMapClaim() throws Exception { } @Test - public void shouldGetAvailableClaims() throws Exception { + public void shouldGetAvailableClaims() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsImlhdCI6MTIzNDU2Nzg5MCwibmJmIjoxMjM0NTY3ODkwLCJqdGkiOiJodHRwczovL2p3dC5pby8iLCJhdWQiOiJodHRwczovL2RvbWFpbi5hdXRoMC5jb20iLCJzdWIiOiJsb2dpbiIsImlzcyI6ImF1dGgwIiwiZXh0cmFDbGFpbSI6IkpvaG4gRG9lIn0.2_0nxDPJwOk64U5V5V9pt8U92jTPJbGsHYQ35HYhbdE"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaims(), is(notNullValue())); diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index 20bb384b..bf7e07da 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -44,7 +44,7 @@ public class JWTTest { // Decode @Test - public void shouldDecodeAStringToken() throws Exception { + public void shouldDecodeAStringToken() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; DecodedJWT jwt = JWT.decode(token); @@ -52,7 +52,7 @@ public void shouldDecodeAStringToken() throws Exception { } @Test - public void shouldDecodeAStringTokenUsingInstance() throws Exception { + public void shouldDecodeAStringTokenUsingInstance() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; JWT jwt = new JWT(); DecodedJWT decodedJWT = jwt.decodeJwt(token); @@ -62,7 +62,7 @@ public void shouldDecodeAStringTokenUsingInstance() throws Exception { // getToken @Test - public void shouldGetStringToken() throws Exception { + public void shouldGetStringToken() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getToken(), is(notNullValue())); @@ -71,7 +71,7 @@ public void shouldGetStringToken() throws Exception { // getToken @Test - public void shouldGetStringTokenUsingInstance() throws Exception { + public void shouldGetStringTokenUsingInstance() { JWT jwt = new JWT(); DecodedJWT decodedJWT = jwt.decodeJwt("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(decodedJWT, is(notNullValue())); @@ -94,7 +94,7 @@ public void shouldVerifyDecodedToken() throws Exception { } @Test - public void shouldAcceptNoneAlgorithm() throws Exception { + public void shouldAcceptNoneAlgorithm() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; DecodedJWT jwt = JWT.require(Algorithm.none()) .build() @@ -104,7 +104,7 @@ public void shouldAcceptNoneAlgorithm() throws Exception { } @Test - public void shouldAcceptHMAC256Algorithm() throws Exception { + public void shouldAcceptHMAC256Algorithm() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -114,7 +114,7 @@ public void shouldAcceptHMAC256Algorithm() throws Exception { } @Test - public void shouldAcceptHMAC384Algorithm() throws Exception { + public void shouldAcceptHMAC384Algorithm() { String token = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; DecodedJWT jwt = JWT.require(Algorithm.HMAC384("secret")) .build() @@ -124,7 +124,7 @@ public void shouldAcceptHMAC384Algorithm() throws Exception { } @Test - public void shouldAcceptHMAC512Algorithm() throws Exception { + public void shouldAcceptHMAC512Algorithm() { String token = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; DecodedJWT jwt = JWT.require(Algorithm.HMAC512("secret")) .build() @@ -206,7 +206,7 @@ public void shouldAcceptECDSA512Algorithm() throws Exception { // Public Claims @Test - public void shouldGetAlgorithm() throws Exception { + public void shouldGetAlgorithm() { String token = "eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -217,7 +217,7 @@ public void shouldGetAlgorithm() throws Exception { } @Test - public void shouldGetSignature() throws Exception { + public void shouldGetSignature() { String token = "eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -228,7 +228,7 @@ public void shouldGetSignature() throws Exception { } @Test - public void shouldGetIssuer() throws Exception { + public void shouldGetIssuer() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIERvZSJ9.SgXosfRR_IwCgHq5lF3tlM-JHtpucWCRSaVuoHTbWbQ"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -239,7 +239,7 @@ public void shouldGetIssuer() throws Exception { } @Test - public void shouldGetSubject() throws Exception { + public void shouldGetSubject() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJUb2szbnMifQ.RudAxkslimoOY3BLl2Ghny3BrUKu9I1ZrXzCZGDJtNs"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -250,7 +250,7 @@ public void shouldGetSubject() throws Exception { } @Test - public void shouldGetArrayAudience() throws Exception { + public void shouldGetArrayAudience() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -262,7 +262,7 @@ public void shouldGetArrayAudience() throws Exception { } @Test - public void shouldGetStringAudience() throws Exception { + public void shouldGetStringAudience() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -274,7 +274,7 @@ public void shouldGetStringAudience() throws Exception { } @Test - public void shouldGetExpirationTime() throws Exception { + public void shouldGetExpirationTime() { long seconds = 1477592L; Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); @@ -308,7 +308,7 @@ public void shouldGetNotBefore() { } @Test - public void shouldGetIssuedAt() throws Exception { + public void shouldGetIssuedAt() { long seconds = 1477592; Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); @@ -325,7 +325,7 @@ public void shouldGetIssuedAt() throws Exception { } @Test - public void shouldGetId() throws Exception { + public void shouldGetId() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTY3ODkwIn0.m3zgEfVUFOd-CvL3xG5BuOWLzb0zMQZCqiVNQQOPOvA"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification @@ -337,7 +337,7 @@ public void shouldGetId() throws Exception { } @Test - public void shouldGetContentType() throws Exception { + public void shouldGetContentType() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6ImF3ZXNvbWUifQ.e30.AIm-pJDOaAyct9qKMlN-lQieqNDqc3d4erqUZc5SHAs"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -348,7 +348,7 @@ public void shouldGetContentType() throws Exception { } @Test - public void shouldGetType() throws Exception { + public void shouldGetType() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.e30.WdFmrzx8b9v_a-r6EHC2PTAaWywgm_8LiP8RBRhYwkI"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -359,7 +359,7 @@ public void shouldGetType() throws Exception { } @Test - public void shouldGetKeyId() throws Exception { + public void shouldGetKeyId() { String token = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleSJ9.e30.von1Vt9tq9cn5ZYdX1f4cf2EE7fUvb5BCBlKOTm9YWs"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -370,7 +370,7 @@ public void shouldGetKeyId() throws Exception { } @Test - public void shouldGetCustomClaims() throws Exception { + public void shouldGetCustomClaims() { String token = "eyJhbGciOiJIUzI1NiIsImlzQWRtaW4iOnRydWV9.eyJpc0FkbWluIjoibm9wZSJ9.YDKBAgUDbh0PkhioDcLNzdQ8c2Gdf_yS6zdEtJQS3F0"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -386,7 +386,7 @@ public void shouldGetCustomClaims() throws Exception { // Sign @Test - public void shouldCreateAnEmptyHMAC256SignedToken() throws Exception { + public void shouldCreateAnEmptyHMAC256SignedToken() { String signed = JWT.create().sign(Algorithm.HMAC256("secret")); assertThat(signed, is(notNullValue())); @@ -402,7 +402,7 @@ public void shouldCreateAnEmptyHMAC256SignedToken() throws Exception { } @Test - public void shouldCreateAnEmptyHMAC384SignedToken() throws Exception { + public void shouldCreateAnEmptyHMAC384SignedToken() { String signed = JWT.create().sign(Algorithm.HMAC384("secret")); assertThat(signed, is(notNullValue())); @@ -418,7 +418,7 @@ public void shouldCreateAnEmptyHMAC384SignedToken() throws Exception { } @Test - public void shouldCreateAnEmptyHMAC512SignedToken() throws Exception { + public void shouldCreateAnEmptyHMAC512SignedToken() { String signed = JWT.create().sign(Algorithm.HMAC512("secret")); assertThat(signed, is(notNullValue())); diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 48b0ab4f..4a3dbb65 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; +import static org.junit.Assert.assertThrows; public class JWTVerifierTest { @@ -34,14 +35,14 @@ public class JWTVerifierTest { public ExpectedException exception = ExpectedException.none(); @Test - public void shouldThrowWhenInitializedWithoutAlgorithm() throws Exception { + public void shouldThrowWhenInitializedWithoutAlgorithm() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Algorithm cannot be null"); JWTVerifier.init(null); } @Test - public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() throws Exception { + public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() { exception.expect(AlgorithmMismatchException.class); exception.expectMessage("The provided Algorithm doesn't match the one defined in the JWT's Header."); JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC512("secret")).build(); @@ -49,7 +50,7 @@ public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() throws Excep } @Test - public void shouldValidateIssuer() throws Exception { + public void shouldValidateIssuer() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withIssuer("auth0") @@ -72,7 +73,7 @@ public void shouldValidateMultipleIssuers() { } @Test - public void shouldThrowOnInvalidIssuer() throws Exception { + public void shouldThrowOnInvalidIssuer() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'iss' value doesn't match the required issuer."); String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; @@ -83,7 +84,7 @@ public void shouldThrowOnInvalidIssuer() throws Exception { } @Test - public void shouldThrowOnNullIssuer() throws Exception { + public void shouldThrowOnNullIssuer() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'iss' value doesn't match the required issuer."); @@ -95,7 +96,7 @@ public void shouldThrowOnNullIssuer() throws Exception { } @Test - public void shouldValidateSubject() throws Exception { + public void shouldValidateSubject() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withSubject("1234567890") @@ -106,7 +107,7 @@ public void shouldValidateSubject() throws Exception { } @Test - public void shouldThrowOnInvalidSubject() throws Exception { + public void shouldThrowOnInvalidSubject() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'sub' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; @@ -117,7 +118,7 @@ public void shouldThrowOnInvalidSubject() throws Exception { } @Test - public void shouldAcceptAudienceWhenWithAudienceContainsAll() throws Exception { + public void shouldAcceptAudienceWhenWithAudienceContainsAll() { // Token 'aud': ["Mark"] String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJNYXJrIn0.xWB6czYI0XObbVhLAxe55TwChWZg7zO08RxONWU2iY4"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -182,7 +183,7 @@ public void shouldAllowWithAudienceVerificationToOverrideWithAnyOfAudience() { } @Test - public void shouldAcceptAudienceWhenWithAudienceAndPartialExpected() throws Exception { + public void shouldAcceptAudienceWhenWithAudienceAndPartialExpected() { // Token 'aud' = ["Mark", "David", "John"] String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; DecodedJWT jwtArr = JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -212,14 +213,14 @@ public void shouldThrowWhenAudienceHasNoneOfExpectedAnyOfAudience() { // Token 'aud' = ["Mark", "David", "John"] String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - DecodedJWT jwtArr = JWTVerifier.init(Algorithm.HMAC256("secret")) + JWTVerifier.init(Algorithm.HMAC256("secret")) .withAnyOfAudience("Joe", "Jim") .build() .verify(tokenArr); } @Test - public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() throws Exception { + public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); @@ -232,7 +233,7 @@ public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() throws Excep } @Test - public void shouldThrowWhenAudienceClaimIsNull() throws Exception { + public void shouldThrowWhenAudienceClaimIsNull() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); @@ -245,7 +246,7 @@ public void shouldThrowWhenAudienceClaimIsNull() throws Exception { } @Test - public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() throws Exception { + public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); @@ -258,7 +259,7 @@ public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() throws Exception } @Test - public void shouldRemoveAudienceWhenPassingNullReference() throws Exception { + public void shouldRemoveAudienceWhenPassingNullReference() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withAudience((String) null) @@ -291,7 +292,7 @@ public void shouldRemoveAudienceWhenPassingNullReference() throws Exception { } @Test - public void shouldRemoveAudienceWhenPassingNullReferenceWithAnyOfAudience() throws Exception { + public void shouldRemoveAudienceWhenPassingNullReferenceWithAnyOfAudience() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withAnyOfAudience((String) null) @@ -324,7 +325,7 @@ public void shouldRemoveAudienceWhenPassingNullReferenceWithAnyOfAudience() thro } @Test - public void shouldRemoveAudienceWhenPassingNull() throws Exception { + public void shouldRemoveAudienceWhenPassingNull() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withAudience("John") @@ -344,7 +345,7 @@ public void shouldRemoveAudienceWhenPassingNull() throws Exception { } @Test - public void shouldRemoveAudienceWhenPassingNullWithAnyAudience() throws Exception { + public void shouldRemoveAudienceWhenPassingNullWithAnyAudience() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withAnyOfAudience("John") @@ -364,7 +365,7 @@ public void shouldRemoveAudienceWhenPassingNullWithAnyAudience() throws Exceptio } @Test - public void shouldThrowOnNullCustomClaimName() throws Exception { + public void shouldThrowOnNullCustomClaimName() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Custom Claim's name can't be null."); JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -372,7 +373,7 @@ public void shouldThrowOnNullCustomClaimName() throws Exception { } @Test - public void shouldThrowWhenExpectedArrayClaimIsMissing() throws Exception { + public void shouldThrowWhenExpectedArrayClaimIsMissing() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'missing' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcnJheSI6WzEsMiwzXX0.wKNFBcMdwIpdF9rXRxvexrzSM6umgSFqRO1WZj992YM"; @@ -383,7 +384,7 @@ public void shouldThrowWhenExpectedArrayClaimIsMissing() throws Exception { } @Test - public void shouldThrowWhenExpectedClaimIsMissing() throws Exception { + public void shouldThrowWhenExpectedClaimIsMissing() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'missing' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbSI6InRleHQifQ.aZ27Ze35VvTqxpaSIK5ZcnYHr4SrvANlUbDR8fw9qsQ"; @@ -394,7 +395,7 @@ public void shouldThrowWhenExpectedClaimIsMissing() throws Exception { } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeString() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeString() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -405,7 +406,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeString() throws Exception } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -416,7 +417,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() throws Exception } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -427,7 +428,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() throws Exception } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -439,7 +440,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() throws Exception @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -450,7 +451,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() throws Exception { } @Test - public void shouldThrowOnInvalidCustomClaimValue() throws Exception { + public void shouldThrowOnInvalidCustomClaimValue() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -461,7 +462,7 @@ public void shouldThrowOnInvalidCustomClaimValue() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeString() throws Exception { + public void shouldValidateCustomClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ.Jki8pvw6KGbxpMinufrgo6RDL1cu7AtNMJYVh6t-_cE"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", "value") @@ -472,7 +473,7 @@ public void shouldValidateCustomClaimOfTypeString() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeInteger() throws Exception { + public void shouldValidateCustomClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", 123) @@ -483,7 +484,7 @@ public void shouldValidateCustomClaimOfTypeInteger() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeLong() throws Exception { + public void shouldValidateCustomClaimOfTypeLong() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjo5MjIzMzcyMDM2ODU0Nzc2MDB9.km-IwQ5IDnTZFmuJzhSgvjTzGkn_Z5X29g4nAuVC56I"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", 922337203685477600L) @@ -494,7 +495,7 @@ public void shouldValidateCustomClaimOfTypeLong() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeDouble() throws Exception { + public void shouldValidateCustomClaimOfTypeDouble() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", 23.45) @@ -505,7 +506,7 @@ public void shouldValidateCustomClaimOfTypeDouble() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeBoolean() throws Exception { + public void shouldValidateCustomClaimOfTypeBoolean() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", true) @@ -516,7 +517,7 @@ public void shouldValidateCustomClaimOfTypeBoolean() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeDate() throws Exception { + public void shouldValidateCustomClaimOfTypeDate() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; Date date = new Date(1478891521000L); DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -528,7 +529,7 @@ public void shouldValidateCustomClaimOfTypeDate() throws Exception { } @Test - public void shouldValidateCustomArrayClaimOfTypeString() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", "text", "123", "true") @@ -539,7 +540,7 @@ public void shouldValidateCustomArrayClaimOfTypeString() throws Exception { } @Test - public void shouldValidateCustomArrayClaimOfTypeInteger() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", 1, 2, 3) @@ -550,7 +551,7 @@ public void shouldValidateCustomArrayClaimOfTypeInteger() throws Exception { } @Test - public void shouldValidateCustomArrayClaimOfTypeLong() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeLong() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbNTAwMDAwMDAwMDAxLDUwMDAwMDAwMDAwMiw1MDAwMDAwMDAwMDNdfQ.vzV7S0gbV9ZAVxChuIt4XZuSVTxMH536rFmoHzxmayM"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", 500000000001L, 500000000002L, 500000000003L) @@ -561,7 +562,7 @@ public void shouldValidateCustomArrayClaimOfTypeLong() throws Exception { } @Test - public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsInteger() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsInteger() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", 1L, 2L, 3L) @@ -572,7 +573,7 @@ public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsInteger() throws } @Test - public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsIntegerAndLong() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsIntegerAndLong() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSw1MDAwMDAwMDAwMDIsNTAwMDAwMDAwMDAzXX0.PQjb2rPPpYjM2sItZEzZcjS2YbfPCp6xksTSPjpjTQA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", 1L, 500000000002L, 500000000003L) @@ -585,7 +586,7 @@ public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsIntegerAndLong() // Generic Delta @SuppressWarnings("RedundantCast") @Test - public void shouldAddDefaultLeewayToDateClaims() throws Exception { + public void shouldAddDefaultLeewayToDateClaims() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .build(); @@ -598,7 +599,7 @@ public void shouldAddDefaultLeewayToDateClaims() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldAddCustomLeewayToDateClaims() throws Exception { + public void shouldAddCustomLeewayToDateClaims() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -612,7 +613,7 @@ public void shouldAddCustomLeewayToDateClaims() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldOverrideDefaultIssuedAtLeeway() throws Exception { + public void shouldOverrideDefaultIssuedAtLeeway() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -627,7 +628,7 @@ public void shouldOverrideDefaultIssuedAtLeeway() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldOverrideDefaultExpiresAtLeeway() throws Exception { + public void shouldOverrideDefaultExpiresAtLeeway() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -642,7 +643,7 @@ public void shouldOverrideDefaultExpiresAtLeeway() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldOverrideDefaultNotBeforeLeeway() throws Exception { + public void shouldOverrideDefaultNotBeforeLeeway() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -656,7 +657,7 @@ public void shouldOverrideDefaultNotBeforeLeeway() throws Exception { } @Test - public void shouldThrowOnNegativeCustomLeeway() throws Exception { + public void shouldThrowOnNegativeCustomLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -666,7 +667,7 @@ public void shouldThrowOnNegativeCustomLeeway() throws Exception { // Expires At @Test - public void shouldValidateExpiresAtWithLeeway() throws Exception { + public void shouldValidateExpiresAtWithLeeway() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) .acceptExpiresAt(2); @@ -689,7 +690,7 @@ public void shouldValidateExpiresAtIfPresent() { } @Test - public void shouldThrowOnInvalidExpiresAtIfPresent() throws Exception { + public void shouldThrowOnInvalidExpiresAtIfPresent() { exception.expect(TokenExpiredException.class); exception.expectMessage(startsWith("The Token has expired on")); @@ -701,7 +702,7 @@ public void shouldThrowOnInvalidExpiresAtIfPresent() throws Exception { } @Test - public void shouldThrowOnNegativeExpiresAtLeeway() throws Exception { + public void shouldThrowOnNegativeExpiresAtLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -711,7 +712,7 @@ public void shouldThrowOnNegativeExpiresAtLeeway() throws Exception { // Not before @Test - public void shouldValidateNotBeforeWithLeeway() throws Exception { + public void shouldValidateNotBeforeWithLeeway() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) .acceptNotBefore(2); @@ -723,7 +724,7 @@ public void shouldValidateNotBeforeWithLeeway() throws Exception { } @Test - public void shouldThrowOnInvalidNotBeforeIfPresent() throws Exception { + public void shouldThrowOnInvalidNotBeforeIfPresent() { exception.expect(InvalidClaimException.class); exception.expectMessage(startsWith("The Token can't be used before")); @@ -735,7 +736,7 @@ public void shouldThrowOnInvalidNotBeforeIfPresent() throws Exception { } @Test - public void shouldValidateNotBeforeIfPresent() throws Exception { + public void shouldValidateNotBeforeIfPresent() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification @@ -746,7 +747,7 @@ public void shouldValidateNotBeforeIfPresent() throws Exception { } @Test - public void shouldThrowOnNegativeNotBeforeLeeway() throws Exception { + public void shouldThrowOnNegativeNotBeforeLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -756,7 +757,7 @@ public void shouldThrowOnNegativeNotBeforeLeeway() throws Exception { // Issued At with future date @Test(expected = InvalidClaimException.class) - public void shouldThrowOnFutureIssuedAt() throws Exception { + public void shouldThrowOnFutureIssuedAt() { String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -766,7 +767,7 @@ public void shouldThrowOnFutureIssuedAt() throws Exception { // Issued At with future date and ignore flag @Test - public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() throws Exception { + public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() { String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); verification.ignoreIssuedAt(); @@ -776,7 +777,7 @@ public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() throws Exception { } @Test - public void shouldThrowOnInvalidIssuedAtIfPresent() throws Exception { + public void shouldThrowOnInvalidIssuedAtIfPresent() { exception.expect(InvalidClaimException.class); exception.expectMessage(startsWith("The Token can't be used before")); @@ -788,7 +789,7 @@ public void shouldThrowOnInvalidIssuedAtIfPresent() throws Exception { } @Test - public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVerification() throws Exception { + public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVerification() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) .acceptIssuedAt(1) @@ -801,7 +802,7 @@ public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVe } @Test - public void shouldValidateIssuedAtIfPresent() throws Exception { + public void shouldValidateIssuedAtIfPresent() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification @@ -812,7 +813,7 @@ public void shouldValidateIssuedAtIfPresent() throws Exception { } @Test - public void shouldThrowOnNegativeIssuedAtLeeway() throws Exception { + public void shouldThrowOnNegativeIssuedAtLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -821,7 +822,7 @@ public void shouldThrowOnNegativeIssuedAtLeeway() throws Exception { } @Test - public void shouldValidateJWTId() throws Exception { + public void shouldValidateJWTId() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withJWTId("jwt_id_123") @@ -832,7 +833,7 @@ public void shouldValidateJWTId() throws Exception { } @Test - public void shouldThrowOnInvalidJWTId() throws Exception { + public void shouldThrowOnInvalidJWTId() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'jti' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; @@ -843,7 +844,7 @@ public void shouldThrowOnInvalidJWTId() throws Exception { } @Test - public void shouldRemoveClaimWhenPassingNull() throws Exception { + public void shouldRemoveClaimWhenPassingNull() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withIssuer("iss") @@ -863,7 +864,7 @@ public void shouldRemoveClaimWhenPassingNull() throws Exception { } @Test - public void shouldRemoveIssuerWhenPassingNullReference() throws Exception { + public void shouldRemoveIssuerWhenPassingNullReference() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withIssuer((String) null) @@ -896,7 +897,7 @@ public void shouldRemoveIssuerWhenPassingNullReference() throws Exception { } @Test - public void shouldSkipClaimValidationsIfNoClaimsRequired() throws Exception { + public void shouldSkipClaimValidationsIfNoClaimsRequired() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .build() @@ -926,7 +927,7 @@ public void shouldThrowWhenVerifyingClaimPresenceWhenClaimNameIsNull() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Custom Claim's name can't be null."); - String jwt = JWTCreator.init() + JWTCreator.init() .withClaim("custom", "value") .sign(Algorithm.HMAC256("secret")); diff --git a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java index a9ad8cbe..d32ee859 100644 --- a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java +++ b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java @@ -14,7 +14,7 @@ public class TokenUtilsTest { public ExpectedException exception = ExpectedException.none(); @Test - public void shouldSplitToken() throws Exception { + public void shouldSplitToken() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; String[] parts = TokenUtils.splitToken(token); @@ -26,7 +26,7 @@ public void shouldSplitToken() throws Exception { } @Test - public void shouldSplitTokenWithEmptySignature() throws Exception { + public void shouldSplitTokenWithEmptySignature() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; String[] parts = TokenUtils.splitToken(token); @@ -38,7 +38,7 @@ public void shouldSplitTokenWithEmptySignature() throws Exception { } @Test - public void shouldThrowOnSplitTokenWithMoreThan3Parts() throws Exception { + public void shouldThrowOnSplitTokenWithMoreThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 4."); String token = "this.has.four.parts"; @@ -46,7 +46,7 @@ public void shouldThrowOnSplitTokenWithMoreThan3Parts() throws Exception { } @Test - public void shouldThrowOnSplitTokenWithLessThan3Parts() throws Exception { + public void shouldThrowOnSplitTokenWithLessThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 2."); String token = "two.parts"; diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java index d2e26e9a..dd919625 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java @@ -25,7 +25,7 @@ public class AlgorithmTest { @Test - public void shouldThrowHMAC256InstanceWithNullSecretBytes() throws Exception { + public void shouldThrowHMAC256InstanceWithNullSecretBytes() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); byte[] secret = null; @@ -33,7 +33,7 @@ public void shouldThrowHMAC256InstanceWithNullSecretBytes() throws Exception { } @Test - public void shouldThrowHMAC384InstanceWithNullSecretBytes() throws Exception { + public void shouldThrowHMAC384InstanceWithNullSecretBytes() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); byte[] secret = null; @@ -41,7 +41,7 @@ public void shouldThrowHMAC384InstanceWithNullSecretBytes() throws Exception { } @Test - public void shouldThrowHMAC512InstanceWithNullSecretBytes() throws Exception { + public void shouldThrowHMAC512InstanceWithNullSecretBytes() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); byte[] secret = null; @@ -49,7 +49,7 @@ public void shouldThrowHMAC512InstanceWithNullSecretBytes() throws Exception { } @Test - public void shouldThrowHMAC256InstanceWithNullSecret() throws Exception { + public void shouldThrowHMAC256InstanceWithNullSecret() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); String secret = null; @@ -57,7 +57,7 @@ public void shouldThrowHMAC256InstanceWithNullSecret() throws Exception { } @Test - public void shouldThrowHMAC384InstanceWithNullSecret() throws Exception { + public void shouldThrowHMAC384InstanceWithNullSecret() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); String secret = null; @@ -65,7 +65,7 @@ public void shouldThrowHMAC384InstanceWithNullSecret() throws Exception { } @Test - public void shouldThrowHMAC512InstanceWithNullSecret() throws Exception { + public void shouldThrowHMAC512InstanceWithNullSecret() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); String secret = null; @@ -73,7 +73,7 @@ public void shouldThrowHMAC512InstanceWithNullSecret() throws Exception { } @Test - public void shouldThrowRSA256InstanceWithNullKey() throws Exception { + public void shouldThrowRSA256InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); RSAKey key = null; @@ -81,14 +81,14 @@ public void shouldThrowRSA256InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowRSA256InstanceWithNullKeys() throws Exception { + public void shouldThrowRSA256InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.RSA256(null, null); } @Test - public void shouldThrowRSA256InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowRSA256InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); RSAKeyProvider provider = null; @@ -96,7 +96,7 @@ public void shouldThrowRSA256InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowRSA384InstanceWithNullKey() throws Exception { + public void shouldThrowRSA384InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); RSAKey key = null; @@ -104,14 +104,14 @@ public void shouldThrowRSA384InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowRSA384InstanceWithNullKeys() throws Exception { + public void shouldThrowRSA384InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.RSA384(null, null); } @Test - public void shouldThrowRSA384InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowRSA384InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); RSAKeyProvider provider = null; @@ -119,7 +119,7 @@ public void shouldThrowRSA384InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowRSA512InstanceWithNullKey() throws Exception { + public void shouldThrowRSA512InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); RSAKey key = null; @@ -127,14 +127,14 @@ public void shouldThrowRSA512InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowRSA512InstanceWithNullKeys() throws Exception { + public void shouldThrowRSA512InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.RSA512(null, null); } @Test - public void shouldThrowRSA512InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowRSA512InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); RSAKeyProvider provider = null; @@ -142,7 +142,7 @@ public void shouldThrowRSA512InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowECDSA256InstanceWithNullKey() throws Exception { + public void shouldThrowECDSA256InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); ECKey key = null; @@ -150,14 +150,14 @@ public void shouldThrowECDSA256InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowECDSA256InstanceWithNullKeys() throws Exception { + public void shouldThrowECDSA256InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.ECDSA256(null, null); } @Test - public void shouldThrowECDSA256InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowECDSA256InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); ECDSAKeyProvider provider = null; @@ -165,7 +165,7 @@ public void shouldThrowECDSA256InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowECDSA384InstanceWithNullKey() throws Exception { + public void shouldThrowECDSA384InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); ECKey key = null; @@ -173,14 +173,14 @@ public void shouldThrowECDSA384InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowECDSA384InstanceWithNullKeys() throws Exception { + public void shouldThrowECDSA384InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.ECDSA384(null, null); } @Test - public void shouldThrowECDSA384InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowECDSA384InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); ECDSAKeyProvider provider = null; @@ -188,7 +188,7 @@ public void shouldThrowECDSA384InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowECDSA512InstanceWithNullKey() throws Exception { + public void shouldThrowECDSA512InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); ECKey key = null; @@ -196,14 +196,14 @@ public void shouldThrowECDSA512InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowECDSA512InstanceWithNullKeys() throws Exception { + public void shouldThrowECDSA512InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.ECDSA512(null, null); } @Test - public void shouldThrowECDSA512InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowECDSA512InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); ECDSAKeyProvider provider = null; @@ -211,7 +211,7 @@ public void shouldThrowECDSA512InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldCreateHMAC256AlgorithmWithBytes() throws Exception { + public void shouldCreateHMAC256AlgorithmWithBytes() { Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); assertThat(algorithm, is(notNullValue())); @@ -221,7 +221,7 @@ public void shouldCreateHMAC256AlgorithmWithBytes() throws Exception { } @Test - public void shouldCreateHMAC384AlgorithmWithBytes() throws Exception { + public void shouldCreateHMAC384AlgorithmWithBytes() { Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); assertThat(algorithm, is(notNullValue())); @@ -231,7 +231,7 @@ public void shouldCreateHMAC384AlgorithmWithBytes() throws Exception { } @Test - public void shouldCreateHMAC512AlgorithmWithBytes() throws Exception { + public void shouldCreateHMAC512AlgorithmWithBytes() { Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); assertThat(algorithm, is(notNullValue())); @@ -241,7 +241,7 @@ public void shouldCreateHMAC512AlgorithmWithBytes() throws Exception { } @Test - public void shouldCreateHMAC256AlgorithmWithString() throws Exception { + public void shouldCreateHMAC256AlgorithmWithString() { Algorithm algorithm = Algorithm.HMAC256("secret"); assertThat(algorithm, is(notNullValue())); @@ -251,7 +251,7 @@ public void shouldCreateHMAC256AlgorithmWithString() throws Exception { } @Test - public void shouldCreateHMAC384AlgorithmWithString() throws Exception { + public void shouldCreateHMAC384AlgorithmWithString() { Algorithm algorithm = Algorithm.HMAC384("secret"); assertThat(algorithm, is(notNullValue())); @@ -261,7 +261,7 @@ public void shouldCreateHMAC384AlgorithmWithString() throws Exception { } @Test - public void shouldCreateHMAC512AlgorithmWithString() throws Exception { + public void shouldCreateHMAC512AlgorithmWithString() { Algorithm algorithm = Algorithm.HMAC512("secret"); assertThat(algorithm, is(notNullValue())); @@ -271,7 +271,7 @@ public void shouldCreateHMAC512AlgorithmWithString() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithPublicKey() throws Exception { + public void shouldCreateRSA256AlgorithmWithPublicKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); Algorithm algorithm = Algorithm.RSA256(key); @@ -282,7 +282,7 @@ public void shouldCreateRSA256AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateRSA256AlgorithmWithPrivateKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); Algorithm algorithm = Algorithm.RSA256(key); @@ -293,7 +293,7 @@ public void shouldCreateRSA256AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithBothKeys() throws Exception { + public void shouldCreateRSA256AlgorithmWithBothKeys() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); @@ -305,7 +305,7 @@ public void shouldCreateRSA256AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithProvider() throws Exception { + public void shouldCreateRSA256AlgorithmWithProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); Algorithm algorithm = Algorithm.RSA256(provider); @@ -316,7 +316,7 @@ public void shouldCreateRSA256AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithPublicKey() throws Exception { + public void shouldCreateRSA384AlgorithmWithPublicKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); Algorithm algorithm = Algorithm.RSA384(key); @@ -327,7 +327,7 @@ public void shouldCreateRSA384AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateRSA384AlgorithmWithPrivateKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); Algorithm algorithm = Algorithm.RSA384(key); @@ -338,7 +338,7 @@ public void shouldCreateRSA384AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithBothKeys() throws Exception { + public void shouldCreateRSA384AlgorithmWithBothKeys() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); Algorithm algorithm = Algorithm.RSA384(publicKey, privateKey); @@ -350,7 +350,7 @@ public void shouldCreateRSA384AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithProvider() throws Exception { + public void shouldCreateRSA384AlgorithmWithProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); Algorithm algorithm = Algorithm.RSA384(provider); @@ -361,7 +361,7 @@ public void shouldCreateRSA384AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithPublicKey() throws Exception { + public void shouldCreateRSA512AlgorithmWithPublicKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); Algorithm algorithm = Algorithm.RSA512(key); @@ -372,7 +372,7 @@ public void shouldCreateRSA512AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateRSA512AlgorithmWithPrivateKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); Algorithm algorithm = Algorithm.RSA512(key); @@ -383,7 +383,7 @@ public void shouldCreateRSA512AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithBothKeys() throws Exception { + public void shouldCreateRSA512AlgorithmWithBothKeys() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); Algorithm algorithm = Algorithm.RSA512(publicKey, privateKey); @@ -395,7 +395,7 @@ public void shouldCreateRSA512AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithProvider() throws Exception { + public void shouldCreateRSA512AlgorithmWithProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); Algorithm algorithm = Algorithm.RSA512(provider); @@ -406,7 +406,7 @@ public void shouldCreateRSA512AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithPublicKey() throws Exception { + public void shouldCreateECDSA256AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); Algorithm algorithm = Algorithm.ECDSA256(key); @@ -417,7 +417,7 @@ public void shouldCreateECDSA256AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateECDSA256AlgorithmWithPrivateKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); Algorithm algorithm = Algorithm.ECDSA256(key); @@ -428,7 +428,7 @@ public void shouldCreateECDSA256AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA256AlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA256(publicKey, privateKey); @@ -440,7 +440,7 @@ public void shouldCreateECDSA256AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA256AlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA256(provider); @@ -451,22 +451,22 @@ public void shouldCreateECDSA256AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA256KAlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA256KAlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA256K(publicKey, privateKey); - + assertThat(algorithm, is(notNullValue())); assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); assertThat(algorithm.getDescription(), is("SHA256withECDSA")); assertThat(algorithm.getName(), is("ES256K")); } - + @Test - public void shouldCreateECDSA256KAlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA256KAlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA256K(provider); - + assertThat(algorithm, is(notNullValue())); assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); assertThat(algorithm.getDescription(), is("SHA256withECDSA")); @@ -474,7 +474,7 @@ public void shouldCreateECDSA256KAlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithPublicKey() throws Exception { + public void shouldCreateECDSA384AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); Algorithm algorithm = Algorithm.ECDSA384(key); @@ -485,7 +485,7 @@ public void shouldCreateECDSA384AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateECDSA384AlgorithmWithPrivateKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); Algorithm algorithm = Algorithm.ECDSA384(key); @@ -496,7 +496,7 @@ public void shouldCreateECDSA384AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA384AlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA384(publicKey, privateKey); @@ -508,7 +508,7 @@ public void shouldCreateECDSA384AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA384AlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA384(provider); @@ -519,7 +519,7 @@ public void shouldCreateECDSA384AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithPublicKey() throws Exception { + public void shouldCreateECDSA512AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); Algorithm algorithm = Algorithm.ECDSA512(key); @@ -530,7 +530,7 @@ public void shouldCreateECDSA512AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateECDSA512AlgorithmWithPrivateKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); Algorithm algorithm = Algorithm.ECDSA512(key); @@ -541,7 +541,7 @@ public void shouldCreateECDSA512AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA512AlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA512(publicKey, privateKey); @@ -553,7 +553,7 @@ public void shouldCreateECDSA512AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA512AlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA512(provider); @@ -564,7 +564,7 @@ public void shouldCreateECDSA512AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateNoneAlgorithm() throws Exception { + public void shouldCreateNoneAlgorithm() { Algorithm algorithm = Algorithm.none(); assertThat(algorithm, is(notNullValue())); diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index 8dd00ca3..ee1bf928 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -113,7 +113,7 @@ public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -225,7 +225,7 @@ public void shouldPassECDSA256KVerificationWithProvidedPublicKey() throws Except } @Test - public void shouldFailECDSA256KVerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA256KVerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -343,7 +343,7 @@ public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -468,7 +468,7 @@ public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -675,7 +675,7 @@ public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -733,7 +733,7 @@ public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -794,7 +794,7 @@ public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -869,7 +869,7 @@ public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { } @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { + public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); @@ -879,7 +879,7 @@ public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Ex } @Test - public void shouldReturnSigningKeyIdFromProvider() throws Exception { + public void shouldReturnSigningKeyIdFromProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); @@ -1295,7 +1295,7 @@ public void shouldBeEqualSignatureMethodDecodeResults() throws Exception { */ @Test - public void shouldFailOnECDSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java index 675baeff..d000bb34 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java @@ -64,18 +64,18 @@ public class ECDSABouncyCastleProviderTests { //These tests add and use the BouncyCastle SecurityProvider to handle ECDSA algorithms @BeforeClass - public static void setUp() throws Exception { + public static void setUp() { //Set BC as the preferred bcProvider Security.insertProviderAt(bcProvider, 1); } @AfterClass - public static void tearDown() throws Exception { + public static void tearDown() { Security.removeProvider(bcProvider.getName()); } @Test - public void shouldPreferBouncyCastleProvider() throws Exception { + public void shouldPreferBouncyCastleProvider() { assertThat(Security.getProviders()[0], is(equalTo(bcProvider))); } @@ -118,7 +118,7 @@ public void shouldPassECDSA256KVerificationWithProvidedPublicKey() throws Except } @Test - public void shouldFailECDSA256KVerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA256KVerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -237,7 +237,7 @@ public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -362,7 +362,7 @@ public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -487,7 +487,7 @@ public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -675,7 +675,7 @@ public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -733,7 +733,7 @@ public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -792,7 +792,7 @@ public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -867,7 +867,7 @@ public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { } @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { + public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); @@ -877,7 +877,7 @@ public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Ex } @Test - public void shouldReturnSigningKeyIdFromProvider() throws Exception { + public void shouldReturnSigningKeyIdFromProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java index ded62aff..4a0269cc 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java @@ -34,14 +34,14 @@ public class HMACAlgorithmTest { // Verify @Test - public void shouldGetStringBytes() throws Exception { + public void shouldGetStringBytes() { String text = "abcdef123456!@#$%^"; byte[] expectedBytes = text.getBytes(StandardCharsets.UTF_8); assertArrayEquals(expectedBytes, HMACAlgorithm.getSecretBytes(text)); } @Test - public void shouldCopyTheReceivedSecretArray() throws Exception { + public void shouldCopyTheReceivedSecretArray() { String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; byte[] secretArray = "secret".getBytes(Charset.defaultCharset()); Algorithm algorithmString = Algorithm.HMAC256(secretArray); @@ -53,7 +53,7 @@ public void shouldCopyTheReceivedSecretArray() throws Exception { } @Test - public void shouldPassHMAC256Verification() throws Exception { + public void shouldPassHMAC256Verification() { String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; Algorithm algorithmString = Algorithm.HMAC256("secret"); Algorithm algorithmBytes = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); @@ -63,7 +63,7 @@ public void shouldPassHMAC256Verification() throws Exception { } @Test - public void shouldFailHMAC256VerificationWithInvalidSecretString() throws Exception { + public void shouldFailHMAC256VerificationWithInvalidSecretString() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; @@ -72,7 +72,7 @@ public void shouldFailHMAC256VerificationWithInvalidSecretString() throws Except } @Test - public void shouldFailHMAC256VerificationWithInvalidSecretBytes() throws Exception { + public void shouldFailHMAC256VerificationWithInvalidSecretBytes() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; @@ -81,7 +81,7 @@ public void shouldFailHMAC256VerificationWithInvalidSecretBytes() throws Excepti } @Test - public void shouldPassHMAC384Verification() throws Exception { + public void shouldPassHMAC384Verification() { String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; Algorithm algorithmString = Algorithm.HMAC384("secret"); Algorithm algorithmBytes = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); @@ -91,7 +91,7 @@ public void shouldPassHMAC384Verification() throws Exception { } @Test - public void shouldFailHMAC384VerificationWithInvalidSecretString() throws Exception { + public void shouldFailHMAC384VerificationWithInvalidSecretString() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384"); String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; @@ -100,7 +100,7 @@ public void shouldFailHMAC384VerificationWithInvalidSecretString() throws Except } @Test - public void shouldFailHMAC384VerificationWithInvalidSecretBytes() throws Exception { + public void shouldFailHMAC384VerificationWithInvalidSecretBytes() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384"); String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; @@ -109,7 +109,7 @@ public void shouldFailHMAC384VerificationWithInvalidSecretBytes() throws Excepti } @Test - public void shouldPassHMAC512Verification() throws Exception { + public void shouldPassHMAC512Verification() { String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; Algorithm algorithmString = Algorithm.HMAC512("secret"); Algorithm algorithmBytes = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); @@ -119,7 +119,7 @@ public void shouldPassHMAC512Verification() throws Exception { } @Test - public void shouldFailHMAC512VerificationWithInvalidSecretString() throws Exception { + public void shouldFailHMAC512VerificationWithInvalidSecretString() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512"); String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; @@ -128,7 +128,7 @@ public void shouldFailHMAC512VerificationWithInvalidSecretString() throws Except } @Test - public void shouldFailHMAC512VerificationWithInvalidSecretBytes() throws Exception { + public void shouldFailHMAC512VerificationWithInvalidSecretBytes() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512"); String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; @@ -174,7 +174,7 @@ public void shouldThrowOnVerifyWhenTheSecretIsInvalid() throws Exception { private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; @Test - public void shouldDoHMAC256SigningWithBytes() throws Exception { + public void shouldDoHMAC256SigningWithBytes() { Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); String jwt = asJWT(algorithm, HS256Header, auth0IssPayload); @@ -186,7 +186,7 @@ public void shouldDoHMAC256SigningWithBytes() throws Exception { } @Test - public void shouldDoHMAC384SigningWithBytes() throws Exception { + public void shouldDoHMAC384SigningWithBytes() { Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); String jwt = asJWT(algorithm, HS384Header, auth0IssPayload); @@ -198,7 +198,7 @@ public void shouldDoHMAC384SigningWithBytes() throws Exception { } @Test - public void shouldDoHMAC512SigningWithBytes() throws Exception { + public void shouldDoHMAC512SigningWithBytes() { Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); String jwt = asJWT(algorithm, HS512Header, auth0IssPayload); @@ -210,7 +210,7 @@ public void shouldDoHMAC512SigningWithBytes() throws Exception { } @Test - public void shouldDoHMAC256SigningWithString() throws Exception { + public void shouldDoHMAC256SigningWithString() { Algorithm algorithm = Algorithm.HMAC256("secret"); String jwt = asJWT(algorithm, HS256Header, auth0IssPayload); @@ -222,7 +222,7 @@ public void shouldDoHMAC256SigningWithString() throws Exception { } @Test - public void shouldDoHMAC384SigningWithString() throws Exception { + public void shouldDoHMAC384SigningWithString() { Algorithm algorithm = Algorithm.HMAC384("secret"); String jwt = asJWT(algorithm, HS384Header, auth0IssPayload); @@ -234,7 +234,7 @@ public void shouldDoHMAC384SigningWithString() throws Exception { } @Test - public void shouldDoHMAC512SigningWithString() throws Exception { + public void shouldDoHMAC512SigningWithString() { Algorithm algorithm = Algorithm.HMAC512("secret"); String jwt = asJWT(algorithm ,HS512Header, auth0IssPayload); @@ -274,7 +274,7 @@ public void shouldThrowOnSignWhenTheSecretIsInvalid() throws Exception { } @Test - public void shouldReturnNullSigningKeyId() throws Exception { + public void shouldReturnNullSigningKeyId() { assertThat(Algorithm.HMAC256("secret").getSigningKeyId(), is(nullValue())); } diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java index f4946dfa..263dc249 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java @@ -16,14 +16,14 @@ public class NoneAlgorithmTest { public ExpectedException exception = ExpectedException.none(); @Test - public void shouldPassNoneVerification() throws Exception { + public void shouldPassNoneVerification() { Algorithm algorithm = Algorithm.none(); String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; algorithm.verify(JWT.decode(jwt)); } @Test - public void shouldFailNoneVerificationWhenTokenHasTwoParts() throws Exception { + public void shouldFailNoneVerificationWhenTokenHasTwoParts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 2."); String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9"; @@ -32,7 +32,7 @@ public void shouldFailNoneVerificationWhenTokenHasTwoParts() throws Exception { } @Test - public void shouldFailNoneVerificationWhenSignatureIsPresent() throws Exception { + public void shouldFailNoneVerificationWhenSignatureIsPresent() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: none"); String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; @@ -41,7 +41,7 @@ public void shouldFailNoneVerificationWhenSignatureIsPresent() throws Exception } @Test - public void shouldReturnNullSigningKeyId() throws Exception { + public void shouldReturnNullSigningKeyId() { assertThat(Algorithm.none().getSigningKeyId(), is(nullValue())); } diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java index d7a062af..115de64c 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java @@ -61,7 +61,7 @@ public void shouldPassRSA256VerificationWithProvidedPublicKey() throws Exception } @Test - public void shouldFailRSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailRSA256VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -118,7 +118,7 @@ public void shouldPassRSA384VerificationWithProvidedPublicKey() throws Exception } @Test - public void shouldFailRSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailRSA384VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -175,7 +175,7 @@ public void shouldPassRSA512VerificationWithProvidedPublicKey() throws Exception } @Test - public void shouldFailRSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailRSA512VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -309,7 +309,7 @@ public void shouldDoRSA256SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -373,7 +373,7 @@ public void shouldDoRSA384SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnRSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA384SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -437,7 +437,7 @@ public void shouldDoRSA512SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnRSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA512SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -512,7 +512,7 @@ public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { } @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { + public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); @@ -522,7 +522,7 @@ public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Ex } @Test - public void shouldReturnSigningKeyIdFromProvider() throws Exception { + public void shouldReturnSigningKeyIdFromProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new RSAAlgorithm("some-alg", "some-algorithm", provider); @@ -552,11 +552,10 @@ public void shouldBeEqualSignatureMethodResults() throws Exception { * Test deprecated signing method error handling. * * @see {@linkplain #shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull} - * @throws Exception expected exception */ @Test - public void shouldFailOnRSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); exception.expectCause(isA(IllegalStateException.class)); diff --git a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java index c2d89556..e3d04c77 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java @@ -25,21 +25,21 @@ public class BasicHeaderTest { @SuppressWarnings("Convert2Diamond") @Test - public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNonNullTree() throws Exception { + public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNonNullTree() { exception.expect(UnsupportedOperationException.class); BasicHeader header = new BasicHeader(null, null, null, null, new HashMap(), objectReader); header.getTree().put("something", null); } @Test - public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNullTree() throws Exception { + public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNullTree() { exception.expect(UnsupportedOperationException.class); BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); header.getTree().put("something", null); } @Test - public void shouldHaveTree() throws Exception { + public void shouldHaveTree() { HashMap map = new HashMap<>(); JsonNode node = NullNode.getInstance(); map.put("key", node); @@ -50,7 +50,7 @@ public void shouldHaveTree() throws Exception { } @Test - public void shouldGetAlgorithm() throws Exception { + public void shouldGetAlgorithm() { BasicHeader header = new BasicHeader("HS256", null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -59,7 +59,7 @@ public void shouldGetAlgorithm() throws Exception { } @Test - public void shouldGetNullAlgorithmIfMissing() throws Exception { + public void shouldGetNullAlgorithmIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -67,7 +67,7 @@ public void shouldGetNullAlgorithmIfMissing() throws Exception { } @Test - public void shouldGetType() throws Exception { + public void shouldGetType() { BasicHeader header = new BasicHeader(null, "jwt", null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -76,7 +76,7 @@ public void shouldGetType() throws Exception { } @Test - public void shouldGetNullTypeIfMissing() throws Exception { + public void shouldGetNullTypeIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -84,7 +84,7 @@ public void shouldGetNullTypeIfMissing() throws Exception { } @Test - public void shouldGetContentType() throws Exception { + public void shouldGetContentType() { BasicHeader header = new BasicHeader(null, null, "content", null, null, objectReader); assertThat(header, is(notNullValue())); @@ -93,7 +93,7 @@ public void shouldGetContentType() throws Exception { } @Test - public void shouldGetNullContentTypeIfMissing() throws Exception { + public void shouldGetNullContentTypeIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -101,7 +101,7 @@ public void shouldGetNullContentTypeIfMissing() throws Exception { } @Test - public void shouldGetKeyId() throws Exception { + public void shouldGetKeyId() { BasicHeader header = new BasicHeader(null, null, null, "key", null, objectReader); assertThat(header, is(notNullValue())); @@ -110,7 +110,7 @@ public void shouldGetKeyId() throws Exception { } @Test - public void shouldGetNullKeyIdIfMissing() throws Exception { + public void shouldGetNullKeyIdIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -118,7 +118,7 @@ public void shouldGetNullKeyIdIfMissing() throws Exception { } @Test - public void shouldGetExtraClaim() throws Exception { + public void shouldGetExtraClaim() { Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); BasicHeader header = new BasicHeader(null, null, null, null, tree, objectReader); @@ -129,7 +129,7 @@ public void shouldGetExtraClaim() throws Exception { } @Test - public void shouldGetNotNullExtraClaimIfMissing() throws Exception { + public void shouldGetNotNullExtraClaimIfMissing() { Map tree = new HashMap<>(); BasicHeader header = new BasicHeader(null, null, null, null, tree, objectReader); diff --git a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java b/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java index faa48948..38601bdc 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java @@ -13,7 +13,7 @@ public class ClaimsHolderTest { @SuppressWarnings("RedundantCast") @Test - public void shouldGetClaims() throws Exception { + public void shouldGetClaims() { HashMap claims = new HashMap<>(); claims.put("iss", "auth0"); ClaimsHolder holder = new ClaimsHolder(claims); @@ -24,7 +24,7 @@ public void shouldGetClaims() throws Exception { } @Test - public void shouldGetNotNullClaims() throws Exception { + public void shouldGetNotNullClaims() { ClaimsHolder holder = new ClaimsHolder(null); assertThat(holder, is(notNullValue())); assertThat(holder.getClaims(), is(notNullValue())); diff --git a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java index fce6b26b..328f4ab4 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java @@ -37,7 +37,7 @@ public class HeaderDeserializerTest { private ObjectReader objectReader = new ObjectMapper().reader(); @Before - public void setUp() throws Exception { + public void setUp() { deserializer = new HeaderDeserializer(objectReader); } @@ -88,7 +88,7 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNullNode() throws Exception { + public void shouldGetNullStringWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -98,7 +98,7 @@ public void shouldGetNullStringWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNull() throws Exception { + public void shouldGetNullStringWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); @@ -107,7 +107,7 @@ public void shouldGetNullStringWhenParsingNull() throws Exception { } @Test - public void shouldGetStringWhenParsingTextNode() throws Exception { + public void shouldGetStringWhenParsingTextNode() { Map tree = new HashMap<>(); TextNode node = new TextNode("something here"); tree.put("key", node); diff --git a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java index 4f97b2bd..a40a23d4 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java @@ -27,12 +27,12 @@ public class JWTParserTest { private JWTParser parser; @Before - public void setUp() throws Exception { + public void setUp() { parser = new JWTParser(); } @Test - public void shouldGetDefaultObjectMapper() throws Exception { + public void shouldGetDefaultObjectMapper() { ObjectMapper mapper = getDefaultObjectMapper(); assertThat(mapper, is(notNullValue())); assertThat(mapper, is(instanceOf(ObjectMapper.class))); @@ -40,7 +40,7 @@ public void shouldGetDefaultObjectMapper() throws Exception { } @Test - public void shouldAddDeserializers() throws Exception { + public void shouldAddDeserializers() { ObjectMapper mapper = mock(ObjectMapper.class); new JWTParser(mapper); verify(mapper).registerModule(any(Module.class)); @@ -58,7 +58,7 @@ public void shouldParsePayload() throws Exception { } @Test - public void shouldThrowOnInvalidPayload() throws Exception { + public void shouldThrowOnInvalidPayload() { String jsonPayload = "{{"; exception.expect(JWTDecodeException.class); exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", jsonPayload)); @@ -78,7 +78,7 @@ public void shouldParseHeader() throws Exception { } @Test - public void shouldThrowOnInvalidHeader() throws Exception { + public void shouldThrowOnInvalidHeader() { String jsonHeader = "}}"; exception.expect(JWTDecodeException.class); exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", jsonHeader)); @@ -87,28 +87,28 @@ public void shouldThrowOnInvalidHeader() throws Exception { } @Test - public void shouldThrowWhenConvertingHeaderIfNullJson() throws Exception { + public void shouldThrowWhenConvertingHeaderIfNullJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string 'null' doesn't have a valid JSON format."); parser.parseHeader(null); } @Test - public void shouldThrowWhenConvertingHeaderFromInvalidJson() throws Exception { + public void shouldThrowWhenConvertingHeaderFromInvalidJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string '}{' doesn't have a valid JSON format."); parser.parseHeader("}{"); } @Test - public void shouldThrowWhenConvertingPayloadIfNullJson() throws Exception { + public void shouldThrowWhenConvertingPayloadIfNullJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string 'null' doesn't have a valid JSON format."); parser.parsePayload(null); } @Test - public void shouldThrowWhenConvertingPayloadFromInvalidJson() throws Exception { + public void shouldThrowWhenConvertingPayloadFromInvalidJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string '}{' doesn't have a valid JSON format."); parser.parsePayload("}{"); diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java index 430490a4..3299134d 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java @@ -39,13 +39,13 @@ public class JsonNodeClaimTest { public ExpectedException exception = ExpectedException.none(); @Before - public void setUp() throws Exception { + public void setUp() { mapper = getDefaultObjectMapper(); objectReader = mapper.reader(); } @Test - public void shouldGetBooleanValue() throws Exception { + public void shouldGetBooleanValue() { JsonNode value = mapper.valueToTree(true); Claim claim = claimFromNode(value); @@ -58,7 +58,7 @@ private Claim claimFromNode(JsonNode value) { } @Test - public void shouldGetNullBooleanIfNotBooleanValue() throws Exception { + public void shouldGetNullBooleanIfNotBooleanValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asBoolean(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("boolean"); @@ -66,7 +66,7 @@ public void shouldGetNullBooleanIfNotBooleanValue() throws Exception { } @Test - public void shouldGetIntValue() throws Exception { + public void shouldGetIntValue() { JsonNode value = mapper.valueToTree(123); Claim claim = claimFromNode(value); @@ -75,7 +75,7 @@ public void shouldGetIntValue() throws Exception { } @Test - public void shouldGetNullIntIfNotIntValue() throws Exception { + public void shouldGetNullIntIfNotIntValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asInt(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("123"); @@ -83,7 +83,7 @@ public void shouldGetNullIntIfNotIntValue() throws Exception { } @Test - public void shouldGetLongValue() throws Exception { + public void shouldGetLongValue() { JsonNode value = mapper.valueToTree(Long.MAX_VALUE); Claim claim = claimFromNode(value); @@ -92,7 +92,7 @@ public void shouldGetLongValue() throws Exception { } @Test - public void shouldGetNullLongIfNotIntValue() throws Exception { + public void shouldGetNullLongIfNotIntValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asLong(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("" + Long.MAX_VALUE); @@ -100,7 +100,7 @@ public void shouldGetNullLongIfNotIntValue() throws Exception { } @Test - public void shouldGetDoubleValue() throws Exception { + public void shouldGetDoubleValue() { JsonNode value = mapper.valueToTree(1.5); Claim claim = claimFromNode(value); @@ -109,7 +109,7 @@ public void shouldGetDoubleValue() throws Exception { } @Test - public void shouldGetNullDoubleIfNotDoubleValue() throws Exception { + public void shouldGetNullDoubleIfNotDoubleValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asDouble(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("123.23"); @@ -117,7 +117,7 @@ public void shouldGetNullDoubleIfNotDoubleValue() throws Exception { } @Test - public void shouldGetDateValue() throws Exception { + public void shouldGetDateValue() { JsonNode value = mapper.valueToTree(1476824844L); Claim claim = claimFromNode(value); @@ -126,7 +126,7 @@ public void shouldGetDateValue() throws Exception { } @Test - public void shouldGetNullDateIfNotDateValue() throws Exception { + public void shouldGetNullDateIfNotDateValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asDate(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("1476824844"); @@ -134,7 +134,7 @@ public void shouldGetNullDateIfNotDateValue() throws Exception { } @Test - public void shouldGetStringValue() throws Exception { + public void shouldGetStringValue() { JsonNode value = mapper.valueToTree("string"); Claim claim = claimFromNode(value); @@ -143,7 +143,7 @@ public void shouldGetStringValue() throws Exception { } @Test - public void shouldGetNullStringIfNotStringValue() throws Exception { + public void shouldGetNullStringIfNotStringValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asString(), is(nullValue())); JsonNode intValue = mapper.valueToTree(12345); @@ -151,7 +151,7 @@ public void shouldGetNullStringIfNotStringValue() throws Exception { } @Test - public void shouldGetArrayValueOfCustomClass() throws Exception { + public void shouldGetArrayValueOfCustomClass() { JsonNode value = mapper.valueToTree(new UserPojo[]{new UserPojo("George", 1), new UserPojo("Mark", 2)}); Claim claim = claimFromNode(value); @@ -160,7 +160,7 @@ public void shouldGetArrayValueOfCustomClass() throws Exception { } @Test - public void shouldGetArrayValue() throws Exception { + public void shouldGetArrayValue() { JsonNode value = mapper.valueToTree(new String[]{"string1", "string2"}); Claim claim = claimFromNode(value); @@ -169,7 +169,7 @@ public void shouldGetArrayValue() throws Exception { } @Test - public void shouldGetNullArrayIfNullValue() throws Exception { + public void shouldGetNullArrayIfNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -177,7 +177,7 @@ public void shouldGetNullArrayIfNullValue() throws Exception { } @Test - public void shouldGetNullArrayIfNonArrayValue() throws Exception { + public void shouldGetNullArrayIfNonArrayValue() { JsonNode value = mapper.valueToTree(1); Claim claim = claimFromNode(value); @@ -185,7 +185,7 @@ public void shouldGetNullArrayIfNonArrayValue() throws Exception { } @Test - public void shouldThrowIfArrayClassMismatch() throws Exception { + public void shouldThrowIfArrayClassMismatch() { JsonNode value = mapper.valueToTree(new String[]{"keys", "values"}); Claim claim = claimFromNode(value); @@ -194,7 +194,7 @@ public void shouldThrowIfArrayClassMismatch() throws Exception { } @Test - public void shouldGetListValueOfCustomClass() throws Exception { + public void shouldGetListValueOfCustomClass() { JsonNode value = mapper.valueToTree(Arrays.asList(new UserPojo("George", 1), new UserPojo("Mark", 2))); Claim claim = claimFromNode(value); @@ -203,7 +203,7 @@ public void shouldGetListValueOfCustomClass() throws Exception { } @Test - public void shouldGetListValue() throws Exception { + public void shouldGetListValue() { JsonNode value = mapper.valueToTree(Arrays.asList("string1", "string2")); Claim claim = claimFromNode(value); @@ -212,7 +212,7 @@ public void shouldGetListValue() throws Exception { } @Test - public void shouldGetNullListIfNullValue() throws Exception { + public void shouldGetNullListIfNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -220,7 +220,7 @@ public void shouldGetNullListIfNullValue() throws Exception { } @Test - public void shouldGetNullListIfNonArrayValue() throws Exception { + public void shouldGetNullListIfNonArrayValue() { JsonNode value = mapper.valueToTree(1); Claim claim = claimFromNode(value); @@ -228,7 +228,7 @@ public void shouldGetNullListIfNonArrayValue() throws Exception { } @Test - public void shouldThrowIfListClassMismatch() throws Exception { + public void shouldThrowIfListClassMismatch() { JsonNode value = mapper.valueToTree(new String[]{"keys", "values"}); Claim claim = claimFromNode(value); @@ -237,7 +237,7 @@ public void shouldThrowIfListClassMismatch() throws Exception { } @Test - public void shouldGetNullMapIfNullValue() throws Exception { + public void shouldGetNullMapIfNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -245,7 +245,7 @@ public void shouldGetNullMapIfNullValue() throws Exception { } @Test - public void shouldGetNullMapIfNonArrayValue() throws Exception { + public void shouldGetNullMapIfNonArrayValue() { JsonNode value = mapper.valueToTree(1); Claim claim = claimFromNode(value); @@ -253,7 +253,7 @@ public void shouldGetNullMapIfNonArrayValue() throws Exception { } @Test - public void shouldGetMapValue() throws Exception { + public void shouldGetMapValue() { Map map = new HashMap<>(); map.put("text", "extraValue"); map.put("number", 12); @@ -292,7 +292,7 @@ public void shouldThrowIfAnExtraordinaryExceptionHappensWhenParsingAsGenericMap( } @Test - public void shouldGetCustomClassValue() throws Exception { + public void shouldGetCustomClassValue() { JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); Claim claim = claimFromNode(value); @@ -302,7 +302,7 @@ public void shouldGetCustomClassValue() throws Exception { } @Test - public void shouldThrowIfCustomClassMismatch() throws Exception { + public void shouldThrowIfCustomClassMismatch() { JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); Claim claim = claimFromNode(value); @@ -312,7 +312,7 @@ public void shouldThrowIfCustomClassMismatch() throws Exception { @SuppressWarnings({"unchecked", "RedundantCast"}) @Test - public void shouldGetAsMapValue() throws Exception { + public void shouldGetAsMapValue() { JsonNode value = mapper.valueToTree(Collections.singletonMap("key", new UserPojo("john", 123))); Claim claim = claimFromNode(value); @@ -323,7 +323,7 @@ public void shouldGetAsMapValue() throws Exception { } @Test - public void shouldReturnBaseClaimWhenParsingMissingNode() throws Exception { + public void shouldReturnBaseClaimWhenParsingMissingNode() { JsonNode value = MissingNode.getInstance(); Claim claim = claimFromNode(value); @@ -333,7 +333,7 @@ public void shouldReturnBaseClaimWhenParsingMissingNode() throws Exception { } @Test - public void shouldReturnBaseClaimWhenParsingNullNode() throws Exception { + public void shouldReturnBaseClaimWhenParsingNullNode() { JsonNode value = NullNode.getInstance(); Claim claim = claimFromNode(value); @@ -343,7 +343,7 @@ public void shouldReturnBaseClaimWhenParsingNullNode() throws Exception { } @Test - public void shouldReturnBaseClaimWhenParsingNullValue() throws Exception { + public void shouldReturnBaseClaimWhenParsingNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -353,7 +353,7 @@ public void shouldReturnBaseClaimWhenParsingNullValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingObject() throws Exception { + public void shouldReturnNonNullClaimWhenParsingObject() { JsonNode value = mapper.valueToTree(new Object()); Claim claim = claimFromNode(value); @@ -363,7 +363,7 @@ public void shouldReturnNonNullClaimWhenParsingObject() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingArray() throws Exception { + public void shouldReturnNonNullClaimWhenParsingArray() { JsonNode value = mapper.valueToTree(new String[]{}); Claim claim = claimFromNode(value); @@ -373,7 +373,7 @@ public void shouldReturnNonNullClaimWhenParsingArray() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingList() throws Exception { + public void shouldReturnNonNullClaimWhenParsingList() { JsonNode value = mapper.valueToTree(new ArrayList()); Claim claim = claimFromNode(value); @@ -383,7 +383,7 @@ public void shouldReturnNonNullClaimWhenParsingList() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingStringValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingStringValue() { JsonNode value = mapper.valueToTree(""); Claim claim = claimFromNode(value); @@ -393,7 +393,7 @@ public void shouldReturnNonNullClaimWhenParsingStringValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingIntValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingIntValue() { JsonNode value = mapper.valueToTree(Integer.MAX_VALUE); Claim claim = claimFromNode(value); @@ -403,7 +403,7 @@ public void shouldReturnNonNullClaimWhenParsingIntValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingDoubleValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingDoubleValue() { JsonNode value = mapper.valueToTree(Double.MAX_VALUE); Claim claim = claimFromNode(value); @@ -413,7 +413,7 @@ public void shouldReturnNonNullClaimWhenParsingDoubleValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingDateValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingDateValue() { JsonNode value = mapper.valueToTree(new Date()); Claim claim = claimFromNode(value); @@ -423,7 +423,7 @@ public void shouldReturnNonNullClaimWhenParsingDateValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingBooleanValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingBooleanValue() { JsonNode value = mapper.valueToTree(Boolean.TRUE); Claim claim = claimFromNode(value); diff --git a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java index 8cca7b53..84f91c78 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java @@ -11,62 +11,62 @@ public class NullClaimTest { private NullClaim claim; @Before - public void setUp() throws Exception { + public void setUp() { claim = new NullClaim(); } @Test - public void shouldBeNull() throws Exception { + public void shouldBeNull() { assertThat(claim.isNull(), is(true)); } @Test - public void shouldGetAsBoolean() throws Exception { + public void shouldGetAsBoolean() { assertThat(claim.asBoolean(), is(nullValue())); } @Test - public void shouldGetAsInt() throws Exception { + public void shouldGetAsInt() { assertThat(claim.asInt(), is(nullValue())); } @Test - public void shouldGetAsLong() throws Exception { + public void shouldGetAsLong() { assertThat(claim.asLong(), is(nullValue())); } @Test - public void shouldGetAsDouble() throws Exception { + public void shouldGetAsDouble() { assertThat(claim.asDouble(), is(nullValue())); } @Test - public void shouldGetAsString() throws Exception { + public void shouldGetAsString() { assertThat(claim.asString(), is(nullValue())); } @Test - public void shouldGetAsDate() throws Exception { + public void shouldGetAsDate() { assertThat(claim.asDate(), is(nullValue())); } @Test - public void shouldGetAsArray() throws Exception { + public void shouldGetAsArray() { assertThat(claim.asArray(Object.class), is(nullValue())); } @Test - public void shouldGetAsList() throws Exception { + public void shouldGetAsList() { assertThat(claim.asList(Object.class), is(nullValue())); } @Test - public void shouldGetAsMap() throws Exception { + public void shouldGetAsMap() { assertThat(claim.asMap(), is(nullValue())); } @Test - public void shouldGetAsCustomClass() throws Exception { + public void shouldGetAsCustomClass() { assertThat(claim.as(Object.class), is(nullValue())); } diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 5d44216e..16a7198d 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -35,7 +35,7 @@ public class PayloadDeserializerTest { private PayloadDeserializer deserializer; @Before - public void setUp() throws Exception { + public void setUp() { deserializer = new PayloadDeserializer(new ObjectMapper().reader()); } @@ -109,7 +109,7 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { } @Test - public void shouldGetStringArrayWhenParsingArrayNode() throws Exception { + public void shouldGetStringArrayWhenParsingArrayNode() { Map tree = new HashMap<>(); List subNodes = new ArrayList<>(); TextNode textNode1 = new TextNode("one"); @@ -126,7 +126,7 @@ public void shouldGetStringArrayWhenParsingArrayNode() throws Exception { } @Test - public void shouldGetStringArrayWhenParsingTextNode() throws Exception { + public void shouldGetStringArrayWhenParsingTextNode() { Map tree = new HashMap<>(); TextNode textNode = new TextNode("something"); tree.put("key", textNode); @@ -138,7 +138,7 @@ public void shouldGetStringArrayWhenParsingTextNode() throws Exception { } @Test - public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() throws Exception { + public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() { Map tree = new HashMap<>(); TextNode textNode = new TextNode(""); tree.put("key", textNode); @@ -149,7 +149,7 @@ public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() throws Exception } @Test - public void shouldGetNullArrayWhenParsingNullNode() throws Exception { + public void shouldGetNullArrayWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -159,7 +159,7 @@ public void shouldGetNullArrayWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullArrayWhenParsingNullNodeValue() throws Exception { + public void shouldGetNullArrayWhenParsingNullNodeValue() { Map tree = new HashMap<>(); tree.put("key", null); @@ -168,7 +168,7 @@ public void shouldGetNullArrayWhenParsingNullNodeValue() throws Exception { } @Test - public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() throws Exception { + public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() { Map tree = new HashMap<>(); IntNode node = new IntNode(456789); tree.put("key", node); @@ -179,7 +179,7 @@ public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() throws Exception { @Test - public void shouldGetNullDateWhenParsingNullNode() throws Exception { + public void shouldGetNullDateWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -189,7 +189,7 @@ public void shouldGetNullDateWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullDateWhenParsingNull() throws Exception { + public void shouldGetNullDateWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); @@ -198,7 +198,7 @@ public void shouldGetNullDateWhenParsingNull() throws Exception { } @Test - public void shouldThrowWhenParsingNonNumericNode() throws Exception { + public void shouldThrowWhenParsingNonNumericNode() { exception.expect(JWTDecodeException.class); exception.expectMessage("The claim 'key' contained a non-numeric date value."); @@ -210,7 +210,7 @@ public void shouldThrowWhenParsingNonNumericNode() throws Exception { } @Test - public void shouldGetDateWhenParsingNumericNode() throws Exception { + public void shouldGetDateWhenParsingNumericNode() { Map tree = new HashMap<>(); long seconds = 1478627949 / 1000; LongNode node = new LongNode(seconds); @@ -222,7 +222,7 @@ public void shouldGetDateWhenParsingNumericNode() throws Exception { } @Test - public void shouldGetLargeDateWhenParsingNumericNode() throws Exception { + public void shouldGetLargeDateWhenParsingNumericNode() { Map tree = new HashMap<>(); long seconds = Integer.MAX_VALUE + 10000L; LongNode node = new LongNode(seconds); @@ -235,7 +235,7 @@ public void shouldGetLargeDateWhenParsingNumericNode() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNullNode() throws Exception { + public void shouldGetNullStringWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -245,7 +245,7 @@ public void shouldGetNullStringWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNull() throws Exception { + public void shouldGetNullStringWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); @@ -254,7 +254,7 @@ public void shouldGetNullStringWhenParsingNull() throws Exception { } @Test - public void shouldGetStringWhenParsingTextNode() throws Exception { + public void shouldGetStringWhenParsingTextNode() { Map tree = new HashMap<>(); TextNode node = new TextNode("something here"); tree.put("key", node); diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java index 3c604a30..3cf6e023 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java @@ -33,7 +33,7 @@ public class PayloadImplTest { private ObjectReader objectReader; @Before - public void setUp() throws Exception { + public void setUp() { mapper = getDefaultObjectMapper(); objectReader = mapper.reader(); @@ -47,47 +47,47 @@ public void setUp() throws Exception { @SuppressWarnings("Convert2Diamond") @Test - public void shouldHaveUnmodifiableTree() throws Exception { + public void shouldHaveUnmodifiableTree() { exception.expect(UnsupportedOperationException.class); PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap(), objectReader); payload.getTree().put("something", null); } @Test - public void shouldHaveUnmodifiableAudience() throws Exception { + public void shouldHaveUnmodifiableAudience() { exception.expect(UnsupportedOperationException.class); PayloadImpl payload = new PayloadImpl(null, null, new ArrayList(), null, null, null, null, null, objectReader); payload.getAudience().add("something"); } @Test - public void shouldGetIssuer() throws Exception { + public void shouldGetIssuer() { assertThat(payload, is(notNullValue())); assertThat(payload.getIssuer(), is("issuer")); } @Test - public void shouldGetNullIssuerIfMissing() throws Exception { + public void shouldGetNullIssuerIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuer(), is(nullValue())); } @Test - public void shouldGetSubject() throws Exception { + public void shouldGetSubject() { assertThat(payload, is(notNullValue())); assertThat(payload.getSubject(), is("subject")); } @Test - public void shouldGetNullSubjectIfMissing() throws Exception { + public void shouldGetNullSubjectIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getSubject(), is(nullValue())); } @Test - public void shouldGetAudience() throws Exception { + public void shouldGetAudience() { assertThat(payload, is(notNullValue())); assertThat(payload.getAudience(), is(IsCollectionWithSize.hasSize(1))); @@ -95,73 +95,73 @@ public void shouldGetAudience() throws Exception { } @Test - public void shouldGetNullAudienceIfMissing() throws Exception { + public void shouldGetNullAudienceIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getAudience(), is(nullValue())); } @Test - public void shouldGetExpiresAt() throws Exception { + public void shouldGetExpiresAt() { assertThat(payload, is(notNullValue())); assertThat(payload.getExpiresAt(), is(expiresAt)); } @Test - public void shouldGetNullExpiresAtIfMissing() throws Exception { + public void shouldGetNullExpiresAtIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getExpiresAt(), is(nullValue())); } @Test - public void shouldGetNotBefore() throws Exception { + public void shouldGetNotBefore() { assertThat(payload, is(notNullValue())); assertThat(payload.getNotBefore(), is(notBefore)); } @Test - public void shouldGetNullNotBeforeIfMissing() throws Exception { + public void shouldGetNullNotBeforeIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getNotBefore(), is(nullValue())); } @Test - public void shouldGetIssuedAt() throws Exception { + public void shouldGetIssuedAt() { assertThat(payload, is(notNullValue())); assertThat(payload.getIssuedAt(), is(issuedAt)); } @Test - public void shouldGetNullIssuedAtIfMissing() throws Exception { + public void shouldGetNullIssuedAtIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuedAt(), is(nullValue())); } @Test - public void shouldGetJWTId() throws Exception { + public void shouldGetJWTId() { assertThat(payload, is(notNullValue())); assertThat(payload.getId(), is("jwtId")); } @Test - public void shouldGetNullJWTIdIfMissing() throws Exception { + public void shouldGetNullJWTIdIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getId(), is(nullValue())); } @Test - public void shouldGetExtraClaim() throws Exception { + public void shouldGetExtraClaim() { assertThat(payload, is(notNullValue())); assertThat(payload.getClaim("extraClaim"), is(instanceOf(JsonNodeClaim.class))); assertThat(payload.getClaim("extraClaim").asString(), is("extraValue")); } @Test - public void shouldGetNotNullExtraClaimIfMissing() throws Exception { + public void shouldGetNotNullExtraClaimIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getClaim("missing"), is(notNullValue())); @@ -169,7 +169,7 @@ public void shouldGetNotNullExtraClaimIfMissing() throws Exception { } @Test - public void shouldGetClaims() throws Exception { + public void shouldGetClaims() { Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); tree.put("sub", new TextNode("auth0")); @@ -183,7 +183,7 @@ public void shouldGetClaims() throws Exception { } @Test - public void shouldNotAllowToModifyClaimsMap() throws Exception { + public void shouldNotAllowToModifyClaimsMap() { assertThat(payload, is(notNullValue())); Map claims = payload.getClaims(); assertThat(claims, is(notNullValue())); From 9245f49fea7bec9fec39e5a21af8a230987c2704 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 3 Mar 2022 15:11:46 -0600 Subject: [PATCH 005/134] [SDK-3160] Remove internal Clock (#533) --- .../main/java/com/auth0/jwt/ClockImpl.java | 24 ------------------- .../java/com/auth0/jwt/interfaces/Clock.java | 16 ------------- .../java/com/auth0/jwt/ClockImplTest.java | 21 ---------------- 3 files changed, 61 deletions(-) delete mode 100644 lib/src/main/java/com/auth0/jwt/ClockImpl.java delete mode 100644 lib/src/main/java/com/auth0/jwt/interfaces/Clock.java delete mode 100644 lib/src/test/java/com/auth0/jwt/ClockImplTest.java diff --git a/lib/src/main/java/com/auth0/jwt/ClockImpl.java b/lib/src/main/java/com/auth0/jwt/ClockImpl.java deleted file mode 100644 index 29ed3c1e..00000000 --- a/lib/src/main/java/com/auth0/jwt/ClockImpl.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.interfaces.Clock; - -import java.util.Date; - -/** - * Default Clock implementation used for verification. - * - * @see Clock - * @see JWTVerifier - *

- * This class is thread-safe. - */ -final class ClockImpl implements Clock { - - ClockImpl() { - } - - @Override - public Date getToday() { - return new Date(); - } -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java b/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java deleted file mode 100644 index 7dd9c43b..00000000 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.auth0.jwt.interfaces; - -import java.util.Date; - -/** - * The Clock class is used to wrap calls to Date class. - */ -public interface Clock { - - /** - * Returns a new Date representing Today's time. - * - * @return a new Date representing Today's time. - */ - Date getToday(); -} diff --git a/lib/src/test/java/com/auth0/jwt/ClockImplTest.java b/lib/src/test/java/com/auth0/jwt/ClockImplTest.java deleted file mode 100644 index 0feb7c40..00000000 --- a/lib/src/test/java/com/auth0/jwt/ClockImplTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.auth0.jwt; - -import com.auth0.jwt.interfaces.Clock; -import org.junit.Test; - -import java.util.Date; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class ClockImplTest { - - @Test - public void shouldGetToday() throws Exception{ - Clock clock = new ClockImpl(); - Date clockToday = clock.getToday(); - assertThat(clockToday, is(notNullValue())); - } - -} \ No newline at end of file From 5c94325d6ca48532e1e13193e85a0eaec71c1ed6 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Fri, 4 Mar 2022 10:22:47 -0600 Subject: [PATCH 006/134] [SDK-3150] Serialize dates in collections as seconds since epoch (#534) * [SDK-3150] Serialize dates in collections as seconds since epoch * cleanup tests * Update javadocs --- .../main/java/com/auth0/jwt/JWTCreator.java | 12 ++++-- .../com/auth0/jwt/impl/PayloadSerializer.java | 41 ++++++++++++++++--- .../java/com/auth0/jwt/JWTCreatorTest.java | 17 ++++---- .../auth0/jwt/impl/PayloadSerializerTest.java | 17 ++++++++ 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index 26df771f..e2c22434 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -140,7 +140,8 @@ public Builder withAudience(String... audience) { } /** - * Add a specific Expires At ("exp") claim to the Payload. + * Add a specific Expires At ("exp") claim to the payload. The claim will be written as seconds since the epoch. + * Milliseconds will be truncated by rounding down to the nearest second. * * @param expiresAt the Expires At value. * @return this same Builder instance. @@ -151,7 +152,8 @@ public Builder withExpiresAt(Date expiresAt) { } /** - * Add a specific Not Before ("nbf") claim to the Payload. + * Add a specific Not Before ("nbf") claim to the Payload. The claim will be written as seconds since the epoch. + * Milliseconds will be truncated by rounding down to the nearest second. * * @param notBefore the Not Before value. * @return this same Builder instance. @@ -162,7 +164,8 @@ public Builder withNotBefore(Date notBefore) { } /** - * Add a specific Issued At ("iat") claim to the Payload. + * Add a specific Issued At ("iat") claim to the Payload. The claim will be written as seconds since the epoch. + * Milliseconds will be truncated by rounding down to the nearest second. * * @param issuedAt the Issued At value. * @return this same Builder instance. @@ -254,7 +257,8 @@ public Builder withClaim(String name, String value) throws IllegalArgumentExcept } /** - * Add a custom Claim value. + * Add a custom Claim value. The claim will be written as seconds since the epoch. + * Milliseconds will be truncated by rounding down to the nearest second. * * @param name the Claim's name. * @param value the Claim's value. diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index 8a86c04a..9ec6dc89 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -33,11 +33,7 @@ public void serialize(ClaimsHolder holder, JsonGenerator gen, SerializerProvider writeAudience(gen, e); } else { gen.writeFieldName(e.getKey()); - if (e.getValue() instanceof Date) { // true for EXPIRES_AT, ISSUED_AT, NOT_BEFORE - gen.writeNumber(dateToSeconds((Date) e.getValue())); - } else { - gen.writeObject(e.getValue()); - } + handleSerialization(e.getValue(), gen); } } @@ -74,6 +70,41 @@ private void writeAudience(JsonGenerator gen, Map.Entry e) throw } } + /** + * Serializes {@linkplain Date} to epoch second values, traversing maps and lists as needed. + * @param value the object to serialize + * @param gen the JsonGenerator to use for JSON serialization + */ + private void handleSerialization(Object value, JsonGenerator gen) throws IOException { + if (value instanceof Date) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom date claims + gen.writeNumber(dateToSeconds((Date) value)); + } else if (value instanceof Map) { + serializeMap((Map) value, gen); + } else if (value instanceof List) { + serializeList((List) value, gen); + } else { + gen.writeObject(value); + } + } + + private void serializeMap(Map map, JsonGenerator gen) throws IOException { + gen.writeStartObject(); + for (Map.Entry entry : map.entrySet()) { + gen.writeFieldName((String) entry.getKey()); + Object value = entry.getValue(); + handleSerialization(value, gen); + } + gen.writeEndObject(); + } + + private void serializeList(List list, JsonGenerator gen) throws IOException { + gen.writeStartArray(); + for (Object entry : list) { + handleSerialization(entry, gen); + } + gen.writeEndArray(); + } + private long dateToSeconds(Date date) { return date.getTime() / 1000; } diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 2a8812bd..fe15f3db 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -499,7 +499,7 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { data.put("integer", 1); data.put("long", Long.MAX_VALUE); data.put("double", 123.456d); - data.put("date", new Date(123L)); + data.put("date", new Date(123000)); data.put("boolean", true); // array types @@ -529,13 +529,14 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { assertThat(map.get("integer"), is(1)); assertThat(map.get("long"), is(Long.MAX_VALUE)); assertThat(map.get("double"), is(123.456d)); + assertThat(map.get("date"), is(123)); assertThat(map.get("boolean"), is(true)); // array types - assertThat(map.get("intArray"), is(Arrays.asList(new Integer[]{3, 5}))); - assertThat(map.get("longArray"), is(Arrays.asList(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}))); - assertThat(map.get("stringArray"), is(Arrays.asList(new String[]{"string"}))); + assertThat(map.get("intArray"), is(Arrays.asList(3, 5))); + assertThat(map.get("longArray"), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); + assertThat(map.get("stringArray"), is(Arrays.asList("string"))); // list assertThat(map.get("list"), is(Arrays.asList("a", "b", "c"))); @@ -553,7 +554,7 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { data.add(1); data.add(Long.MAX_VALUE); data.add(123.456d); - data.add(new Date(123L)); + data.add(new Date(123000)); data.add(true); // array types @@ -587,9 +588,9 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { assertThat(list.get(5), is(true)); // array types - assertThat(list.get(6), is(Arrays.asList(new Integer[]{3, 5}))); - assertThat(list.get(7), is(Arrays.asList(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}))); - assertThat(list.get(8), is(Arrays.asList(new String[]{"string"}))); + assertThat(list.get(6), is(Arrays.asList(3, 5))); + assertThat(list.get(7), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); + assertThat(list.get(8), is(Arrays.asList("string"))); // list assertThat(list.get(9), is(Arrays.asList("a", "b", "c"))); diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java index d990978d..df93f0ba 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java @@ -176,15 +176,32 @@ public void shouldSerializeDatesUsingLong() throws Exception { claims.put("nbf", date); claims.put("exp", date); claims.put("ctm", date); + claims.put("map", Collections.singletonMap("date", date)); + claims.put("list", Collections.singletonList(date)); + + Map nestedInMap = new HashMap<>(); + nestedInMap.put("list", Collections.singletonList(date)); + claims.put("nestedInMap", nestedInMap); + + List nestedInList = new ArrayList<>(); + nestedInList.add(Collections.singletonMap("nested", date)); + claims.put("nestedInList", nestedInList); + ClaimsHolder holder = new ClaimsHolder(claims); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); String json = writer.toString(); + System.out.println(json); + assertThat(json, containsString("\"iat\":2147493647")); assertThat(json, containsString("\"nbf\":2147493647")); assertThat(json, containsString("\"exp\":2147493647")); assertThat(json, containsString("\"ctm\":2147493647")); + assertThat(json, containsString("\"map\":{\"date\":2147493647")); + assertThat(json, containsString("\"list\":[2147493647]")); + assertThat(json, containsString("\"nestedInMap\":{\"list\":[2147493647]}")); + assertThat(json, containsString("\"nestedInList\":[{\"nested\":2147493647}]")); } @Test From ed91dc6db9fd4b31b14ff8c5299b68acad560789 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Mon, 7 Mar 2022 22:00:51 +0530 Subject: [PATCH 007/134] Testing Java LTS versions (#536) * Added Gradle Tasks to run tests on Java LTS versions * Ignore secp256k1 curve tests * Removing ignore for tests and checking the CI failure * Exclude secp256k1 Tests for Java 17 * Remove unwanted "ignore" imports --- lib/build.gradle | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/lib/build.gradle b/lib/build.gradle index e1a4b4e7..2bb5c599 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -55,6 +55,10 @@ dependencies { testImplementation 'org.mockito:mockito-core:2.18.3' } +jacoco { + toolVersion = "0.8.7" +} + jacocoTestReport { reports { xml.enabled = true @@ -87,6 +91,48 @@ task compileModuleInfoJava(type: JavaCompile) { } } +compileTestJava { + options.compilerArgs = ['--release', "8"] +} + +def testJava8 = tasks.register('testJava8', Test) { + description = 'Runs unit tests on Java 8.' + group = 'verification' + + javaLauncher.set(javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(8) + }) + shouldRunAfter(tasks.named('test')) +} + +def testJava17 = tasks.register('testJava17', Test) { + description = 'Runs unit tests on Java 17.' + group = 'verification' + + javaLauncher.set(javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(17) + }) + shouldRunAfter(tasks.named('test')) + + //Following Tests are excluded in Java 17 since secp256k1 curve is disabled Java 15+ + filter { + excludeTestsMatching "*.jwt.ConcurrentVerifyTest.shouldPassECDSA256KVerificationWithJOSESignature" + excludeTestsMatching "*.jwt.JWTCreatorTest.shouldAddKeyIdIfAvailableFromECDSAKAlgorithms" + excludeTestsMatching "*.jwt.JWTCreatorTest.shouldNotOverwriteKeyIdIfAddedFromECDSAKAlgorithms" + excludeTestsMatching "*.jwt.JWTTest.shouldCreateAnEmptyECDSA256KSignedToken" + excludeTestsMatching "*.jwt.algorithms.ECDSAAlgorithmTest.shouldPassECDSA256KVerificationWithJOSESignature" + excludeTestsMatching "*.jwt.algorithms.ECDSAAlgorithmTest.shouldPassECDSA256KVerificationWithJOSESignatureWithBothKeys" + excludeTestsMatching "*.jwt.algorithms.ECDSAAlgorithmTest.shouldPassECDSA256KVerificationWithProvidedPublicKey" + excludeTestsMatching "*.jwt.ECDSABouncyCastleProviderTests.shouldPassECDSA256KVerificationWithJOSESignatureWithBothKeys" + excludeTestsMatching "*.jwt.ECDSABouncyCastleProviderTests.shouldPassECDSA256KVerificationWithProvidedPublicKey" + } +} + +tasks.named('check') { + dependsOn(testJava8) + dependsOn(testJava17) +} + jar { manifest.attributes('Multi-Release': 'true') } From 90cea2d99680b985130f702ccb830bb322458171 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 9 Mar 2022 14:27:38 -0600 Subject: [PATCH 008/134] [SDK-3149] Add Instant support (#537) * [SDK-3149] Add support for java.time.Instant * formatting fixes * add javadocs * remove custom Instant claim verification check (not yet supported) * add tests for default method implementations * fix NullClaimTest for asInstant --- .../main/java/com/auth0/jwt/JWTCreator.java | 58 +++++++++++- .../main/java/com/auth0/jwt/JWTDecoder.java | 16 ++++ .../main/java/com/auth0/jwt/JWTVerifier.java | 34 +++---- .../com/auth0/jwt/impl/JsonNodeClaim.java | 11 ++- .../java/com/auth0/jwt/impl/NullClaim.java | 6 ++ .../auth0/jwt/impl/PayloadDeserializer.java | 12 +-- .../java/com/auth0/jwt/impl/PayloadImpl.java | 31 +++++-- .../com/auth0/jwt/impl/PayloadSerializer.java | 11 ++- .../java/com/auth0/jwt/interfaces/Claim.java | 12 +++ .../com/auth0/jwt/interfaces/Payload.java | 28 ++++++ .../java/com/auth0/jwt/JWTCreatorTest.java | 83 +++++++++++++---- .../java/com/auth0/jwt/JWTDecoderTest.java | 34 ++++--- lib/src/test/java/com/auth0/jwt/JWTTest.java | 12 +-- .../java/com/auth0/jwt/JWTVerifierTest.java | 12 +-- .../com/auth0/jwt/impl/JsonNodeClaimTest.java | 17 ++-- .../com/auth0/jwt/impl/NullClaimTest.java | 5 + .../jwt/impl/PayloadDeserializerTest.java | 38 ++++---- .../com/auth0/jwt/impl/PayloadImplTest.java | 31 ++++--- .../com/auth0/jwt/interfaces/ClaimTest.java | 93 +++++++++++++++++++ .../com/auth0/jwt/interfaces/PayloadTest.java | 83 +++++++++++++++++ 20 files changed, 504 insertions(+), 123 deletions(-) create mode 100644 lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java create mode 100644 lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index e2c22434..7d58fe2f 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.*; import java.util.Map.Entry; @@ -152,7 +153,19 @@ public Builder withExpiresAt(Date expiresAt) { } /** - * Add a specific Not Before ("nbf") claim to the Payload. The claim will be written as seconds since the epoch. + * Add a specific Expires At ("exp") claim to the payload. The claim will be written as seconds since the epoch; + * Milliseconds will be truncated by rounding down to the nearest second. + * + * @param expiresAt the Expires At value. + * @return this same Builder instance. + */ + public Builder withExpiresAt(Instant expiresAt) { + addClaim(PublicClaims.EXPIRES_AT, expiresAt); + return this; + } + + /** + * Add a specific Not Before ("nbf") claim to the Payload. The claim will be written as seconds since the epoch; * Milliseconds will be truncated by rounding down to the nearest second. * * @param notBefore the Not Before value. @@ -164,7 +177,19 @@ public Builder withNotBefore(Date notBefore) { } /** - * Add a specific Issued At ("iat") claim to the Payload. The claim will be written as seconds since the epoch. + * Add a specific Not Before ("nbf") claim to the Payload. The claim will be written as seconds since the epoch; + * Milliseconds will be truncated by rounding down to the nearest second. + * + * @param notBefore the Not Before value. + * @return this same Builder instance. + */ + public Builder withNotBefore(Instant notBefore) { + addClaim(PublicClaims.NOT_BEFORE, notBefore); + return this; + } + + /** + * Add a specific Issued At ("iat") claim to the Payload. The claim will be written as seconds since the epoch; * Milliseconds will be truncated by rounding down to the nearest second. * * @param issuedAt the Issued At value. @@ -175,6 +200,18 @@ public Builder withIssuedAt(Date issuedAt) { return this; } + /** + * Add a specific Issued At ("iat") claim to the Payload. The claim will be written as seconds since the epoch; + * Milliseconds will be truncated by rounding down to the nearest second. + * + * @param issuedAt the Issued At value. + * @return this same Builder instance. + */ + public Builder withIssuedAt(Instant issuedAt) { + addClaim(PublicClaims.ISSUED_AT, issuedAt); + return this; + } + /** * Add a specific JWT Id ("jti") claim to the Payload. * @@ -271,6 +308,21 @@ public Builder withClaim(String name, Date value) throws IllegalArgumentExceptio return this; } + /** + * Add a custom Claim value. The claim will be written as seconds since the epoch. + * Milliseconds will be truncated by rounding down to the nearest second. + * + * @param name the Claim's name. + * @param value the Claim's value. + * @return this same Builder instance. + * @throws IllegalArgumentException if the name is null. + */ + public Builder withClaim(String name, Instant value) throws IllegalArgumentException { + assertNonNull(name); + addClaim(name, value); + return this; + } + /** * Add a custom Array Claim with the given items. * @@ -453,7 +505,7 @@ private static boolean isBasicType(Object value) { if (c.isArray()) { return c == Integer[].class || c == Long[].class || c == String[].class; } - return c == String.class || c == Integer.class || c == Long.class || c == Double.class || c == Date.class || c == Boolean.class; + return c == String.class || c == Integer.class || c == Long.class || c == Double.class || c == Date.class || c == Instant.class || c == Boolean.class; } /** diff --git a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java index 71acbe59..55855241 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java +++ b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java @@ -9,6 +9,7 @@ import java.io.Serializable; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.Base64; import java.util.Date; import java.util.List; @@ -93,16 +94,31 @@ public Date getExpiresAt() { return payload.getExpiresAt(); } + @Override + public Instant getExpiresAtAsInstant() { + return payload.getExpiresAtAsInstant(); + } + @Override public Date getNotBefore() { return payload.getNotBefore(); } + @Override + public Instant getNotBeforeAsInstant() { + return payload.getNotBeforeAsInstant(); + } + @Override public Date getIssuedAt() { return payload.getIssuedAt(); } + @Override + public Instant getIssuedAtAsInstant() { + return payload.getIssuedAtAsInstant(); + } + @Override public String getId() { return payload.getId(); diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 9a7ea2b2..8dfb6dbf 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -9,8 +9,11 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; -import java.util.*; import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; /** * The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, but also its signature matches. @@ -327,13 +330,13 @@ private void verifyClaimValues(DecodedJWT jwt, Map.Entry expecte assertValidAudienceClaim(jwt.getAudience(), (List) expectedClaim.getValue(), false); break; case PublicClaims.EXPIRES_AT: - assertValidDateClaim(jwt.getExpiresAt(), (Long) expectedClaim.getValue(), true); + assertValidInstantClaim(jwt.getExpiresAtAsInstant(), (Long) expectedClaim.getValue(), true); break; case PublicClaims.ISSUED_AT: - assertValidDateClaim(jwt.getIssuedAt(), (Long) expectedClaim.getValue(), false); + assertValidInstantClaim(jwt.getIssuedAtAsInstant(), (Long) expectedClaim.getValue(), false); break; case PublicClaims.NOT_BEFORE: - assertValidDateClaim(jwt.getNotBefore(), (Long) expectedClaim.getValue(), false); + assertValidInstantClaim(jwt.getNotBeforeAsInstant(), (Long) expectedClaim.getValue(), false); break; case PublicClaims.ISSUER: assertValidIssuerClaim(jwt.getIssuer(), (List) expectedClaim.getValue()); @@ -403,27 +406,24 @@ private void assertValidStringClaim(String claimName, String value, String expec } } - private void assertValidDateClaim(Date date, long leeway, boolean shouldBeFuture) { - Date today = new Date(clock.millis()); - today.setTime(today.getTime() / 1000 * 1000); // truncate millis + private void assertValidInstantClaim(Instant claimVal, long leeway, boolean shouldBeFuture) { + Instant now = clock.instant().truncatedTo(ChronoUnit.SECONDS); if (shouldBeFuture) { - assertDateIsFuture(date, leeway, today); + assertInstantIsFuture(claimVal, leeway, now); } else { - assertDateIsPast(date, leeway, today); + assertInstantIsPast(claimVal, leeway, now); } } - private void assertDateIsFuture(Date date, long leeway, Date today) { - today.setTime(today.getTime() - leeway * 1000); - if (date != null && today.after(date)) { - throw new TokenExpiredException(String.format("The Token has expired on %s.", date)); + private void assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { + if (claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)) { + throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal)); } } - private void assertDateIsPast(Date date, long leeway, Date today) { - today.setTime(today.getTime() + leeway * 1000); - if (date != null && today.before(date)) { - throw new InvalidClaimException(String.format("The Token can't be used before %s.", date)); + private void assertInstantIsPast(Instant claimVal, long leeway, Instant now) { + if (claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)) { + throw new InvalidClaimException(String.format("The Token can't be used before %s.", claimVal)); } } diff --git a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java index ae266798..0d816128 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import java.io.IOException; import java.lang.reflect.Array; +import java.time.Instant; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -63,6 +63,15 @@ public Date asDate() { return new Date(seconds * 1000); } + @Override + public Instant asInstant() { + if (!data.canConvertToLong()) { + return null; + } + long seconds = data.asLong(); + return Instant.ofEpochSecond(seconds); + } + @Override @SuppressWarnings("unchecked") public T[] asArray(Class tClazz) throws JWTDecodeException { diff --git a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java index 2e9a38c2..664328de 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java @@ -3,6 +3,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.Claim; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -46,6 +47,11 @@ public Date asDate() { return null; } + @Override + public Instant asInstant() { + return null; + } + @Override public T[] asArray(Class tClazz) throws JWTDecodeException { return null; diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 8935a277..46bd7ebe 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; +import java.time.Instant; import java.util.*; /** @@ -45,9 +46,9 @@ public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOE String issuer = getString(tree, PublicClaims.ISSUER); String subject = getString(tree, PublicClaims.SUBJECT); List audience = getStringOrArray(tree, PublicClaims.AUDIENCE); - Date expiresAt = getDateFromSeconds(tree, PublicClaims.EXPIRES_AT); - Date notBefore = getDateFromSeconds(tree, PublicClaims.NOT_BEFORE); - Date issuedAt = getDateFromSeconds(tree, PublicClaims.ISSUED_AT); + Instant expiresAt = getInstantFromSeconds(tree, PublicClaims.EXPIRES_AT); + Instant notBefore = getInstantFromSeconds(tree, PublicClaims.NOT_BEFORE); + Instant issuedAt = getInstantFromSeconds(tree, PublicClaims.ISSUED_AT); String jwtId = getString(tree, PublicClaims.JWT_ID); return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, objectReader); @@ -73,7 +74,7 @@ List getStringOrArray(Map tree, String claimName) thro return list; } - Date getDateFromSeconds(Map tree, String claimName) { + Instant getInstantFromSeconds(Map tree, String claimName) { JsonNode node = tree.get(claimName); if (node == null || node.isNull()) { return null; @@ -81,8 +82,7 @@ Date getDateFromSeconds(Map tree, String claimName) { if (!node.canConvertToLong()) { throw new JWTDecodeException(String.format("The claim '%s' contained a non-numeric date value.", claimName)); } - final long ms = node.asLong() * 1000; - return new Date(ms); + return Instant.ofEpochSecond(node.asLong()); } String getString(Map tree, String claimName) { diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java index f056c038..a446741c 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectReader; import java.io.Serializable; +import java.time.Instant; import java.util.*; import static com.auth0.jwt.impl.JsonNodeClaim.extractClaim; @@ -24,14 +25,14 @@ class PayloadImpl implements Payload, Serializable { private final String issuer; private final String subject; private final List audience; - private final Date expiresAt; - private final Date notBefore; - private final Date issuedAt; + private final Instant expiresAt; + private final Instant notBefore; + private final Instant issuedAt; private final String jwtId; private final Map tree; private final ObjectReader objectReader; - PayloadImpl(String issuer, String subject, List audience, Date expiresAt, Date notBefore, Date issuedAt, String jwtId, Map tree, ObjectReader objectReader) { + PayloadImpl(String issuer, String subject, List audience, Instant expiresAt, Instant notBefore, Instant issuedAt, String jwtId, Map tree, ObjectReader objectReader) { this.issuer = issuer; this.subject = subject; this.audience = audience != null ? Collections.unmodifiableList(audience) : null; @@ -64,19 +65,35 @@ public List getAudience() { @Override public Date getExpiresAt() { - return expiresAt; + return (expiresAt != null) ? Date.from(expiresAt) : null; } + @Override - public Date getNotBefore() { - return notBefore; + public Instant getExpiresAtAsInstant() { + return expiresAt; } @Override public Date getIssuedAt() { + return (issuedAt != null) ? Date.from(issuedAt) : null; + } + + @Override + public Instant getIssuedAtAsInstant() { return issuedAt; } + @Override + public Date getNotBefore() { + return (notBefore != null) ? Date.from(notBefore) : null; + } + + @Override + public Instant getNotBeforeAsInstant() { + return notBefore; + } + @Override public String getId() { return jwtId; diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index 9ec6dc89..0389121c 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; +import java.time.Instant; import java.util.*; /** @@ -71,13 +72,15 @@ private void writeAudience(JsonGenerator gen, Map.Entry e) throw } /** - * Serializes {@linkplain Date} to epoch second values, traversing maps and lists as needed. + * Serializes {@linkplain Instant} to epoch second values, traversing maps and lists as needed. * @param value the object to serialize * @param gen the JsonGenerator to use for JSON serialization */ private void handleSerialization(Object value, JsonGenerator gen) throws IOException { - if (value instanceof Date) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom date claims + if (value instanceof Date) { gen.writeNumber(dateToSeconds((Date) value)); + } else if (value instanceof Instant) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom Instant claims + gen.writeNumber(instantToSeconds((Instant) value)); } else if (value instanceof Map) { serializeMap((Map) value, gen); } else if (value instanceof List) { @@ -105,6 +108,10 @@ private void serializeList(List list, JsonGenerator gen) throws IOException { gen.writeEndArray(); } + private long instantToSeconds(Instant instant) { + return instant.getEpochSecond(); + } + private long dateToSeconds(Date date) { return date.getTime() / 1000; } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java index b3d41b1d..cc5256f4 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java @@ -2,6 +2,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -66,6 +67,17 @@ public interface Claim { */ Date asDate(); + /** + * Get this Claim as an Instant. + * If the value can't be converted to an Instant, null will be returned. + * + * @return the value as a Date or null. + */ + default Instant asInstant() { + Date date = asDate(); + return date != null ? date.toInstant() : null; + } + /** * Get this Claim as an Array of type T. * If the value isn't an Array, null will be returned. diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java index b999ad43..b3bf71f5 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java @@ -1,5 +1,6 @@ package com.auth0.jwt.interfaces; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -37,6 +38,15 @@ public interface Payload { */ Date getExpiresAt(); + /** + * Get the value of the "exp" claim as an {@linkplain Instant}, or null if it's not available. + * + * @return the Expiration Time value or null. + */ + default Instant getExpiresAtAsInstant() { + return getExpiresAt() != null ? getExpiresAt().toInstant() : null; + } + /** * Get the value of the "nbf" claim, or null if it's not available. * @@ -44,6 +54,15 @@ public interface Payload { */ Date getNotBefore(); + /** + * Get the value of the "nbf" claim as an {@linkplain Instant}, or null if it's not available. + * + * @return the Not Before value or null. + */ + default Instant getNotBeforeAsInstant() { + return getNotBefore() != null ? getNotBefore().toInstant() : null; + } + /** * Get the value of the "iat" claim, or null if it's not available. * @@ -51,6 +70,15 @@ public interface Payload { */ Date getIssuedAt(); + /** + * Get the value of the "iat" claim as an {@linkplain Instant}, or null if it's not available. + * + * @return the Issued At value or null. + */ + default Instant getIssuedAtAsInstant() { + return getIssuedAt() != null ? getIssuedAt().toInstant() : null; + } + /** * Get the value of the "jti" claim, or null if it's not available. * diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index fe15f3db..c6fff1f2 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -13,6 +13,7 @@ import java.nio.charset.StandardCharsets; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.RSAPrivateKey; +import java.time.Instant; import java.util.*; import static org.hamcrest.Matchers.*; @@ -64,7 +65,7 @@ public void shouldReturnBuilderIfNullMapIsProvided() { @Test public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { - Map header = new HashMap(); + Map header = new HashMap<>(); header.put(PublicClaims.KEY_ID, "xyz"); String signed = JWTCreator.init() @@ -80,7 +81,7 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { @Test public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { - Map header = new HashMap(); + Map header = new HashMap<>(); header.put(PublicClaims.KEY_ID, "xyz"); String signed = JWTCreator.init() @@ -96,7 +97,7 @@ public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { @Test public void shouldRemoveHeaderIfTheValueIsNull() { - Map header = new HashMap(); + Map header = new HashMap<>(); header.put(PublicClaims.KEY_ID, null); header.put("test2", "isSet"); @@ -271,6 +272,17 @@ public void shouldAddExpiresAt() { assertThat(TokenUtils.splitToken(signed)[1], is("eyJleHAiOjE0Nzc1OTJ9")); } + @Test + public void shouldAddExpiresAtInstant() { + String signed = JWTCreator.init() + .withExpiresAt(Instant.ofEpochSecond(1477592)) + .sign(Algorithm.HMAC256("secret")); + + System.out.println(signed); + assertThat(signed, is(notNullValue())); + assertThat(TokenUtils.splitToken(signed)[1], is("eyJleHAiOjE0Nzc1OTJ9")); + } + @Test public void shouldAddNotBefore() { String signed = JWTCreator.init() @@ -281,6 +293,16 @@ public void shouldAddNotBefore() { assertThat(TokenUtils.splitToken(signed)[1], is("eyJuYmYiOjE0Nzc1OTJ9")); } + @Test + public void shouldAddNotBeforeInstant() { + String signed = JWTCreator.init() + .withNotBefore(Instant.ofEpochSecond(1477592)) + .sign(Algorithm.HMAC256("secret")); + + assertThat(signed, is(notNullValue())); + assertThat(TokenUtils.splitToken(signed)[1], is("eyJuYmYiOjE0Nzc1OTJ9")); + } + @Test public void shouldAddIssuedAt() { String signed = JWTCreator.init() @@ -291,6 +313,16 @@ public void shouldAddIssuedAt() { assertThat(TokenUtils.splitToken(signed)[1], is("eyJpYXQiOjE0Nzc1OTJ9")); } + @Test + public void shouldAddIssuedAtInstant() { + String signed = JWTCreator.init() + .withIssuedAt(Instant.ofEpochSecond(1477592)) + .sign(Algorithm.HMAC256("secret")); + + assertThat(signed, is(notNullValue())); + assertThat(TokenUtils.splitToken(signed)[1], is("eyJpYXQiOjE0Nzc1OTJ9")); + } + @Test public void shouldAddJWTId() { String signed = JWTCreator.init() @@ -430,6 +462,18 @@ public void shouldAcceptCustomClaimOfTypeDate() { assertThat(parts[1], is("eyJuYW1lIjoxNDc4ODkxNTIxfQ")); } + @Test + public void shouldAcceptCustomClaimOfTypeDateInstant() { + Instant instant = Instant.ofEpochSecond(1478891521); + String jwt = JWTCreator.init() + .withClaim("name", instant) + .sign(Algorithm.HMAC256("secret")); + + assertThat(jwt, is(notNullValue())); + String[] parts = jwt.split("\\."); + assertThat(parts[1], is("eyJuYW1lIjoxNDc4ODkxNTIxfQ")); + } + @Test public void shouldAcceptCustomArrayClaimOfTypeString() { String jwt = JWTCreator.init() @@ -499,7 +543,8 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { data.put("integer", 1); data.put("long", Long.MAX_VALUE); data.put("double", 123.456d); - data.put("date", new Date(123000)); + data.put("date", new Date(123000L)); + data.put("instant", Instant.ofEpochSecond(123)); data.put("boolean", true); // array types @@ -531,12 +576,13 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { assertThat(map.get("double"), is(123.456d)); assertThat(map.get("date"), is(123)); + assertThat(map.get("instant"), is(123)); assertThat(map.get("boolean"), is(true)); // array types assertThat(map.get("intArray"), is(Arrays.asList(3, 5))); assertThat(map.get("longArray"), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); - assertThat(map.get("stringArray"), is(Arrays.asList("string"))); + assertThat(map.get("stringArray"), is(Collections.singletonList("string"))); // list assertThat(map.get("list"), is(Arrays.asList("a", "b", "c"))); @@ -554,7 +600,8 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { data.add(1); data.add(Long.MAX_VALUE); data.add(123.456d); - data.add(new Date(123000)); + data.add(new Date(123000L)); + data.add(Instant.ofEpochSecond(123)); data.add(true); // array types @@ -585,17 +632,17 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { assertThat(list.get(2), is(Long.MAX_VALUE)); assertThat(list.get(3), is(123.456d)); assertThat(list.get(4), is(123)); - assertThat(list.get(5), is(true)); + assertThat(list.get(5), is(123)); + assertThat(list.get(6), is(true)); // array types - assertThat(list.get(6), is(Arrays.asList(3, 5))); - assertThat(list.get(7), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); - assertThat(list.get(8), is(Arrays.asList("string"))); + assertThat(list.get(7), is(Arrays.asList(3, 5))); + assertThat(list.get(8), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); + assertThat(list.get(9), is(Arrays.asList("string"))); // list - assertThat(list.get(9), is(Arrays.asList("a", "b", "c"))); - assertThat(list.get(10), is(sub)); - + assertThat(list.get(10), is(Arrays.asList("a", "b", "c"))); + assertThat(list.get(11), is(sub)); } @Test @@ -681,7 +728,7 @@ public void shouldRefuseCustomMapClaimForNonStringKey() { @Test public void shouldRefuseCustomListClaimForUnknownListElement() { - List list = Arrays.asList(new UserPojo("Michael", 255)); + List list = Collections.singletonList(new UserPojo("Michael", 255)); exception.expect(IllegalArgumentException.class); @@ -692,7 +739,7 @@ public void shouldRefuseCustomListClaimForUnknownListElement() { @Test public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() { - List list = Arrays.asList(new UserPojo("Michael", 255)); + List list = Collections.singletonList(new UserPojo("Michael", 255)); Map data = new HashMap<>(); data.put("someList", list); @@ -798,7 +845,7 @@ public void withPayloadShouldNotAllowCustomType() { Map payload = new HashMap<>(); payload.put("entry", "value"); payload.put("pojo", new UserPojo("name", 42)); - String jwt = JWTCreator.init() + JWTCreator.init() .withPayload(payload) .sign(Algorithm.HMAC256("secret")); } @@ -824,7 +871,7 @@ public void withPayloadShouldNotAllowListWithCustomType() { Map payload = new HashMap<>(); payload.put("list", Arrays.asList("item1", new UserPojo("name", 42))); - String jwt = JWTCreator.init() + JWTCreator.init() .withPayload(payload) .sign(Algorithm.HMAC256("secret")); } @@ -837,7 +884,7 @@ public void withPayloadShouldNotAllowMapWithCustomType() { Map payload = new HashMap<>(); payload.put("entry", "value"); payload.put("map", Collections.singletonMap("pojo", new UserPojo("name", 42))); - String jwt = JWTCreator.init() + JWTCreator.init() .withPayload(payload) .sign(Algorithm.HMAC256("secret")); } diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 536c2dbb..a9e8f248 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -12,6 +12,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.Base64; import java.util.Date; import java.util.Map; @@ -156,33 +157,27 @@ public void shouldGetStringAudience() { public void shouldGetExpirationTime() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzY3MjcwODZ9.L9dcPHEDQew2u9MkDCORFkfDGcSOsgoPqNY-LUMLEHg"); assertThat(jwt, is(notNullValue())); - assertThat(jwt.getExpiresAt(), is(instanceOf(Date.class))); long ms = 1476727086L * 1000; - Date expectedDate = new Date(ms); - assertThat(jwt.getExpiresAt(), is(notNullValue())); - assertThat(jwt.getExpiresAt(), is(equalTo(expectedDate))); + assertThat(jwt.getExpiresAt(), is(equalTo(new Date(ms)))); + assertThat(jwt.getExpiresAtAsInstant(), is(equalTo(Instant.ofEpochMilli(ms)))); } @Test public void shouldGetNotBefore() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0NzY3MjcwODZ9.tkpD3iCPQPVqjnjpDVp2bJMBAgpVCG9ZjlBuMitass0"); assertThat(jwt, is(notNullValue())); - assertThat(jwt.getNotBefore(), is(instanceOf(Date.class))); long ms = 1476727086L * 1000; - Date expectedDate = new Date(ms); - assertThat(jwt.getNotBefore(), is(notNullValue())); - assertThat(jwt.getNotBefore(), is(equalTo(expectedDate))); + assertThat(jwt.getNotBefore(), is(equalTo(new Date(ms)))); + assertThat(jwt.getNotBeforeAsInstant(), is(equalTo(Instant.ofEpochMilli(ms)))); } @Test public void shouldGetIssuedAt() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NzY3MjcwODZ9.KPjGoW665E8V5_27Jugab8qSTxLk2cgquhPCBfAP0_w"); assertThat(jwt, is(notNullValue())); - assertThat(jwt.getIssuedAt(), is(instanceOf(Date.class))); long ms = 1476727086L * 1000; - Date expectedDate = new Date(ms); - assertThat(jwt.getIssuedAt(), is(notNullValue())); - assertThat(jwt.getIssuedAt(), is(equalTo(expectedDate))); + assertThat(jwt.getIssuedAt(), is(equalTo(new Date(ms)))); + assertThat(jwt.getIssuedAtAsInstant(), is(equalTo(Instant.ofEpochMilli(ms)))); } @Test @@ -272,6 +267,15 @@ public void shouldGetCustomClaimOfTypeDate() { assertThat(jwt.getClaim("name").asDate().getTime(), is(date.getTime())); } + @Test + public void shouldGetCustomClaimOfTypeInstant() { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; + Instant instant = Instant.ofEpochSecond(1478891521L); + DecodedJWT jwt = JWT.decode(token); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getClaim("name").asInstant(), is(equalTo(instant))); + } + @Test public void shouldGetCustomArrayClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; @@ -294,9 +298,9 @@ public void shouldGetCustomMapClaim() { DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); Map map = jwt.getClaim("name").asMap(); - assertThat(map, hasEntry("string", (Object) "value")); - assertThat(map, hasEntry("number", (Object) 1)); - assertThat(map, hasEntry("boolean", (Object) true)); + assertThat(map, hasEntry("string", "value")); + assertThat(map, hasEntry("number", 1)); + assertThat(map, hasEntry("boolean", true)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index bf7e07da..2015c037 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -21,8 +21,6 @@ import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class JWTTest { @@ -285,9 +283,9 @@ public void shouldGetExpirationTime() { .verify(token); assertThat(jwt, is(notNullValue())); - assertThat(jwt.getExpiresAt(), is(instanceOf(Date.class))); - assertThat(jwt.getExpiresAt(), is(notNullValue())); assertThat(jwt.getExpiresAt(), is(equalTo(new Date(seconds * 1000)))); + assertThat(jwt.getExpiresAtAsInstant(), is(equalTo(Instant.ofEpochSecond(seconds)))); + } @Test @@ -302,9 +300,8 @@ public void shouldGetNotBefore() { .verify(token); assertThat(jwt, is(notNullValue())); - assertThat(jwt.getNotBefore(), is(instanceOf(Date.class))); - assertThat(jwt.getNotBefore(), is(notNullValue())); assertThat(jwt.getNotBefore(), is(equalTo(new Date(seconds * 1000)))); + assertThat(jwt.getNotBeforeAsInstant(), is(equalTo(Instant.ofEpochSecond(seconds)))); } @Test @@ -319,9 +316,8 @@ public void shouldGetIssuedAt() { .verify(token); assertThat(jwt, is(notNullValue())); - assertThat(jwt.getIssuedAt(), is(instanceOf(Date.class))); - assertThat(jwt.getIssuedAt(), is(notNullValue())); assertThat(jwt.getIssuedAt(), is(equalTo(new Date(seconds * 1000)))); + assertThat(jwt.getIssuedAtAsInstant(), is(equalTo(Instant.ofEpochSecond(seconds)))); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 4a3dbb65..acc633fc 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -19,17 +19,15 @@ import java.util.HashMap; import java.util.Map; -import static org.hamcrest.Matchers.startsWith; -import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.*; -import static org.junit.Assert.assertThrows; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.mock; public class JWTVerifierTest { - private Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); - private Clock mockOneSecondEarlier = Clock.offset(mockNow, Duration.ofSeconds(-1)); - private Clock mockOneSecondLater = Clock.offset(mockNow, Duration.ofSeconds(1)); + private final Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); + private final Clock mockOneSecondEarlier = Clock.offset(mockNow, Duration.ofSeconds(-1)); + private final Clock mockOneSecondLater = Clock.offset(mockNow, Duration.ofSeconds(1)); @Rule public ExpectedException exception = ExpectedException.none(); diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java index 3299134d..3c744487 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java @@ -20,14 +20,14 @@ import org.mockito.ArgumentMatchers; import java.io.IOException; +import java.time.Instant; import java.util.*; import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; -import static com.auth0.jwt.impl.JsonNodeClaim.claimFromNode; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class JsonNodeClaimTest { @@ -117,20 +117,23 @@ public void shouldGetNullDoubleIfNotDoubleValue() { } @Test - public void shouldGetDateValue() { - JsonNode value = mapper.valueToTree(1476824844L); + public void shouldGetNumericDateValue() { + long seconds = 1476824844L; + JsonNode value = mapper.valueToTree(seconds); Claim claim = claimFromNode(value); - assertThat(claim.asDate(), is(notNullValue())); - assertThat(claim.asDate(), is(new Date(1476824844L * 1000))); + assertThat(claim.asDate(), is(new Date(seconds * 1000))); + assertThat(claim.asInstant(), is(Instant.ofEpochSecond(seconds))); } @Test - public void shouldGetNullDateIfNotDateValue() { + public void shouldGetNullIfNotNumericDateValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asDate(), is(nullValue())); + assertThat(claimFromNode(objectValue).asInstant(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("1476824844"); assertThat(claimFromNode(stringValue).asDate(), is(nullValue())); + assertThat(claimFromNode(stringValue).asInstant(), is(nullValue())); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java index 84f91c78..bd478130 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java @@ -50,6 +50,11 @@ public void shouldGetAsDate() { assertThat(claim.asDate(), is(nullValue())); } + @Test + public void shouldGetAsInstant() { + assertThat(claim.asInstant(), is(nullValue())); + } + @Test public void shouldGetAsArray() { assertThat(claim.asArray(Object.class), is(nullValue())); diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 16a7198d..96b79afa 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -19,6 +19,7 @@ import org.junit.rules.ExpectedException; import java.io.StringReader; +import java.time.Instant; import java.util.*; import static org.hamcrest.Matchers.*; @@ -96,6 +97,9 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { assertThat(payload.getIssuedAt().getTime(), is(10101010L * 1000)); assertThat(payload.getExpiresAt().getTime(), is(11111111L * 1000)); assertThat(payload.getNotBefore().getTime(), is(10101011L * 1000)); + assertThat(payload.getIssuedAtAsInstant().getEpochSecond(), is(10101010L)); + assertThat(payload.getExpiresAtAsInstant().getEpochSecond(), is(11111111L)); + assertThat(payload.getNotBeforeAsInstant().getEpochSecond(), is(10101011L)); assertThat(payload.getId(), is("idid")); assertThat(payload.getClaim("roles").asString(), is("admin")); @@ -177,24 +181,23 @@ public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() { assertThat(values, is(nullValue())); } - @Test - public void shouldGetNullDateWhenParsingNullNode() { + public void shouldGetNullInstantWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(nullValue())); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(nullValue())); } @Test - public void shouldGetNullDateWhenParsingNull() { + public void shouldGetNullInstantWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(nullValue())); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(nullValue())); } @Test @@ -206,32 +209,33 @@ public void shouldThrowWhenParsingNonNumericNode() { TextNode node = new TextNode("123456789"); tree.put("key", node); - deserializer.getDateFromSeconds(tree, "key"); + deserializer.getInstantFromSeconds(tree, "key"); } @Test - public void shouldGetDateWhenParsingNumericNode() { + public void shouldGetInstantWhenParsingNumericNode() { Map tree = new HashMap<>(); long seconds = 1478627949 / 1000; LongNode node = new LongNode(seconds); tree.put("key", node); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(notNullValue())); - assertThat(date.getTime(), is(seconds * 1000)); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(notNullValue())); + assertThat(instant.toEpochMilli(), is(seconds * 1000)); } + @Test - public void shouldGetLargeDateWhenParsingNumericNode() { + public void shouldGetLargeInstantWhenParsingNumericNode() { Map tree = new HashMap<>(); long seconds = Integer.MAX_VALUE + 10000L; LongNode node = new LongNode(seconds); tree.put("key", node); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(notNullValue())); - assertThat(date.getTime(), is(seconds * 1000)); - assertThat(date.getTime(), is(2147493647L * 1000)); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(notNullValue())); + assertThat(instant.toEpochMilli(), is(seconds * 1000)); + assertThat(instant.toEpochMilli(), is(2147493647L * 1000)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java index 3cf6e023..1d3218ed 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java @@ -11,8 +11,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.Mockito; +import java.time.Instant; import java.util.*; import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; @@ -25,38 +25,33 @@ public class PayloadImplTest { public ExpectedException exception = ExpectedException.none(); private PayloadImpl payload; - private Date expiresAt; - private Date notBefore; - private Date issuedAt; + private final Instant expiresAt = Instant.now().plusSeconds(10); + private final Instant notBefore = Instant.now(); + private final Instant issuedAt = Instant.now(); - private ObjectMapper mapper; private ObjectReader objectReader; @Before public void setUp() { - mapper = getDefaultObjectMapper(); + ObjectMapper mapper = getDefaultObjectMapper(); objectReader = mapper.reader(); - expiresAt = Mockito.mock(Date.class); - notBefore = Mockito.mock(Date.class); - issuedAt = Mockito.mock(Date.class); Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); payload = new PayloadImpl("issuer", "subject", Collections.singletonList("audience"), expiresAt, notBefore, issuedAt, "jwtId", tree, objectReader); } - @SuppressWarnings("Convert2Diamond") @Test public void shouldHaveUnmodifiableTree() { exception.expect(UnsupportedOperationException.class); - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap(), objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap<>(), objectReader); payload.getTree().put("something", null); } @Test public void shouldHaveUnmodifiableAudience() { exception.expect(UnsupportedOperationException.class); - PayloadImpl payload = new PayloadImpl(null, null, new ArrayList(), null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, new ArrayList<>(), null, null, null, null, null, objectReader); payload.getAudience().add("something"); } @@ -104,7 +99,8 @@ public void shouldGetNullAudienceIfMissing() { @Test public void shouldGetExpiresAt() { assertThat(payload, is(notNullValue())); - assertThat(payload.getExpiresAt(), is(expiresAt)); + assertThat(payload.getExpiresAt(), is(Date.from(expiresAt))); + assertThat(payload.getExpiresAtAsInstant(), is(expiresAt)); } @Test @@ -112,12 +108,14 @@ public void shouldGetNullExpiresAtIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getExpiresAt(), is(nullValue())); + assertThat(payload.getExpiresAtAsInstant(), is(nullValue())); } @Test public void shouldGetNotBefore() { assertThat(payload, is(notNullValue())); - assertThat(payload.getNotBefore(), is(notBefore)); + assertThat(payload.getNotBefore(), is(Date.from(notBefore))); + assertThat(payload.getNotBeforeAsInstant(), is(notBefore)); } @Test @@ -125,12 +123,14 @@ public void shouldGetNullNotBeforeIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getNotBefore(), is(nullValue())); + assertThat(payload.getNotBeforeAsInstant(), is(nullValue())); } @Test public void shouldGetIssuedAt() { assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuedAt(), is(issuedAt)); + assertThat(payload.getIssuedAt(), is(Date.from(issuedAt))); + assertThat(payload.getIssuedAtAsInstant(), is(issuedAt)); } @Test @@ -138,6 +138,7 @@ public void shouldGetNullIssuedAtIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuedAt(), is(nullValue())); + assertThat(payload.getIssuedAtAsInstant(), is(nullValue())); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java new file mode 100644 index 00000000..120f6a9d --- /dev/null +++ b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java @@ -0,0 +1,93 @@ +package com.auth0.jwt.interfaces; + +import com.auth0.jwt.exceptions.JWTDecodeException; +import org.junit.Test; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class ClaimTest { + + @Test + public void shouldGetInstantUsingDefault() { + Date date = new Date(1646667492000L); + Claim claim = new ClaimImplForTest(date); + assertThat(claim.asInstant(), is(date.toInstant())); + } + + @Test + public void shouldGetNullInstantUsingDefault() { + Claim claim = new ClaimImplForTest(null); + assertThat(claim.asInstant(), is(nullValue())); + } + + /** + * Implementation that does not override {@code asInstant()} + */ + static class ClaimImplForTest implements Claim { + private final Date date; + + ClaimImplForTest(Date date) { + this.date = date; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public Boolean asBoolean() { + return null; + } + + @Override + public Integer asInt() { + return null; + } + + @Override + public Long asLong() { + return null; + } + + @Override + public Double asDouble() { + return null; + } + + @Override + public String asString() { + return null; + } + + @Override + public Date asDate() { + return date; + } + + @Override + public T[] asArray(Class tClazz) throws JWTDecodeException { + return null; + } + + @Override + public List asList(Class tClazz) throws JWTDecodeException { + return null; + } + + @Override + public Map asMap() throws JWTDecodeException { + return null; + } + + @Override + public T as(Class tClazz) throws JWTDecodeException { + return null; + } + } +} diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java new file mode 100644 index 00000000..c5d2bd00 --- /dev/null +++ b/lib/src/test/java/com/auth0/jwt/interfaces/PayloadTest.java @@ -0,0 +1,83 @@ +package com.auth0.jwt.interfaces; + +import org.junit.Test; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +public class PayloadTest { + + @Test + public void shouldGetInstantFromDefault() { + Date date = new Date(1646667492000L); + Payload payload = new PayloadImplForTest(date); + assertThat(payload.getExpiresAtAsInstant(), is(date.toInstant())); + assertThat(payload.getIssuedAtAsInstant(), is(date.toInstant())); + assertThat(payload.getNotBeforeAsInstant(), is(date.toInstant())); + } + + @Test + public void shouldGetInstantFromDefaultAsNu() { + Payload payload = new PayloadImplForTest(null); + assertThat(payload.getExpiresAtAsInstant(), is(nullValue())); + assertThat(payload.getIssuedAtAsInstant(), is(nullValue())); + assertThat(payload.getNotBeforeAsInstant(), is(nullValue())); + } + + static class PayloadImplForTest implements Payload { + private final Date date; + + PayloadImplForTest(Date date) { + this.date = date; + } + + @Override + public String getIssuer() { + return null; + } + + @Override + public String getSubject() { + return null; + } + + @Override + public List getAudience() { + return null; + } + + @Override + public Date getExpiresAt() { + return date; + } + + @Override + public Date getNotBefore() { + return date; + } + + @Override + public Date getIssuedAt() { + return date; + } + + @Override + public String getId() { + return null; + } + + @Override + public Claim getClaim(String name) { + return null; + } + + @Override + public Map getClaims() { + return null; + } + } +} From fef3ccf0e03b4557faa110432466c631c0cc3fff Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Fri, 11 Mar 2022 09:41:55 -0600 Subject: [PATCH 009/134] Update test dependencies (#539) --- lib/build.gradle | 13 +++++++------ lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java | 6 +++--- lib/src/test/java/com/auth0/jwt/JWTTest.java | 6 +++--- .../com/auth0/jwt/impl/PayloadDeserializerTest.java | 8 ++++---- .../java/com/auth0/jwt/impl/PayloadImplTest.java | 4 ++-- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/build.gradle b/lib/build.gradle index 2bb5c599..9dcf7e40 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -48,11 +48,12 @@ javadoc { dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.6' - testImplementation 'org.bouncycastle:bcprov-jdk15on:1.60' - testImplementation 'junit:junit:4.12' - testImplementation 'net.jodah:concurrentunit:0.4.3' - testImplementation 'org.hamcrest:java-hamcrest:2.0.0.0' - testImplementation 'org.mockito:mockito-core:2.18.3' + + testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' + testImplementation 'junit:junit:4.13.2' + testImplementation 'net.jodah:concurrentunit:0.4.6' + testImplementation 'org.hamcrest:hamcrest:2.2' + testImplementation 'org.mockito:mockito-core:4.4.0' } jacoco { @@ -92,7 +93,7 @@ task compileModuleInfoJava(type: JavaCompile) { } compileTestJava { - options.compilerArgs = ['--release', "8"] + options.compilerArgs = ['--release', "8", "-Xlint:deprecation"] } def testJava8 = tasks.register('testJava8', Test) { diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index a9e8f248..626bc6fd 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -5,7 +5,7 @@ import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.core.IsCollectionContaining; +import org.hamcrest.core.IsIterableContaining; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -142,7 +142,7 @@ public void shouldGetArrayAudience() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(3))); - assertThat(jwt.getAudience(), is(IsCollectionContaining.hasItems("Hope", "Travis", "Solomon"))); + assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Hope", "Travis", "Solomon"))); } @Test @@ -150,7 +150,7 @@ public void shouldGetStringAudience() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(1))); - assertThat(jwt.getAudience(), is(IsCollectionContaining.hasItems("Jack Reyes"))); + assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Jack Reyes"))); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index 2015c037..35ad4971 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -3,7 +3,7 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.core.IsCollectionContaining; +import org.hamcrest.core.IsIterableContaining; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -256,7 +256,7 @@ public void shouldGetArrayAudience() { assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(3))); - assertThat(jwt.getAudience(), is(IsCollectionContaining.hasItems("Hope", "Travis", "Solomon"))); + assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Hope", "Travis", "Solomon"))); } @Test @@ -268,7 +268,7 @@ public void shouldGetStringAudience() { assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(1))); - assertThat(jwt.getAudience(), is(IsCollectionContaining.hasItems("Jack Reyes"))); + assertThat(jwt.getAudience(), is(IsIterableContaining.hasItems("Jack Reyes"))); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 96b79afa..2d80bed9 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.databind.node.*; import org.hamcrest.collection.IsCollectionWithSize; import org.hamcrest.collection.IsEmptyCollection; -import org.hamcrest.core.IsCollectionContaining; +import org.hamcrest.core.IsIterableContaining; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -93,7 +93,7 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { assertThat(payload, is(notNullValue())); assertThat(payload.getIssuer(), is("auth0")); assertThat(payload.getSubject(), is("emails")); - assertThat(payload.getAudience(), is(IsCollectionContaining.hasItem("users"))); + assertThat(payload.getAudience(), is(IsIterableContaining.hasItem("users"))); assertThat(payload.getIssuedAt().getTime(), is(10101010L * 1000)); assertThat(payload.getExpiresAt().getTime(), is(11111111L * 1000)); assertThat(payload.getNotBefore().getTime(), is(10101011L * 1000)); @@ -126,7 +126,7 @@ public void shouldGetStringArrayWhenParsingArrayNode() { List values = deserializer.getStringOrArray(tree, "key"); assertThat(values, is(notNullValue())); assertThat(values, is(IsCollectionWithSize.hasSize(2))); - assertThat(values, is(IsCollectionContaining.hasItems("one", "two"))); + assertThat(values, is(IsIterableContaining.hasItems("one", "two"))); } @Test @@ -138,7 +138,7 @@ public void shouldGetStringArrayWhenParsingTextNode() { List values = deserializer.getStringOrArray(tree, "key"); assertThat(values, is(notNullValue())); assertThat(values, is(IsCollectionWithSize.hasSize(1))); - assertThat(values, is(IsCollectionContaining.hasItems("something"))); + assertThat(values, is(IsIterableContaining.hasItems("something"))); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java index 1d3218ed..9e2e6902 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.node.TextNode; import org.hamcrest.collection.IsCollectionWithSize; -import org.hamcrest.core.IsCollectionContaining; +import org.hamcrest.core.IsIterableContaining; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -86,7 +86,7 @@ public void shouldGetAudience() { assertThat(payload, is(notNullValue())); assertThat(payload.getAudience(), is(IsCollectionWithSize.hasSize(1))); - assertThat(payload.getAudience(), is(IsCollectionContaining.hasItems("audience"))); + assertThat(payload.getAudience(), is(IsIterableContaining.hasItems("audience"))); } @Test From 98a6c9643300497d0c18b6392e6ee066de4dcec5 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 16 Mar 2022 08:03:28 -0500 Subject: [PATCH 010/134] [SDK-3186] Support date/time custom claim validation (#538) * [SDK-3186] Support date/time custom claim validation * Add tests for Verification default method implementations * add tests for null expected claim handling * updated javadoc per code review suggestion --- .../main/java/com/auth0/jwt/JWTVerifier.java | 12 +- .../auth0/jwt/interfaces/Verification.java | 17 +- .../java/com/auth0/jwt/JWTVerifierTest.java | 13 +- .../jwt/interfaces/VerificationTest.java | 162 ++++++++++++++++++ 4 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 8dfb6dbf..5bcc7bc7 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -174,8 +174,14 @@ public Verification withClaim(String name, String value) throws IllegalArgumentE @Override public Verification withClaim(String name, Date value) throws IllegalArgumentException { + return withClaim(name, value != null ? value.toInstant() : null); + } + + @Override + public Verification withClaim(String name, Instant value) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, value); + // Since date-time claims are serialized as epoch seconds, we need to compare them with only seconds-granularity + requireClaim(name, value != null ? value.truncatedTo(ChronoUnit.SECONDS) : null); return this; } @@ -371,8 +377,8 @@ private void assertValidClaim(Claim claim, String claimName, Object value) { isValid = value.equals(claim.asBoolean()); } else if (value instanceof Double) { isValid = value.equals(claim.asDouble()); - } else if (value instanceof Date) { - isValid = value.equals(claim.asDate()); + } else if (value instanceof Instant) { + isValid = value.equals(claim.asInstant()); } else if (value instanceof Object[]) { List claimArr; Object[] claimAsObject = claim.as(Object[].class); diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index cd2061d7..1fb6aece 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -2,6 +2,7 @@ import com.auth0.jwt.JWTVerifier; +import java.time.Instant; import java.util.Date; /** @@ -176,7 +177,8 @@ default Verification withAnyOfAudience(String... audience) { Verification withClaim(String name, String value) throws IllegalArgumentException; /** - * Require a specific Claim value. + * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; when verifying + * date-time claim value, any time units more granular than seconds will not be considered. * * @param name the Claim's name. * @param value the Claim's value. @@ -185,6 +187,19 @@ default Verification withAnyOfAudience(String... audience) { */ Verification withClaim(String name, Date value) throws IllegalArgumentException; + /** + * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; when verifying + * a date-time claim value, any time units more granular than seconds will not be considered. + * + * @param name the Claim's name. + * @param value the Claim's value. + * @return this same Verification instance. + * @throws IllegalArgumentException if the name is null. + */ + default Verification withClaim(String name, Instant value) throws IllegalArgumentException { + return withClaim(name, value != null ? Date.from(value) : null); + } + /** * Require a specific Array Claim to contain at least the given items. * diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index acc633fc..93a7bcd1 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -517,7 +517,7 @@ public void shouldValidateCustomClaimOfTypeBoolean() { @Test public void shouldValidateCustomClaimOfTypeDate() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; - Date date = new Date(1478891521000L); + Date date = new Date(1478891521123L); DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", date) .build() @@ -526,6 +526,17 @@ public void shouldValidateCustomClaimOfTypeDate() { assertThat(jwt, is(notNullValue())); } + @Test + public void shouldRemoveCustomClaimOfTypeDateWhenNull() { + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", new Date()) + .withClaim("name", (Date) null) + .build(); + + assertThat(verifier.claims, is(notNullValue())); + assertThat(verifier.claims, not(hasKey("iss"))); + } + @Test public void shouldValidateCustomArrayClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java new file mode 100644 index 00000000..e9f4f815 --- /dev/null +++ b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java @@ -0,0 +1,162 @@ +package com.auth0.jwt.interfaces; + +import com.auth0.jwt.JWTVerifier; +import org.junit.Test; + +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThrows; + +/** + * Tests for any default method implementations in the {@link Verification} interface. + */ +public class VerificationTest { + + @Test + public void withInstantClaimShouldUseDefaultImpl() { + Instant instant = Instant.ofEpochSecond(1478891521); + Verification verification = new VerificationImplForTest() + .withClaim("name", instant); + + assertThat(verification, instanceOf(VerificationImplForTest.class)); + assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("name", Date.from(instant))); + } + + @Test + public void withInstantClaimShouldUseDefaultImplAndHandleNull() { + Verification verification = new VerificationImplForTest() + .withClaim("name", (Instant) null); + + assertThat(verification, instanceOf(VerificationImplForTest.class)); + assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("name", null)); + } + + @Test + public void withAnyOfAudienceDeafultImplShouldThrow() { + assertThrows("withAnyOfAudience", UnsupportedOperationException.class, () -> { + new VerificationImplForTest().withAnyOfAudience(""); + }); + } + + @Test + public void withIssuerStringDefaultImplShouldDelegate() { + Verification verification = new VerificationImplForTest() + .withIssuer("string"); + + assertThat(verification, instanceOf(VerificationImplForTest.class)); + assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("iss", new String[]{"string"})); + } + + static class VerificationImplForTest implements Verification { + + private final Map expectedClaims = new HashMap<>(); + + @Override + public Verification withIssuer(String... issuer) { + expectedClaims.put("iss", issuer); + return this; + } + + @Override + public Verification withSubject(String subject) { + return null; + } + + @Override + public Verification withAudience(String... audience) { + return null; + } + + @Override + public Verification acceptLeeway(long leeway) throws IllegalArgumentException { + return null; + } + + @Override + public Verification acceptExpiresAt(long leeway) throws IllegalArgumentException { + return null; + } + + @Override + public Verification acceptNotBefore(long leeway) throws IllegalArgumentException { + return null; + } + + @Override + public Verification acceptIssuedAt(long leeway) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withJWTId(String jwtId) { + return null; + } + + @Override + public Verification withClaimPresence(String name) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withClaim(String name, Integer value) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withClaim(String name, Long value) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withClaim(String name, Double value) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withClaim(String name, String value) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withClaim(String name, Date value) throws IllegalArgumentException { + this.expectedClaims.put(name, value); + return this; + } + + @Override + public Verification withArrayClaim(String name, String... items) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException { + return null; + } + + @Override + public Verification withArrayClaim(String name, Long... items) throws IllegalArgumentException { + return null; + } + + @Override + public Verification ignoreIssuedAt() { + return null; + } + + @Override + public JWTVerifier build() { + return null; + } + } +} From 1433810366a592bf3fd2be48f1cb28ebcf3b42e6 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 16 Mar 2022 18:46:50 +0530 Subject: [PATCH 011/134] Undeprecate Single Key Constructor for Algorithms (#551) --- .../java/com/auth0/jwt/algorithms/Algorithm.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index d6a3a2f4..6fec5b71 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -48,9 +48,7 @@ public static Algorithm RSA256(RSAPublicKey publicKey, RSAPrivateKey privateKey) * @param key the key to use in the verify or signing instance. * @return a valid RSA256 Algorithm. * @throws IllegalArgumentException if the Key Provider is null. - * @deprecated use {@link #RSA256(RSAPublicKey, RSAPrivateKey)} or {@link #RSA256(RSAKeyProvider)} */ - @Deprecated public static Algorithm RSA256(RSAKey key) throws IllegalArgumentException { RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null; RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null; @@ -86,9 +84,7 @@ public static Algorithm RSA384(RSAPublicKey publicKey, RSAPrivateKey privateKey) * @param key the key to use in the verify or signing instance. * @return a valid RSA384 Algorithm. * @throws IllegalArgumentException if the provided Key is null. - * @deprecated use {@link #RSA384(RSAPublicKey, RSAPrivateKey)} or {@link #RSA384(RSAKeyProvider)} */ - @Deprecated public static Algorithm RSA384(RSAKey key) throws IllegalArgumentException { RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null; RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null; @@ -124,9 +120,7 @@ public static Algorithm RSA512(RSAPublicKey publicKey, RSAPrivateKey privateKey) * @param key the key to use in the verify or signing instance. * @return a valid RSA512 Algorithm. * @throws IllegalArgumentException if the provided Key is null. - * @deprecated use {@link #RSA512(RSAPublicKey, RSAPrivateKey)} or {@link #RSA512(RSAKeyProvider)} */ - @Deprecated public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException { RSAPublicKey publicKey = key instanceof RSAPublicKey ? (RSAPublicKey) key : null; RSAPrivateKey privateKey = key instanceof RSAPrivateKey ? (RSAPrivateKey) key : null; @@ -253,9 +247,7 @@ public static Algorithm ECDSA256(ECPublicKey publicKey, ECPrivateKey privateKey) * @param key the key to use in the verify or signing instance. * @return a valid ECDSA256 Algorithm. * @throws IllegalArgumentException if the provided Key is null. - * @deprecated use {@link #ECDSA256(ECPublicKey, ECPrivateKey)} or {@link #ECDSA256(ECDSAKeyProvider)} */ - @Deprecated public static Algorithm ECDSA256(ECKey key) throws IllegalArgumentException { ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null; ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null; @@ -291,9 +283,7 @@ public static Algorithm ECDSA384(ECPublicKey publicKey, ECPrivateKey privateKey) * @param key the key to use in the verify or signing instance. * @return a valid ECDSA384 Algorithm. * @throws IllegalArgumentException if the provided Key is null. - * @deprecated use {@link #ECDSA384(ECPublicKey, ECPrivateKey)} or {@link #ECDSA384(ECDSAKeyProvider)} */ - @Deprecated public static Algorithm ECDSA384(ECKey key) throws IllegalArgumentException { ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null; ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null; @@ -329,9 +319,7 @@ public static Algorithm ECDSA512(ECPublicKey publicKey, ECPrivateKey privateKey) * @param key the key to use in the verify or signing instance. * @return a valid ECDSA512 Algorithm. * @throws IllegalArgumentException if the provided Key is null. - * @deprecated use {@link #ECDSA512(ECPublicKey, ECPrivateKey)} or {@link #ECDSA512(ECDSAKeyProvider)} */ - @Deprecated public static Algorithm ECDSA512(ECKey key) throws IllegalArgumentException { ECPublicKey publicKey = key instanceof ECPublicKey ? (ECPublicKey) key : null; ECPrivateKey privateKey = key instanceof ECPrivateKey ? (ECPrivateKey) key : null; From e7cae2b56f51143b4cd373639f65557e0877c0ff Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 16 Mar 2022 18:47:16 +0530 Subject: [PATCH 012/134] Update document and remove deprecation notice for content sign methods (#550) --- .../java/com/auth0/jwt/algorithms/Algorithm.java | 3 +-- .../java/com/auth0/jwt/algorithms/CryptoHelper.java | 12 ++++-------- .../com/auth0/jwt/algorithms/ECDSAAlgorithm.java | 1 - .../java/com/auth0/jwt/algorithms/HMACAlgorithm.java | 1 - .../java/com/auth0/jwt/algorithms/NoneAlgorithm.java | 1 - .../java/com/auth0/jwt/algorithms/RSAAlgorithm.java | 1 - 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index 6fec5b71..0b4e74b7 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -397,14 +397,13 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene /** * Sign the given content using this Algorithm instance. + * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} * * @param contentBytes an array of bytes representing the base64 encoded content to be verified against the signature. * @return the signature in a base64 encoded array of bytes * @throws SignatureGenerationException if the Key is invalid. - * @deprecated Please use the {@linkplain #sign(byte[], byte[])} method instead. */ - @Deprecated public abstract byte[] sign(byte[] contentBytes) throws SignatureGenerationException; } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java index 62aec632..26a87bc4 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java @@ -131,6 +131,7 @@ byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] header /** * Verify signature. + * For valid verification, ensure the content is in the format {HEADER}.{PAYLOAD} * * @param algorithm algorithm name. * @param secretBytes algorithm secret. @@ -139,16 +140,15 @@ byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] header * @return true if signature is valid. * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, contentBytes), signatureBytes); } /** * Create signature. + * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} * * @param algorithm algorithm name. * @param secretBytes algorithm secret. @@ -156,10 +156,8 @@ boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] contentB * @return the signature bytes. * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException { final Mac mac = Mac.getInstance(algorithm); mac.init(new SecretKeySpec(secretBytes, algorithm)); @@ -168,6 +166,7 @@ byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBy /** * Verify signature using a public key. + * For valid verification, ensure the content is in the format {HEADER}.{PAYLOAD} * * @param algorithm algorithm name. * @param publicKey algorithm public key. @@ -177,10 +176,8 @@ byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBy * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. - * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initVerify(publicKey); @@ -190,6 +187,7 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] content /** * Create signature using a private key. + * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} * * @param algorithm algorithm name. * @param privateKey the private key to use for signing. @@ -198,10 +196,8 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] content * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. - * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initSign(privateKey); diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index c2d08a15..51fa70fa 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -71,7 +71,6 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene } @Override - @Deprecated public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { try { ECPrivateKey privateKey = keyProvider.getPrivateKey(); diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java index c5792457..26ad6a87 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java @@ -69,7 +69,6 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene } @Override - @Deprecated public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { try { return crypto.createSignatureFor(getDescription(), secret, contentBytes); diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java index 076a6b94..ade07b0e 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java @@ -31,7 +31,6 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene } @Override - @Deprecated public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { return new byte[0]; } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java index 31773a09..cd1e97a5 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java @@ -55,7 +55,6 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { } @Override - @Deprecated public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException { try { RSAPrivateKey privateKey = keyProvider.getPrivateKey(); From 7f45ff7f25b00f17e4dd55e584f2e1c7b8d9a432 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 16 Mar 2022 21:18:41 +0530 Subject: [PATCH 013/134] Catch up v4 to master (#552) * Bump `jackson-databind` dependency to 2.13.2 (#542) * Bump `jackson-databind` dependency to 2.13 * Update build.gradle * Update build.gradle * Deprecate ES256K Algorithm (#543) * [SDK-3192] Deprecate secp256k1 curve for EC Algorithms * Documentation update * Release 3.19.0 Co-authored-by: Evan Sims Co-authored-by: James Anderson --- CHANGELOG.md | 12 ++++++++++++ README.md | 4 ++-- lib/build.gradle | 2 +- .../java/com/auth0/jwt/algorithms/Algorithm.java | 8 ++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8231d4..84686b4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## [3.19.0](https://github.com/auth0/java-jwt/tree/3.19.0) (2022-03-14) +[Full Changelog](https://github.com/auth0/java-jwt/compare/3.18.3...3.19.0) + +**Deprecated** +- Deprecate ES256K Algorithm [\#543](https://github.com/auth0/java-jwt/pull/543) ([poovamraj](https://github.com/poovamraj)) + +**Fixed** +- fix typos in JWTVerifier#verify docstring [\#526](https://github.com/auth0/java-jwt/pull/526) ([OdunlamiZO](https://github.com/OdunlamiZO)) + +**Security** +- Bump `jackson-databind` dependency to 2.13.2 [\#542](https://github.com/auth0/java-jwt/pull/542) ([evansims](https://github.com/evansims)) + ## [3.18.3](https://github.com/auth0/java-jwt/tree/3.18.3) (2022-01-13) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.18.2...3.18.3) diff --git a/README.md b/README.md index 9fbb2138..0f847cca 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ The library is available on both Maven Central and Bintray, and the Javadoc is p com.auth0 java-jwt - 3.18.3 + 3.19.0 ``` ### Gradle ```gradle -implementation 'com.auth0:java-jwt:3.18.3' +implementation 'com.auth0:java-jwt:3.19.0' ``` ## Available Algorithms diff --git a/lib/build.gradle b/lib/build.gradle index 9dcf7e40..a83ccbc5 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -47,7 +47,7 @@ javadoc { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.6' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index 0b4e74b7..f3405f6e 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -177,7 +177,11 @@ public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. * @return a valid ECDSA256 Algorithm. * @throws IllegalArgumentException if the Key Provider is null. + * @deprecated The SECP-256K1 Curve algorithm has been disabled beginning in Java 15. + * Use of this method in those unsupported Java versions will throw a {@link java.security.SignatureException}. + * This method will be removed in the next major version. See for additional information */ + @Deprecated public static Algorithm ECDSA256K(ECDSAKeyProvider keyProvider) throws IllegalArgumentException { return new ECDSAAlgorithm("ES256K", "SHA256withECDSA", 32, keyProvider); } @@ -189,7 +193,11 @@ public static Algorithm ECDSA256K(ECDSAKeyProvider keyProvider) throws IllegalAr * @param privateKey the key to use in the signing instance. * @return a valid ECDSA256 Algorithm. * @throws IllegalArgumentException if the provided Key is null. + * @deprecated The SECP-256K1 Curve algorithm has been disabled beginning in Java 15. + * Use of this method in those unsupported Java versions will throw a {@link java.security.SignatureException}. + * This method will be removed in the next major version. See for additional information */ + @Deprecated public static Algorithm ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException { return ECDSA256K(ECDSAAlgorithm.providerForKeys(publicKey, privateKey)); } From 3b51ee8a4694ffef1b1ffbd60c4cbe8eaa940108 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 16 Mar 2022 15:01:22 -0500 Subject: [PATCH 014/134] [SDK-3171] Fix header claims serialization (#549) * [SDK-3171] Fix header claims serialization * remove debug line --- .../main/java/com/auth0/jwt/JWTCreator.java | 11 ++- .../java/com/auth0/jwt/impl/ClaimsHolder.java | 6 +- .../com/auth0/jwt/impl/ClaimsSerializer.java | 86 +++++++++++++++++++ .../auth0/jwt/impl/HeaderClaimsHolder.java | 12 +++ .../com/auth0/jwt/impl/HeaderSerializer.java | 10 +++ .../auth0/jwt/impl/PayloadClaimsHolder.java | 12 +++ .../com/auth0/jwt/impl/PayloadSerializer.java | 85 ++++-------------- .../java/com/auth0/jwt/JWTCreatorTest.java | 40 +++++++-- .../java/com/auth0/jwt/JWTDecoderTest.java | 30 +++++++ ...Test.java => PayloadClaimsHolderTest.java} | 9 +- .../auth0/jwt/impl/PayloadSerializerTest.java | 60 +++++++------ 11 files changed, 242 insertions(+), 119 deletions(-) create mode 100644 lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java create mode 100644 lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java create mode 100644 lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java create mode 100644 lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java rename lib/src/test/java/com/auth0/jwt/impl/{ClaimsHolderTest.java => PayloadClaimsHolderTest.java} (80%) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index 7d58fe2f..ca6e3918 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -3,9 +3,7 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTCreationException; import com.auth0.jwt.exceptions.SignatureGenerationException; -import com.auth0.jwt.impl.ClaimsHolder; -import com.auth0.jwt.impl.PayloadSerializer; -import com.auth0.jwt.impl.PublicClaims; +import com.auth0.jwt.impl.*; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; @@ -34,7 +32,8 @@ public final class JWTCreator { static { mapper = new ObjectMapper(); module = new SimpleModule(); - module.addSerializer(ClaimsHolder.class, new PayloadSerializer()); + module.addSerializer(PayloadClaimsHolder.class, new PayloadSerializer()); + module.addSerializer(HeaderClaimsHolder.class, new HeaderSerializer()); mapper.registerModule(module); mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); } @@ -42,8 +41,8 @@ public final class JWTCreator { private JWTCreator(Algorithm algorithm, Map headerClaims, Map payloadClaims) throws JWTCreationException { this.algorithm = algorithm; try { - headerJson = mapper.writeValueAsString(headerClaims); - payloadJson = mapper.writeValueAsString(new ClaimsHolder(payloadClaims)); + headerJson = mapper.writeValueAsString(new HeaderClaimsHolder(headerClaims)); + payloadJson = mapper.writeValueAsString(new PayloadClaimsHolder(payloadClaims)); } catch (JsonProcessingException e) { throw new JWTCreationException("Some of the Claims couldn't be converted to a valid JSON format.", e); } diff --git a/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java b/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java index 17602199..30f6ab18 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java +++ b/lib/src/main/java/com/auth0/jwt/impl/ClaimsHolder.java @@ -6,11 +6,11 @@ /** * The ClaimsHolder class is just a wrapper for the Map of Claims used for building a JWT. */ -public final class ClaimsHolder { +public abstract class ClaimsHolder { private Map claims; - public ClaimsHolder(Map claims) { - this.claims = claims == null ? new HashMap() : claims; + protected ClaimsHolder(Map claims) { + this.claims = claims == null ? new HashMap<>() : claims; } Map getClaims() { diff --git a/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java new file mode 100644 index 00000000..4db20119 --- /dev/null +++ b/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java @@ -0,0 +1,86 @@ +package com.auth0.jwt.impl; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import java.io.IOException; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * Custom serializer used to write the resulting JWT. + * + * @param the type this serializer operates on. + */ +public class ClaimsSerializer extends StdSerializer { + + public ClaimsSerializer(Class t) { + super(t); + } + + @Override + public void serialize(T holder, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeStartObject(); + for (Map.Entry entry : holder.getClaims().entrySet()) { + writeClaim(entry, gen); + } + gen.writeEndObject(); + } + + /** + * Writes the given entry to the JSON representation. Custom claim serialization handling can override this method + * to provide use-case specific serialization. Implementors who override this method must write the field name and the + * field value. + * + * @param entry The entry that corresponds to the JSON field to write + * @param gen The {@code JsonGenerator} to use + * @throws IOException + */ + protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { + gen.writeFieldName(entry.getKey()); + handleSerialization(entry.getValue(), gen); + } + + private static void handleSerialization(Object value, JsonGenerator gen) throws IOException { + if (value instanceof Date) { + gen.writeNumber(dateToSeconds((Date) value)); + } else if (value instanceof Instant) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom Instant claims + gen.writeNumber(instantToSeconds((Instant) value)); + } else if (value instanceof Map) { + serializeMap((Map) value, gen); + } else if (value instanceof List) { + serializeList((List) value, gen); + } else { + gen.writeObject(value); + } + } + + private static void serializeMap(Map map, JsonGenerator gen) throws IOException { + gen.writeStartObject(); + for (Map.Entry entry : map.entrySet()) { + gen.writeFieldName((String) entry.getKey()); + Object value = entry.getValue(); + handleSerialization(value, gen); + } + gen.writeEndObject(); + } + + private static void serializeList(List list, JsonGenerator gen) throws IOException { + gen.writeStartArray(); + for (Object entry : list) { + handleSerialization(entry, gen); + } + gen.writeEndArray(); + } + + private static long instantToSeconds(Instant instant) { + return instant.getEpochSecond(); + } + + private static long dateToSeconds(Date date) { + return date.getTime() / 1000; + } +} diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java new file mode 100644 index 00000000..9b480116 --- /dev/null +++ b/lib/src/main/java/com/auth0/jwt/impl/HeaderClaimsHolder.java @@ -0,0 +1,12 @@ +package com.auth0.jwt.impl; + +import java.util.Map; + +/** + * Holds the header claims when serializing a JWT. + */ +public final class HeaderClaimsHolder extends ClaimsHolder { + public HeaderClaimsHolder(Map claims) { + super(claims); + } +} diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java new file mode 100644 index 00000000..5c7cf0fc --- /dev/null +++ b/lib/src/main/java/com/auth0/jwt/impl/HeaderSerializer.java @@ -0,0 +1,10 @@ +package com.auth0.jwt.impl; + +/** + * Responsible for serializing a JWT's header representation to JSON. + */ +public class HeaderSerializer extends ClaimsSerializer { + public HeaderSerializer() { + super(HeaderClaimsHolder.class); + } +} diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java new file mode 100644 index 00000000..7055a2ce --- /dev/null +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadClaimsHolder.java @@ -0,0 +1,12 @@ +package com.auth0.jwt.impl; + +import java.util.Map; + +/** + * Holds the payload claims when serializing a JWT. + */ +public final class PayloadClaimsHolder extends ClaimsHolder { + public PayloadClaimsHolder(Map claims) { + super(claims); + } +} diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index 0389121c..497a3a94 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -1,12 +1,12 @@ package com.auth0.jwt.impl; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; -import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; /** * Jackson serializer implementation for converting into JWT Payload parts. @@ -15,32 +15,26 @@ *

* This class is thread-safe. */ -public class PayloadSerializer extends StdSerializer { - +public class PayloadSerializer extends ClaimsSerializer { public PayloadSerializer() { - this(null); - } - - private PayloadSerializer(Class t) { - super(t); + super(PayloadClaimsHolder.class); } @Override - public void serialize(ClaimsHolder holder, JsonGenerator gen, SerializerProvider provider) throws IOException { - - gen.writeStartObject(); - for (Map.Entry e : holder.getClaims().entrySet()) { - if (PublicClaims.AUDIENCE.equals(e.getKey())) { - writeAudience(gen, e); - } else { - gen.writeFieldName(e.getKey()); - handleSerialization(e.getValue(), gen); - } + protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { + if (PublicClaims.AUDIENCE.equals(entry.getKey())) { + writeAudience(gen, entry); + } else { + super.writeClaim(entry, gen); } - - gen.writeEndObject(); } + /** + * Audience may be a list of strings or a single string. This is needed to properly handle the aud claim when + * added with the {@linkplain com.auth0.jwt.JWTCreator.Builder#withPayload(Map)} method. + */ + + // private void writeAudience(JsonGenerator gen, Map.Entry e) throws IOException { if (e.getValue() instanceof String) { gen.writeFieldName(e.getKey()); @@ -70,49 +64,4 @@ private void writeAudience(JsonGenerator gen, Map.Entry e) throw } } } - - /** - * Serializes {@linkplain Instant} to epoch second values, traversing maps and lists as needed. - * @param value the object to serialize - * @param gen the JsonGenerator to use for JSON serialization - */ - private void handleSerialization(Object value, JsonGenerator gen) throws IOException { - if (value instanceof Date) { - gen.writeNumber(dateToSeconds((Date) value)); - } else if (value instanceof Instant) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom Instant claims - gen.writeNumber(instantToSeconds((Instant) value)); - } else if (value instanceof Map) { - serializeMap((Map) value, gen); - } else if (value instanceof List) { - serializeList((List) value, gen); - } else { - gen.writeObject(value); - } - } - - private void serializeMap(Map map, JsonGenerator gen) throws IOException { - gen.writeStartObject(); - for (Map.Entry entry : map.entrySet()) { - gen.writeFieldName((String) entry.getKey()); - Object value = entry.getValue(); - handleSerialization(value, gen); - } - gen.writeEndObject(); - } - - private void serializeList(List list, JsonGenerator gen) throws IOException { - gen.writeStartArray(); - for (Object entry : list) { - handleSerialization(entry, gen); - } - gen.writeEndArray(); - } - - private long instantToSeconds(Instant instant) { - return instant.getEpochSecond(); - } - - private long dateToSeconds(Date date) { - return date.getTime() / 1000; - } } diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index c6fff1f2..96976166 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -5,7 +5,6 @@ import com.auth0.jwt.interfaces.ECDSAKeyProvider; import com.auth0.jwt.interfaces.RSAKeyProvider; import com.fasterxml.jackson.databind.ObjectMapper; - import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -16,8 +15,8 @@ import java.time.Instant; import java.util.*; -import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -39,11 +38,32 @@ public void shouldThrowWhenRequestingSignWithoutAlgorithm() { .sign(null); } - @SuppressWarnings("Convert2Diamond") @Test public void shouldAddHeaderClaim() { - Map header = new HashMap(); - header.put("asd", 123); + Date date = new Date(123000); + Instant instant = date.toInstant(); + + List list = Arrays.asList(date, instant); + Map map = new HashMap<>(); + map.put("date", date); + map.put("instant", instant); + + List expectedSerializedList = Arrays.asList(date.getTime() / 1000, instant.getEpochSecond()); + Map expectedSerializedMap = new HashMap<>(); + expectedSerializedMap.put("date", date.getTime() / 1000); + expectedSerializedMap.put("instant", instant.getEpochSecond()); + + Map header = new HashMap<>(); + header.put("string", "string"); + header.put("int", 42); + header.put("long", 4200000000L); + header.put("double", 123.123); + header.put("bool", true); + header.put("date", date); + header.put("instant", instant); + header.put("list", list); + header.put("map", map); + String signed = JWTCreator.init() .withHeader(header) .sign(Algorithm.HMAC256("secret")); @@ -51,7 +71,15 @@ public void shouldAddHeaderClaim() { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("asd", 123)); + assertThat(headerJson, JsonMatcher.hasEntry("string", "string")); + assertThat(headerJson, JsonMatcher.hasEntry("int", 42)); + assertThat(headerJson, JsonMatcher.hasEntry("long", 4200000000L)); + assertThat(headerJson, JsonMatcher.hasEntry("double", 123.123)); + assertThat(headerJson, JsonMatcher.hasEntry("bool", true)); + assertThat(headerJson, JsonMatcher.hasEntry("date", 123)); + assertThat(headerJson, JsonMatcher.hasEntry("instant", 123)); + assertThat(headerJson, JsonMatcher.hasEntry("list", expectedSerializedList)); + assertThat(headerJson, JsonMatcher.hasEntry("map", expectedSerializedMap)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 626bc6fd..32db703e 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -15,6 +15,7 @@ import java.time.Instant; import java.util.Base64; import java.util.Date; +import java.util.List; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; @@ -347,6 +348,35 @@ public void shouldSerializeAndDeserialize() throws Exception { is(equalTo(deserializedJwt.getClaims().get("extraClaim").asString()))); } + @Test + public void shouldDecodeHeaderClaims() { + String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImRhdGUiOjE2NDczNTgzMjUsInN0cmluZyI6InN0cmluZyIsImJvb2wiOnRydWUsImRvdWJsZSI6MTIzLjEyMywibGlzdCI6WzE2NDczNTgzMjVdLCJtYXAiOnsiZGF0ZSI6MTY0NzM1ODMyNSwiaW5zdGFudCI6MTY0NzM1ODMyNX0sImludCI6NDIsImxvbmciOjQyMDAwMDAwMDAsImluc3RhbnQiOjE2NDczNTgzMjV9.eyJpYXQiOjE2NDczNjA4ODF9.S2nZDM03ZDvLMeJLWOIqWZ9kmYHZUueyQiIZCCjYNL8"; + + Instant expectedInstant = Instant.ofEpochSecond(1647358325); + Date expectedDate = Date.from(expectedInstant); + + DecodedJWT decoded = JWT.decode(jwt); + assertThat(decoded, is(notNullValue())); + assertThat(decoded.getHeaderClaim("date").asDate(), is(expectedDate)); + assertThat(decoded.getHeaderClaim("instant").asInstant(), is(expectedInstant)); + assertThat(decoded.getHeaderClaim("string").asString(), is("string")); + assertThat(decoded.getHeaderClaim("bool").asBoolean(), is(true)); + assertThat(decoded.getHeaderClaim("double").asDouble(), is(123.123)); + assertThat(decoded.getHeaderClaim("int").asInt(), is(42)); + assertThat(decoded.getHeaderClaim("long").asLong(), is(4200000000L)); + + Map headerMap = decoded.getHeaderClaim("map").asMap(); + assertThat(headerMap, is(notNullValue())); + assertThat(headerMap.size(), is(2)); + assertThat(headerMap, hasEntry("date", 1647358325)); + assertThat(headerMap, hasEntry("instant", 1647358325)); + + List headerList = decoded.getHeaderClaim("list").asList(Object.class); + assertThat(headerList, is(notNullValue())); + assertThat(headerList.size(), is(1)); + assertThat(headerList, contains(1647358325)); + } + //Helper Methods private DecodedJWT customJWT(String jsonHeader, String jsonPayload, String signature) { diff --git a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadClaimsHolderTest.java similarity index 80% rename from lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java rename to lib/src/test/java/com/auth0/jwt/impl/PayloadClaimsHolderTest.java index 38601bdc..2f053830 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadClaimsHolderTest.java @@ -9,23 +9,22 @@ import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; -public class ClaimsHolderTest { +public class PayloadClaimsHolderTest { - @SuppressWarnings("RedundantCast") @Test public void shouldGetClaims() { HashMap claims = new HashMap<>(); claims.put("iss", "auth0"); - ClaimsHolder holder = new ClaimsHolder(claims); + ClaimsHolder holder = new PayloadClaimsHolder(claims); assertThat(holder, is(notNullValue())); assertThat(holder.getClaims(), is(notNullValue())); assertThat(holder.getClaims(), is(instanceOf(Map.class))); - assertThat(holder.getClaims(), is(IsMapContaining.hasEntry("iss", (Object) "auth0"))); + assertThat(holder.getClaims(), is(IsMapContaining.hasEntry("iss", "auth0"))); } @Test public void shouldGetNotNullClaims() { - ClaimsHolder holder = new ClaimsHolder(null); + ClaimsHolder holder = new PayloadClaimsHolder(null); assertThat(holder, is(notNullValue())); assertThat(holder.getClaims(), is(notNullValue())); assertThat(holder.getClaims(), is(instanceOf(Map.class))); diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java index df93f0ba..45761de0 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java @@ -11,8 +11,8 @@ import java.io.StringWriter; import java.util.*; -import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; public class PayloadSerializerTest { @@ -31,10 +31,9 @@ public void setUp() throws Exception { serializerProvider = mapper.getSerializerProvider(); } - @SuppressWarnings("Convert2Diamond") @Test public void shouldSerializeEmptyMap() throws Exception { - ClaimsHolder holder = new ClaimsHolder(new HashMap()); + PayloadClaimsHolder holder = new PayloadClaimsHolder(new HashMap<>()); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -43,7 +42,7 @@ public void shouldSerializeEmptyMap() throws Exception { @Test public void shouldSerializeStringAudienceAsString() throws Exception { - ClaimsHolder holder = holderFor("aud", "auth0"); + PayloadClaimsHolder holder = holderFor("aud", "auth0"); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -52,7 +51,7 @@ public void shouldSerializeStringAudienceAsString() throws Exception { @Test public void shouldSerializeSingleItemAudienceAsArray() throws Exception { - ClaimsHolder holder = holderFor("aud", new String[]{"auth0"}); + PayloadClaimsHolder holder = holderFor("aud", new String[]{"auth0"}); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -61,7 +60,7 @@ public void shouldSerializeSingleItemAudienceAsArray() throws Exception { @Test public void shouldSerializeMultipleItemsAudienceAsArray() throws Exception { - ClaimsHolder holder = holderFor("aud", new String[]{"auth0", "auth10"}); + PayloadClaimsHolder holder = holderFor("aud", new String[]{"auth0", "auth10"}); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -70,7 +69,7 @@ public void shouldSerializeMultipleItemsAudienceAsArray() throws Exception { @Test public void shouldSkipSerializationOnEmptyAudience() throws Exception { - ClaimsHolder holder = holderFor("aud", new String[0]); + PayloadClaimsHolder holder = holderFor("aud", new String[0]); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -79,7 +78,7 @@ public void shouldSkipSerializationOnEmptyAudience() throws Exception { @Test public void shouldSerializeSingleItemAudienceAsArrayWhenAList() throws Exception { - ClaimsHolder holder = holderFor("aud", Collections.singletonList("auth0")); + PayloadClaimsHolder holder = holderFor("aud", Collections.singletonList("auth0")); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -88,7 +87,7 @@ public void shouldSerializeSingleItemAudienceAsArrayWhenAList() throws Exception @Test public void shouldSerializeMultipleItemsAudienceAsArrayWhenAList() throws Exception { - ClaimsHolder holder = holderFor("aud", Arrays.asList("auth0", "auth10")); + PayloadClaimsHolder holder = holderFor("aud", Arrays.asList("auth0", "auth10")); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -97,7 +96,7 @@ public void shouldSerializeMultipleItemsAudienceAsArrayWhenAList() throws Except @Test public void shouldSkipSerializationOnEmptyAudienceWhenList() throws Exception { - ClaimsHolder holder = holderFor("aud", new ArrayList()); + PayloadClaimsHolder holder = holderFor("aud", new ArrayList<>()); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -106,7 +105,7 @@ public void shouldSkipSerializationOnEmptyAudienceWhenList() throws Exception { @Test public void shouldSkipNonStringsOnAudienceWhenSingleItemList() throws Exception { - ClaimsHolder holder = holderFor("aud", Collections.singletonList(2)); + PayloadClaimsHolder holder = holderFor("aud", Collections.singletonList(2)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -115,7 +114,7 @@ public void shouldSkipNonStringsOnAudienceWhenSingleItemList() throws Exception @Test public void shouldSkipNonStringsOnAudienceWhenList() throws Exception { - ClaimsHolder holder = holderFor("aud", Arrays.asList("auth0", 2, "auth10")); + PayloadClaimsHolder holder = holderFor("aud", Arrays.asList("auth0", 2, "auth10")); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -124,7 +123,7 @@ public void shouldSkipNonStringsOnAudienceWhenList() throws Exception { @Test public void shouldSkipNonStringsOnAudience() throws Exception { - ClaimsHolder holder = holderFor("aud", 4); + PayloadClaimsHolder holder = holderFor("aud", 4); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -133,7 +132,7 @@ public void shouldSkipNonStringsOnAudience() throws Exception { @Test public void shouldSerializeNotBeforeDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("nbf", new Date(1478874000)); + PayloadClaimsHolder holder = holderFor("nbf", new Date(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -142,7 +141,7 @@ public void shouldSerializeNotBeforeDateInSeconds() throws Exception { @Test public void shouldSerializeIssuedAtDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("iat", new Date(1478874000)); + PayloadClaimsHolder holder = holderFor("iat", new Date(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -151,7 +150,7 @@ public void shouldSerializeIssuedAtDateInSeconds() throws Exception { @Test public void shouldSerializeExpiresAtDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("exp", new Date(1478874000)); + PayloadClaimsHolder holder = holderFor("exp", new Date(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -160,7 +159,7 @@ public void shouldSerializeExpiresAtDateInSeconds() throws Exception { @Test public void shouldSerializeCustomDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("birthdate", new Date(1478874000)); + PayloadClaimsHolder holder = holderFor("birthdate", new Date(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -171,7 +170,7 @@ public void shouldSerializeCustomDateInSeconds() throws Exception { public void shouldSerializeDatesUsingLong() throws Exception { long secs = Integer.MAX_VALUE + 10000L; Date date = new Date(secs * 1000L); - Map claims = new HashMap(); + Map claims = new HashMap<>(); claims.put("iat", date); claims.put("nbf", date); claims.put("exp", date); @@ -187,7 +186,7 @@ public void shouldSerializeDatesUsingLong() throws Exception { nestedInList.add(Collections.singletonMap("nested", date)); claims.put("nestedInList", nestedInList); - ClaimsHolder holder = new ClaimsHolder(claims); + PayloadClaimsHolder holder = new PayloadClaimsHolder(claims); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -206,7 +205,7 @@ public void shouldSerializeDatesUsingLong() throws Exception { @Test public void shouldSerializeStrings() throws Exception { - ClaimsHolder holder = holderFor("name", "Auth0 Inc"); + PayloadClaimsHolder holder = holderFor("name", "Auth0 Inc"); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -215,7 +214,7 @@ public void shouldSerializeStrings() throws Exception { @Test public void shouldSerializeIntegers() throws Exception { - ClaimsHolder holder = holderFor("number", 12345); + PayloadClaimsHolder holder = holderFor("number", 12345); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -224,7 +223,7 @@ public void shouldSerializeIntegers() throws Exception { @Test public void shouldSerializeDoubles() throws Exception { - ClaimsHolder holder = holderFor("fraction", 23.45); + PayloadClaimsHolder holder = holderFor("fraction", 23.45); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -233,7 +232,7 @@ public void shouldSerializeDoubles() throws Exception { @Test public void shouldSerializeBooleans() throws Exception { - ClaimsHolder holder = holderFor("pro", true); + PayloadClaimsHolder holder = holderFor("pro", true); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -242,7 +241,7 @@ public void shouldSerializeBooleans() throws Exception { @Test public void shouldSerializeNulls() throws Exception { - ClaimsHolder holder = holderFor("id", null); + PayloadClaimsHolder holder = holderFor("id", null); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -253,7 +252,7 @@ public void shouldSerializeNulls() throws Exception { public void shouldSerializeCustomArrayOfObject() throws Exception { UserPojo user1 = new UserPojo("Michael", 1); UserPojo user2 = new UserPojo("Lucas", 2); - ClaimsHolder holder = holderFor("users", new UserPojo[]{user1, user2}); + PayloadClaimsHolder holder = holderFor("users", new UserPojo[]{user1, user2}); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -264,7 +263,7 @@ public void shouldSerializeCustomArrayOfObject() throws Exception { public void shouldSerializeCustomListOfObject() throws Exception { UserPojo user1 = new UserPojo("Michael", 1); UserPojo user2 = new UserPojo("Lucas", 2); - ClaimsHolder holder = holderFor("users", Arrays.asList(user1, user2)); + PayloadClaimsHolder holder = holderFor("users", Arrays.asList(user1, user2)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -274,18 +273,17 @@ public void shouldSerializeCustomListOfObject() throws Exception { @Test public void shouldSerializeCustomObject() throws Exception { UserPojo user = new UserPojo("Michael", 1); - ClaimsHolder holder = holderFor("users", user); + PayloadClaimsHolder holder = holderFor("users", user); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); assertThat(writer.toString(), is(equalTo("{\"users\":{\"name\":\"Michael\",\"id\":1}}"))); } - @SuppressWarnings("Convert2Diamond") - private ClaimsHolder holderFor(String key, Object value) { - Map map = new HashMap(); + private PayloadClaimsHolder holderFor(String key, Object value) { + Map map = new HashMap<>(); map.put(key, value); - return new ClaimsHolder(map); + return new PayloadClaimsHolder(map); } } \ No newline at end of file From f6301e101926e35fdf972f3b9f9ca8bb95fae527 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Thu, 17 Mar 2022 21:51:58 +0530 Subject: [PATCH 015/134] Remove impl package export in module-info (#553) --- lib/src/main/java/module-info.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/src/main/java/module-info.java b/lib/src/main/java/module-info.java index ee2fede4..a1e30e31 100644 --- a/lib/src/main/java/module-info.java +++ b/lib/src/main/java/module-info.java @@ -1,8 +1,5 @@ module com.auth0.jwt { - // remove transitive in next major release requires com.fasterxml.jackson.databind; - // remove in next major release - exports com.auth0.jwt.impl; exports com.auth0.jwt; exports com.auth0.jwt.algorithms; From 499f481a303cea073a95b0b57a920aa71d344993 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 18 Mar 2022 18:21:18 +0530 Subject: [PATCH 016/134] Remove ES256K support (#556) * Remove ES256K methods and related tests * Removed related files and constants --- lib/build.gradle | 13 -- .../com/auth0/jwt/algorithms/Algorithm.java | 31 ----- .../com/auth0/jwt/ConcurrentVerifyTest.java | 13 -- .../java/com/auth0/jwt/JWTCreatorTest.java | 35 ------ lib/src/test/java/com/auth0/jwt/JWTTest.java | 21 ---- .../auth0/jwt/algorithms/AlgorithmTest.java | 23 ---- .../jwt/algorithms/ECDSAAlgorithmTest.java | 112 +----------------- .../ECDSABouncyCastleProviderTests.java | 112 ------------------ lib/src/test/resources/ec256k-key-private.pem | 5 - .../resources/ec256k-key-public-invalid.pem | 4 - lib/src/test/resources/ec256k-key-public.pem | 4 - 11 files changed, 1 insertion(+), 372 deletions(-) delete mode 100644 lib/src/test/resources/ec256k-key-private.pem delete mode 100644 lib/src/test/resources/ec256k-key-public-invalid.pem delete mode 100644 lib/src/test/resources/ec256k-key-public.pem diff --git a/lib/build.gradle b/lib/build.gradle index a83ccbc5..a672afaf 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -114,19 +114,6 @@ def testJava17 = tasks.register('testJava17', Test) { languageVersion = JavaLanguageVersion.of(17) }) shouldRunAfter(tasks.named('test')) - - //Following Tests are excluded in Java 17 since secp256k1 curve is disabled Java 15+ - filter { - excludeTestsMatching "*.jwt.ConcurrentVerifyTest.shouldPassECDSA256KVerificationWithJOSESignature" - excludeTestsMatching "*.jwt.JWTCreatorTest.shouldAddKeyIdIfAvailableFromECDSAKAlgorithms" - excludeTestsMatching "*.jwt.JWTCreatorTest.shouldNotOverwriteKeyIdIfAddedFromECDSAKAlgorithms" - excludeTestsMatching "*.jwt.JWTTest.shouldCreateAnEmptyECDSA256KSignedToken" - excludeTestsMatching "*.jwt.algorithms.ECDSAAlgorithmTest.shouldPassECDSA256KVerificationWithJOSESignature" - excludeTestsMatching "*.jwt.algorithms.ECDSAAlgorithmTest.shouldPassECDSA256KVerificationWithJOSESignatureWithBothKeys" - excludeTestsMatching "*.jwt.algorithms.ECDSAAlgorithmTest.shouldPassECDSA256KVerificationWithProvidedPublicKey" - excludeTestsMatching "*.jwt.ECDSABouncyCastleProviderTests.shouldPassECDSA256KVerificationWithJOSESignatureWithBothKeys" - excludeTestsMatching "*.jwt.ECDSABouncyCastleProviderTests.shouldPassECDSA256KVerificationWithProvidedPublicKey" - } } tasks.named('check') { diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index f3405f6e..ff10a9aa 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -171,37 +171,6 @@ public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { return new HMACAlgorithm("HS256", "HmacSHA256", secret); } - /** - * Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256K". - * - * @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance. - * @return a valid ECDSA256 Algorithm. - * @throws IllegalArgumentException if the Key Provider is null. - * @deprecated The SECP-256K1 Curve algorithm has been disabled beginning in Java 15. - * Use of this method in those unsupported Java versions will throw a {@link java.security.SignatureException}. - * This method will be removed in the next major version. See for additional information - */ - @Deprecated - public static Algorithm ECDSA256K(ECDSAKeyProvider keyProvider) throws IllegalArgumentException { - return new ECDSAAlgorithm("ES256K", "SHA256withECDSA", 32, keyProvider); - } - - /** - * Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256K". - * - * @param publicKey the key to use in the verify instance. - * @param privateKey the key to use in the signing instance. - * @return a valid ECDSA256 Algorithm. - * @throws IllegalArgumentException if the provided Key is null. - * @deprecated The SECP-256K1 Curve algorithm has been disabled beginning in Java 15. - * Use of this method in those unsupported Java versions will throw a {@link java.security.SignatureException}. - * This method will be removed in the next major version. See for additional information - */ - @Deprecated - public static Algorithm ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException { - return ECDSA256K(ECDSAAlgorithm.providerForKeys(publicKey, privateKey)); - } - /** * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". * diff --git a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java index 02666222..a06df7b7 100644 --- a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java +++ b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java @@ -28,8 +28,6 @@ public class ConcurrentVerifyTest { private static final int REPEAT_COUNT = 1000; private static final String PUBLIC_KEY_FILE = "src/test/resources/rsa-public.pem"; private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; - private static final String PUBLIC_KEY_FILE_256K = "src/test/resources/ec256k-key-public.pem"; - private static final String PRIVATE_KEY_FILE_256K = "src/test/resources/ec256k-key-private.pem"; private static final String PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public.pem"; private static final String PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public.pem"; @@ -145,17 +143,6 @@ public void shouldPassECDSA256VerificationWithJOSESignature() throws Exception { concurrentVerify(verifier, token); } - @Test - public void shouldPassECDSA256KVerificationWithJOSESignature() throws Exception { - String token = "eyJraWQiOiJteS1rZXktaWQiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiJhdXRoMCJ9.W-AbsnuQ4vqmPftAyQuF09hn3oGn3tN7VGergxyMbK74yEzDV-mLyC3o3fxXrZxcW5h01DM6BckNag7ZcimPjw"; - ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256K, "EC"); - Algorithm algorithm = Algorithm.ECDSA256K(publicKey, privateKey); - JWTVerifier verifier = JWTVerifier.init(algorithm).withIssuer("auth0").build(); - - concurrentVerify(verifier, token); - } - @Test public void shouldPassECDSA384VerificationWithJOSESignature() throws Exception { String token = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 96976166..6c870656 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -25,8 +25,6 @@ public class JWTCreatorTest { private static final String PRIVATE_KEY_FILE_RSA = "src/test/resources/rsa-private.pem"; private static final String PRIVATE_KEY_FILE_EC_256 = "src/test/resources/ec256-key-private.pem"; - private static final String PRIVATE_KEY_FILE_EC_256K = "src/test/resources/ec256k-key-private.pem"; - @Rule public ExpectedException exception = ExpectedException.none(); @@ -186,39 +184,6 @@ public void shouldNotOverwriteKeyIdIfAddedFromRSAAlgorithms() throws Exception { assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); } - @Test - public void shouldAddKeyIdIfAvailableFromECDSAKAlgorithms() throws Exception { - ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256K, "EC"); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("my-key-id"); - when(provider.getPrivateKey()).thenReturn(privateKey); - - String signed = JWTCreator.init() - .sign(Algorithm.ECDSA256K(provider)); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); - } - - @Test - public void shouldNotOverwriteKeyIdIfAddedFromECDSAKAlgorithms() throws Exception { - ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256K, "EC"); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPrivateKeyId()).thenReturn("my-key-id"); - when(provider.getPrivateKey()).thenReturn(privateKey); - - String signed = JWTCreator.init() - .withKeyId("real-key-id") - .sign(Algorithm.ECDSA256(provider)); - - assertThat(signed, is(notNullValue())); - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); - } - @Test public void shouldAddKeyIdIfAvailableFromECDSAAlgorithms() throws Exception { ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256, "EC"); diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index 35ad4971..958e89fb 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -28,11 +28,9 @@ public class JWTTest { private static final String PRIVATE_KEY_FILE_RSA = "src/test/resources/rsa-private.pem"; private static final String PUBLIC_KEY_FILE_EC_256 = "src/test/resources/ec256-key-public.pem"; - private static final String PUBLIC_KEY_FILE_EC_256K = "src/test/resources/ec256k-key-public.pem"; private static final String PUBLIC_KEY_FILE_EC_384 = "src/test/resources/ec384-key-public.pem"; private static final String PUBLIC_KEY_FILE_EC_512 = "src/test/resources/ec512-key-public.pem"; private static final String PRIVATE_KEY_FILE_EC_256 = "src/test/resources/ec256-key-private.pem"; - private static final String PRIVATE_KEY_FILE_EC_256K = "src/test/resources/ec256k-key-private.pem"; private static final String PRIVATE_KEY_FILE_EC_384 = "src/test/resources/ec384-key-private.pem"; private static final String PRIVATE_KEY_FILE_EC_512 = "src/test/resources/ec512-key-private.pem"; @@ -493,25 +491,6 @@ public void shouldCreateAnEmptyECDSA256SignedToken() throws Exception { assertThat(verified, is(notNullValue())); } - @Test - public void shouldCreateAnEmptyECDSA256KSignedToken() throws Exception { - ECPublicKey publicKey = (ECPublicKey) PemUtils.readPublicKeyFromFile(PUBLIC_KEY_FILE_EC_256K, "EC"); - ECPrivateKey privateKey = (ECPrivateKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_256K, "EC"); - - String signed = JWT.create().sign(Algorithm.ECDSA256K(publicKey, privateKey)); - assertThat(signed, is(notNullValue())); - - String[] parts = signed.split("\\."); - String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES256K")); - assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); - assertThat(parts[1], is("e30")); - - JWTVerifier verified = JWT.require(Algorithm.ECDSA256K(publicKey, privateKey)) - .build(); - assertThat(verified, is(notNullValue())); - } - @Test public void shouldCreateAnEmptyECDSA384SignedToken() throws Exception { String signed = JWT.create().sign(Algorithm.ECDSA384((ECKey) PemUtils.readPrivateKeyFromFile(PRIVATE_KEY_FILE_EC_384, "EC"))); diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java index dd919625..e09661d3 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java @@ -450,29 +450,6 @@ public void shouldCreateECDSA256AlgorithmWithProvider() { assertThat(algorithm.getName(), is("ES256")); } - @Test - public void shouldCreateECDSA256KAlgorithmWithBothKeys() { - ECPublicKey publicKey = mock(ECPublicKey.class); - ECPrivateKey privateKey = mock(ECPrivateKey.class); - Algorithm algorithm = Algorithm.ECDSA256K(publicKey, privateKey); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withECDSA")); - assertThat(algorithm.getName(), is("ES256K")); - } - - @Test - public void shouldCreateECDSA256KAlgorithmWithProvider() { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - Algorithm algorithm = Algorithm.ECDSA256K(provider); - - assertThat(algorithm, is(notNullValue())); - assertThat(algorithm, is(instanceOf(ECDSAAlgorithm.class))); - assertThat(algorithm.getDescription(), is("SHA256withECDSA")); - assertThat(algorithm.getName(), is("ES256K")); - } - @Test public void shouldCreateECDSA384AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index ee1bf928..8634d419 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -39,11 +39,6 @@ public class ECDSAAlgorithmTest { private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public-invalid.pem"; - private static final String PRIVATE_KEY_FILE_256K = "src/test/resources/ec256k-key-private.pem"; - private static final String PUBLIC_KEY_FILE_256K = "src/test/resources/ec256k-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_256K = "src/test/resources/ec256k-key-public-invalid.pem"; - private static final String ES256K_JWT = "eyJraWQiOiJteS1rZXktaWQiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.e30.2ggPsc4xwQhYcgJueo3uQ14MpaVJ3AbEE8UE-wA9fc8SMibeW54gjZbikL-JBHqhEwc22Cp8DNOtadXsM81RGQ"; - private static final String PRIVATE_KEY_FILE_384 = "src/test/resources/ec384-key-private.pem"; private static final String PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public-invalid.pem"; @@ -186,112 +181,7 @@ public void shouldFailECDSA256VerificationOnInvalidDERSignature() throws Excepti Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } - - @Test - public void shouldPassECDSA256KVerificationWithJOSESignature() throws Exception { - ECPublicKey key = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - Algorithm algorithm = Algorithm.ECDSA256K(key, null); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldThrowOnECDSA256KVerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJraWQiOiJteS1rZXktaWQiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.e30.MEUCIQDaCA-xzjHBCFhyAm56je5DXgylpUncBsQTxQT7AD19zwIgEjIm3lueII2W4pC_iQR6oRMHNtgqfAzTrWnV7DPNURk"; - - ECPublicKey key = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - Algorithm algorithm = Algorithm.ECDSA256K(key, null); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA256KVerificationWithJOSESignatureWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC") - , (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256K, "EC")); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldPassECDSA256KVerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA256K(provider); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA256K(provider); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - Algorithm algorithm = Algorithm.ECDSA256K(null, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256K, "EC")); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalArgumentException.class)); - exception.expectCause(hasMessage(is("Last unit does not have enough valid bits"))); - - String jwt = ES256K_JWT.substring(0,ES256K_JWT.length()-1); - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256KVerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NksifQo.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256KVerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - bytes[0] = 0x30; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NksifQo.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(jwt)); - } + @Test public void shouldPassECDSA384VerificationWithJOSESignature() throws Exception { String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java index d000bb34..14631798 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java @@ -33,11 +33,6 @@ import static org.mockito.Mockito.when; public class ECDSABouncyCastleProviderTests { - - - private static final String PRIVATE_KEY_FILE_256K = "src/test/resources/ec256k-key-private.pem"; - private static final String PUBLIC_KEY_FILE_256K = "src/test/resources/ec256k-key-public.pem"; - private static final String INVALID_PUBLIC_KEY_FILE_256K = "src/test/resources/ec256k-key-public-invalid.pem"; private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; @@ -78,113 +73,6 @@ public static void tearDown() { public void shouldPreferBouncyCastleProvider() { assertThat(Security.getProviders()[0], is(equalTo(bcProvider))); } - - // Verify - @Test - public void shouldPassECDSA256KVerificationWithJOSESignature() throws Exception { - ECPublicKey key = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - Algorithm algorithm = Algorithm.ECDSA256K(key, null); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldThrowOnECDSA256KVerificationWithDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(SignatureException.class)); - exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - - String jwt = "eyJraWQiOiJteS1rZXktaWQiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.e30.MEUCIQDaCA-xzjHBCFhyAm56je5DXgylpUncBsQTxQT7AD19zwIgEjIm3lueII2W4pC_iQR6oRMHNtgqfAzTrWnV7DPNURk"; - - ECPublicKey key = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - Algorithm algorithm = Algorithm.ECDSA256K(key, null); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldPassECDSA256KVerificationWithJOSESignatureWithBothKeys() throws Exception { - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC") - , (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256K, "EC")); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldPassECDSA256KVerificationWithProvidedPublicKey() throws Exception { - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); - when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); - Algorithm algorithm = Algorithm.ECDSA256K(provider); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationWhenProvidedPublicKeyIsNull() { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); - when(provider.getPublicKeyById("my-key-id")).thenReturn(null); - Algorithm algorithm = Algorithm.ECDSA256K(provider); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationWithInvalidPublicKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationWhenUsingPrivateKey() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalStateException.class)); - exception.expectCause(hasMessage(is("The given Public Key is null."))); - Algorithm algorithm = Algorithm.ECDSA256K(null, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256K, "EC")); - algorithm.verify(JWT.decode(ES256K_JWT)); - } - - @Test - public void shouldFailECDSA256KVerificationOnInvalidJOSESignatureLength() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - exception.expectCause(isA(IllegalArgumentException.class)); - exception.expectCause(hasMessage(is("Last unit does not have enough valid bits"))); - - String jwt = ES256K_JWT.substring(0,ES256K_JWT.length()-1); - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256KVerificationOnInvalidJOSESignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NksifQo.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(jwt)); - } - - @Test - public void shouldFailECDSA256KVerificationOnInvalidDERSignature() throws Exception { - exception.expect(SignatureVerificationException.class); - exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); - - byte[] bytes = new byte[64]; - bytes[0] = 0x30; - new SecureRandom().nextBytes(bytes); - String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - String jwt = "eyJhbGciOiJFUzI1NksifQo.eyJpc3MiOiJhdXRoMCJ9." + signature; - Algorithm algorithm = Algorithm.ECDSA256K((ECPublicKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256K, "EC"), null); - algorithm.verify(JWT.decode(jwt)); - } @Test public void shouldPassECDSA256VerificationWithJOSESignature() throws Exception { diff --git a/lib/src/test/resources/ec256k-key-private.pem b/lib/src/test/resources/ec256k-key-private.pem deleted file mode 100644 index 43038c8e..00000000 --- a/lib/src/test/resources/ec256k-key-private.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgN78SHuwC8BVLUbuEBXC9 -sn9LuX9a7yqIt1xaiPupqe6hRANCAAS7s8bnSsGqrv7YBqxqJiQKiyPJvcHTe2UG -7FpOaAlqIUWL5xbpCZbcH9yqozS55KMVxG78KskeuET7hl01J6EU ------END PRIVATE KEY----- \ No newline at end of file diff --git a/lib/src/test/resources/ec256k-key-public-invalid.pem b/lib/src/test/resources/ec256k-key-public-invalid.pem deleted file mode 100644 index 8809e21b..00000000 --- a/lib/src/test/resources/ec256k-key-public-invalid.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXzvxXn69y0I54+Yr0pMXqGyCb1R8D4dS -xaYhaRuN2fsV+unbFWUYViRoYUgMAbmvnXzVmThLUeP/PTmlv9lm7Q== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/lib/src/test/resources/ec256k-key-public.pem b/lib/src/test/resources/ec256k-key-public.pem deleted file mode 100644 index 1513ed70..00000000 --- a/lib/src/test/resources/ec256k-key-public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu7PG50rBqq7+2AasaiYkCosjyb3B03tl -BuxaTmgJaiFFi+cW6QmW3B/cqqM0ueSjFcRu/CrJHrhE+4ZdNSehFA== ------END PUBLIC KEY----- \ No newline at end of file From 75833e6d422206ec64e6215bdf0e940aa1c16239 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 25 Mar 2022 13:27:26 +0530 Subject: [PATCH 017/134] Add lint checks (#561) * Add lint checks * Cleaned up lint errors * Add rule to avoid println in code * Remove unused methods in CryptoHelper --- config/checkstyle/checkstyle.xml | 358 ++++++++++++++++++ lib/build.gradle | 6 + lib/src/main/java/com/auth0/jwt/JWT.java | 17 +- .../main/java/com/auth0/jwt/JWTCreator.java | 122 +++--- .../main/java/com/auth0/jwt/JWTDecoder.java | 2 +- .../main/java/com/auth0/jwt/JWTVerifier.java | 45 ++- .../main/java/com/auth0/jwt/TokenUtils.java | 3 +- .../com/auth0/jwt/algorithms/Algorithm.java | 58 +-- .../auth0/jwt/algorithms/CryptoHelper.java | 199 +++++----- .../auth0/jwt/algorithms/ECDSAAlgorithm.java | 57 +-- .../auth0/jwt/algorithms/HMACAlgorithm.java | 6 +- .../auth0/jwt/algorithms/NoneAlgorithm.java | 1 - .../auth0/jwt/algorithms/RSAAlgorithm.java | 11 +- .../AlgorithmMismatchException.java | 3 + .../jwt/exceptions/InvalidClaimException.java | 4 +- .../jwt/exceptions/JWTCreationException.java | 3 + .../jwt/exceptions/JWTDecodeException.java | 3 + .../exceptions/JWTVerificationException.java | 3 + .../SignatureGenerationException.java | 3 + .../SignatureVerificationException.java | 3 + .../jwt/exceptions/TokenExpiredException.java | 3 + .../java/com/auth0/jwt/impl/BasicHeader.java | 11 +- .../com/auth0/jwt/impl/ClaimsSerializer.java | 6 +- .../auth0/jwt/impl/HeaderDeserializer.java | 4 +- .../java/com/auth0/jwt/impl/JWTParser.java | 5 +- .../com/auth0/jwt/impl/JsonNodeClaim.java | 20 +- .../java/com/auth0/jwt/impl/NullClaim.java | 6 +- .../auth0/jwt/impl/PayloadDeserializer.java | 7 +- .../java/com/auth0/jwt/impl/PayloadImpl.java | 16 +- .../com/auth0/jwt/impl/PayloadSerializer.java | 6 +- .../java/com/auth0/jwt/impl/PublicClaims.java | 4 +- .../java/com/auth0/jwt/interfaces/Claim.java | 13 +- .../auth0/jwt/interfaces/JWTPartsParser.java | 3 +- .../com/auth0/jwt/interfaces/JWTVerifier.java | 7 +- .../com/auth0/jwt/interfaces/KeyProvider.java | 6 +- .../auth0/jwt/interfaces/Verification.java | 27 +- .../com/auth0/jwt/interfaces/ClaimTest.java | 4 +- 37 files changed, 765 insertions(+), 290 deletions(-) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 00000000..d2615981 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/build.gradle b/lib/build.gradle index a672afaf..001963bd 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -2,6 +2,12 @@ plugins { id 'java' id 'jacoco' id 'com.auth0.gradle.oss-library.java' + id 'checkstyle' +} + +checkstyle { + toolVersion '10.0' + checkstyleTest.enabled = false //We are disabling lint checks for tests } logger.lifecycle("Using version ${version} for ${group}.${name}") diff --git a/lib/src/main/java/com/auth0/jwt/JWT.java b/lib/src/main/java/com/auth0/jwt/JWT.java index ca05deff..9d719d1e 100644 --- a/lib/src/main/java/com/auth0/jwt/JWT.java +++ b/lib/src/main/java/com/auth0/jwt/JWT.java @@ -6,6 +6,9 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; +/** + * Exposes all the JWT functionalities. + */ @SuppressWarnings("WeakerAccess") public class JWT { @@ -22,11 +25,13 @@ public JWT() { /** * Decode a given Json Web Token. *

- * Note that this method doesn't verify the token's signature! Use it only if you trust the token or you already verified it. + * Note that this method doesn't verify the token's signature! + * Use it only if you trust the token or you already verified it. * * @param token with jwt format as string. * @return a decoded JWT. - * @throws JWTDecodeException if any part of the token contained an invalid jwt or JSON format of each of the jwt parts. + * @throws JWTDecodeException if any part of the token contained an invalid jwt + * or JSON format of each of the jwt parts. */ public DecodedJWT decodeJwt(String token) throws JWTDecodeException { return new JWTDecoder(parser, token); @@ -35,11 +40,13 @@ public DecodedJWT decodeJwt(String token) throws JWTDecodeException { /** * Decode a given Json Web Token. *

- * Note that this method doesn't verify the token's signature! Use it only if you trust the token or you already verified it. + * Note that this method doesn't verify the token's signature! + * Use it only if you trust the token or you already verified it. * * @param token with jwt format as string. * @return a decoded JWT. - * @throws JWTDecodeException if any part of the token contained an invalid jwt or JSON format of each of the jwt parts. + * @throws JWTDecodeException if any part of the token contained an invalid jwt + * or JSON format of each of the jwt parts. */ public static DecodedJWT decode(String token) throws JWTDecodeException { return new JWTDecoder(token); @@ -57,7 +64,7 @@ public static Verification require(Algorithm algorithm) { } /** - * Returns a Json Web Token builder used to create and sign tokens + * Returns a Json Web Token builder used to create and sign tokens. * * @return a token builder. */ diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index ca6e3918..6b355b36 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -15,7 +15,8 @@ import java.util.Map.Entry; /** - * The JWTCreator class holds the sign method to generate a complete JWT (with Signature) from a given Header and Payload content. + * The JWTCreator class holds the sign method to generate a complete JWT (with Signature) + * from a given Header and Payload content. *

* This class is thread-safe. */ @@ -38,7 +39,8 @@ public final class JWTCreator { mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); } - private JWTCreator(Algorithm algorithm, Map headerClaims, Map payloadClaims) throws JWTCreationException { + private JWTCreator(Algorithm algorithm, Map headerClaims, Map payloadClaims) + throws JWTCreationException { this.algorithm = algorithm; try { headerJson = mapper.writeValueAsString(new HeaderClaimsHolder(headerClaims)); @@ -96,7 +98,8 @@ public Builder withHeader(Map headerClaims) { /** * Add a specific Key Id ("kid") claim to the Header. - * If the {@link Algorithm} used to sign this token was instantiated with a KeyProvider, the 'kid' value will be taken from that provider and this one will be ignored. + * If the {@link Algorithm} used to sign this token was instantiated with a KeyProvider, + * the 'kid' value will be taken from that provider and this one will be ignored. * * @param keyId the Key Id value. * @return this same Builder instance. @@ -322,48 +325,6 @@ public Builder withClaim(String name, Instant value) throws IllegalArgumentExcep return this; } - /** - * Add a custom Array Claim with the given items. - * - * @param name the Claim's name. - * @param items the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withArrayClaim(String name, String[] items) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, items); - return this; - } - - /** - * Add a custom Array Claim with the given items. - * - * @param name the Claim's name. - * @param items the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null. - */ - public Builder withArrayClaim(String name, Integer[] items) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, items); - return this; - } - - /** - * Add a custom Array Claim with the given items. - * - * @param name the Claim's name. - * @param items the Claim's value. - * @return this same Builder instance. - * @throws IllegalArgumentException if the name is null - */ - public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentException { - assertNonNull(name); - addClaim(name, items); - return this; - } - /** * Add a custom Map Claim with the given items. *

@@ -381,7 +342,8 @@ public Builder withClaim(String name, Map map) throws IllegalArgument assertNonNull(name); // validate map contents if (map != null && !validateClaim(map)) { - throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, Long, Double, String and Date"); + throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, " + + "Long, Double, String and Date"); } addClaim(name, map); return this; @@ -405,12 +367,55 @@ public Builder withClaim(String name, List list) throws IllegalArgumentExcept assertNonNull(name); // validate list contents if (list != null && !validateClaim(list)) { - throw new IllegalArgumentException("Expected list containing Map, List, Boolean, Integer, Long, Double, String and Date"); + throw new IllegalArgumentException("Expected list containing Map, List, Boolean, Integer, " + + "Long, Double, String and Date"); } addClaim(name, list); return this; } + /** + * Add a custom Array Claim with the given items. + * + * @param name the Claim's name. + * @param items the Claim's value. + * @return this same Builder instance. + * @throws IllegalArgumentException if the name is null. + */ + public Builder withArrayClaim(String name, String[] items) throws IllegalArgumentException { + assertNonNull(name); + addClaim(name, items); + return this; + } + + /** + * Add a custom Array Claim with the given items. + * + * @param name the Claim's name. + * @param items the Claim's value. + * @return this same Builder instance. + * @throws IllegalArgumentException if the name is null. + */ + public Builder withArrayClaim(String name, Integer[] items) throws IllegalArgumentException { + assertNonNull(name); + addClaim(name, items); + return this; + } + + /** + * Add a custom Array Claim with the given items. + * + * @param name the Claim's name. + * @param items the Claim's value. + * @return this same Builder instance. + * @throws IllegalArgumentException if the name is null + */ + public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentException { + assertNonNull(name); + addClaim(name, items); + return this; + } + /** * Add specific Claims to set as the Payload. If the provided map is null then * nothing is changed. @@ -426,8 +431,9 @@ public Builder withClaim(String name, List list) throws IllegalArgumentExcept *

* * @param payloadClaims the values to use as Claims in the token's payload. - * @throws IllegalArgumentException if any of the claim keys or null, or if the values are not of a supported type. * @return this same Builder instance. + * @throws IllegalArgumentException if any of the claim keys or null, + * or if the values are not of a supported type. */ public Builder withPayload(Map payloadClaims) throws IllegalArgumentException { if (payloadClaims == null) { @@ -435,7 +441,8 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE } if (!validatePayload(payloadClaims)) { - throw new IllegalArgumentException("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String and Date"); + throw new IllegalArgumentException("Claim values must only be of types Map, List, Boolean, Integer, " + + "Long, Double, String and Date"); } // add claims only after validating all claims so as not to corrupt the claims map of this builder @@ -504,16 +511,18 @@ private static boolean isBasicType(Object value) { if (c.isArray()) { return c == Integer[].class || c == Long[].class || c == String[].class; } - return c == String.class || c == Integer.class || c == Long.class || c == Double.class || c == Date.class || c == Instant.class || c == Boolean.class; + return c == String.class || c == Integer.class || c == Long.class || c == Double.class + || c == Date.class || c == Instant.class || c == Boolean.class; } /** - * Creates a new JWT and signs is with the given algorithm + * Creates a new JWT and signs is with the given algorithm. * * @param algorithm used to sign the JWT * @return a new JWT token * @throws IllegalArgumentException if the provided algorithm is null. - * @throws JWTCreationException if the claims could not be converted to a valid JSON or there was a problem with the signing key. + * @throws JWTCreationException if the claims could not be converted to a valid JSON + * or there was a problem with the signing key. */ public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException { if (algorithm == null) { @@ -546,10 +555,13 @@ private void addClaim(String name, Object value) { } private String sign() throws SignatureGenerationException { - String header = Base64.getUrlEncoder().withoutPadding().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); - String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); + String header = Base64.getUrlEncoder().withoutPadding() + .encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); + String payload = Base64.getUrlEncoder().withoutPadding() + .encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); - byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8)); + byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), + payload.getBytes(StandardCharsets.UTF_8)); String signature = Base64.getUrlEncoder().withoutPadding().encodeToString((signatureBytes)); return String.format("%s.%s.%s", header, payload, signature); diff --git a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java index 55855241..cc283095 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java +++ b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java @@ -42,7 +42,7 @@ final class JWTDecoder implements DecodedJWT, Serializable { payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); } catch (NullPointerException e) { throw new JWTDecodeException("The UTF-8 Charset isn't initialized.", e); - } catch (IllegalArgumentException e){ + } catch (IllegalArgumentException e) { throw new JWTDecodeException("The input is not a valid base 64 encoded string.", e); } header = converter.parseHeader(headerJson); diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 5bcc7bc7..77dfef4e 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -16,11 +16,13 @@ import java.util.*; /** - * The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, but also its signature matches. + * The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, + * but also its signature matches. *

* This class is thread-safe. + * + * @see com.auth0.jwt.interfaces.JWTVerifier */ -@SuppressWarnings("WeakerAccess") public final class JWTVerifier implements com.auth0.jwt.interfaces.JWTVerifier { private final Algorithm algorithm; final Map claims; @@ -48,6 +50,9 @@ static Verification init(Algorithm algorithm) throws IllegalArgumentException { return new BaseVerification(algorithm); } + /** + * {@link Verification} implementation that accepts all the expected Claim values for verification. + */ public static class BaseVerification implements Verification { private final Algorithm algorithm; private final Map claims; @@ -180,7 +185,8 @@ public Verification withClaim(String name, Date value) throws IllegalArgumentExc @Override public Verification withClaim(String name, Instant value) throws IllegalArgumentException { assertNonNull(name); - // Since date-time claims are serialized as epoch seconds, we need to compare them with only seconds-granularity + // Since date-time claims are serialized as epoch seconds, + // we need to compare them with only seconds-granularity requireClaim(name, value != null ? value.truncatedTo(ChronoUnit.SECONDS) : null); return this; } @@ -280,7 +286,8 @@ private static boolean isNullOrEmpty(String[] args) { * * @param token to verify. * @return a verified and decoded JWT. - * @throws AlgorithmMismatchException if the algorithm stated in the token's header is not equal to the one defined in the {@link JWTVerifier}. + * @throws AlgorithmMismatchException if the algorithm stated in the token's header is not equal to + * the one defined in the {@link JWTVerifier}. * @throws SignatureVerificationException if the signature is invalid. * @throws TokenExpiredException if the token has expired. * @throws InvalidClaimException if a claim contained a different value than the expected one. @@ -296,7 +303,8 @@ public DecodedJWT verify(String token) throws JWTVerificationException { * * @param jwt to verify. * @return a verified and decoded JWT. - * @throws AlgorithmMismatchException if the algorithm stated in the token's header is not equal to the one defined in the {@link JWTVerifier}. + * @throws AlgorithmMismatchException if the algorithm stated in the token's header is not equal to + * the one defined in the {@link JWTVerifier}. * @throws SignatureVerificationException if the signature is invalid. * @throws TokenExpiredException if the token has expired. * @throws InvalidClaimException if a claim contained a different value than the expected one. @@ -311,11 +319,13 @@ public DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException { private void verifyAlgorithm(DecodedJWT jwt, Algorithm expectedAlgorithm) throws AlgorithmMismatchException { if (!expectedAlgorithm.getName().equals(jwt.getAlgorithm())) { - throw new AlgorithmMismatchException("The provided Algorithm doesn't match the one defined in the JWT's Header."); + throw new AlgorithmMismatchException( + "The provided Algorithm doesn't match the one defined in the JWT's Header."); } } - private void verifyClaims(DecodedJWT jwt, Map claims) throws TokenExpiredException, InvalidClaimException { + private void verifyClaims(DecodedJWT jwt, Map claims) + throws TokenExpiredException, InvalidClaimException { for (Map.Entry entry : claims.entrySet()) { if (entry.getValue() instanceof NonEmptyClaim) { assertClaimPresent(jwt.getClaim(entry.getKey()), entry.getKey()); @@ -327,8 +337,9 @@ private void verifyClaims(DecodedJWT jwt, Map claims) throws Tok private void verifyClaimValues(DecodedJWT jwt, Map.Entry expectedClaim) { switch (expectedClaim.getKey()) { - // We use custom keys for audience in the expected claims to differentiate between validating that the audience - // contains all expected values, or validating that the audience contains at least one of the expected values. + // We use custom keys for audience in the expected claims to differentiate between + // validating that the audience contains all expected values, or validating that the audience contains + // at least one of the expected values. case AUDIENCE_EXACT: assertValidAudienceClaim(jwt.getAudience(), (List) expectedClaim.getValue(), true); break; @@ -354,7 +365,8 @@ private void verifyClaimValues(DecodedJWT jwt, Map.Entry expecte assertValidStringClaim(expectedClaim.getKey(), jwt.getSubject(), (String) expectedClaim.getValue()); break; default: - assertValidClaim(jwt.getClaim(expectedClaim.getKey()), expectedClaim.getKey(), expectedClaim.getValue()); + assertValidClaim(jwt.getClaim(expectedClaim.getKey()), expectedClaim.getKey(), + expectedClaim.getValue()); break; } } @@ -402,13 +414,15 @@ private void assertValidClaim(Claim claim, String claimName, Object value) { } if (!isValid) { - throw new InvalidClaimException(String.format("The Claim '%s' value doesn't match the required one.", claimName)); + throw new InvalidClaimException( + String.format("The Claim '%s' value doesn't match the required one.", claimName)); } } private void assertValidStringClaim(String claimName, String value, String expectedValue) { if (!expectedValue.equals(value)) { - throw new InvalidClaimException(String.format("The Claim '%s' value doesn't match the required one.", claimName)); + throw new InvalidClaimException( + String.format("The Claim '%s' value doesn't match the required one.", claimName)); } } @@ -434,8 +448,8 @@ private void assertInstantIsPast(Instant claimVal, long leeway, Instant now) { } private void assertValidAudienceClaim(List audience, List values, boolean shouldContainAll) { - if (audience == null || (shouldContainAll && !audience.containsAll(values)) || - (!shouldContainAll && Collections.disjoint(audience, values))) { + if (audience == null || (shouldContainAll && !audience.containsAll(values)) + || (!shouldContainAll && Collections.disjoint(audience, values))) { throw new InvalidClaimException("The Claim 'aud' value doesn't contain the required audience."); } } @@ -452,7 +466,8 @@ private void assertValidIssuerClaim(String issuer, List value) { private static class NonEmptyClaim { private static NonEmptyClaim nonEmptyClaim; - private NonEmptyClaim() {} + private NonEmptyClaim() { + } public static NonEmptyClaim getInstance() { if (nonEmptyClaim == null) { diff --git a/lib/src/main/java/com/auth0/jwt/TokenUtils.java b/lib/src/main/java/com/auth0/jwt/TokenUtils.java index cb6cff3e..0a76028b 100644 --- a/lib/src/main/java/com/auth0/jwt/TokenUtils.java +++ b/lib/src/main/java/com/auth0/jwt/TokenUtils.java @@ -18,7 +18,8 @@ static String[] splitToken(String token) throws JWTDecodeException { parts = new String[]{parts[0], parts[1], ""}; } if (parts.length != 3) { - throw new JWTDecodeException(String.format("The token was expected to have 3 parts, but got %s.", parts.length)); + throw new JWTDecodeException( + String.format("The token was expected to have 3 parts, but got %s.", parts.length)); } return parts; } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index ff10a9aa..a5247005 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -139,47 +139,47 @@ public static Algorithm HMAC256(String secret) throws IllegalArgumentException { } /** - * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". + * Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256". * - * @param secret the secret to use in the verify or signing instance. - * @return a valid HMAC384 Algorithm. + * @param secret the secret bytes to use in the verify or signing instance. + * @return a valid HMAC256 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ - public static Algorithm HMAC384(String secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS384", "HmacSHA384", secret); + public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { + return new HMACAlgorithm("HS256", "HmacSHA256", secret); } /** - * Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512". + * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". * * @param secret the secret to use in the verify or signing instance. - * @return a valid HMAC512 Algorithm. + * @return a valid HMAC384 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ - public static Algorithm HMAC512(String secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS512", "HmacSHA512", secret); + public static Algorithm HMAC384(String secret) throws IllegalArgumentException { + return new HMACAlgorithm("HS384", "HmacSHA384", secret); } /** - * Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256". + * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". * * @param secret the secret bytes to use in the verify or signing instance. - * @return a valid HMAC256 Algorithm. + * @return a valid HMAC384 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ - public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS256", "HmacSHA256", secret); + public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException { + return new HMACAlgorithm("HS384", "HmacSHA384", secret); } /** - * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". + * Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512". * - * @param secret the secret bytes to use in the verify or signing instance. - * @return a valid HMAC384 Algorithm. + * @param secret the secret to use in the verify or signing instance. + * @return a valid HMAC512 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ - public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException { - return new HMACAlgorithm("HS384", "HmacSHA384", secret); + public static Algorithm HMAC512(String secret) throws IllegalArgumentException { + return new HMACAlgorithm("HS512", "HmacSHA512", secret); } /** @@ -192,8 +192,7 @@ public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException { public static Algorithm HMAC512(byte[] secret) throws IllegalArgumentException { return new HMACAlgorithm("HS512", "HmacSHA512", secret); } - - + /** * Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256". @@ -314,7 +313,8 @@ protected Algorithm(String name, String description) { } /** - * Getter for the Id of the Private Key used to sign the tokens. This is usually specified as the `kid` claim in the Header. + * Getter for the Id of the Private Key used to sign the tokens. + * This is usually specified as the `kid` claim in the Header. * * @return the Key Id that identifies the Signing Key or null if it's not specified. */ @@ -332,7 +332,8 @@ public String getName() { } /** - * Getter for the description of this Algorithm, required when instantiating a Mac or Signature object. i.e. "HmacSHA256" + * Getter for the description of this Algorithm, + * required when instantiating a Mac or Signature object. i.e. "HmacSHA256" * * @return the algorithm description. */ @@ -349,15 +350,19 @@ public String toString() { * Verify the given token using this Algorithm instance. * * @param jwt the already decoded JWT that it's going to be verified. - * @throws SignatureVerificationException if the Token's Signature is invalid, meaning that it doesn't match the signatureBytes, or if the Key is invalid. + * @throws SignatureVerificationException if the Token's Signature is invalid, + * meaning that it doesn't match the signatureBytes, + * or if the Key is invalid. */ public abstract void verify(DecodedJWT jwt) throws SignatureVerificationException; /** * Sign the given content using this Algorithm instance. * - * @param headerBytes an array of bytes representing the base64 encoded header content to be verified against the signature. - * @param payloadBytes an array of bytes representing the base64 encoded payload content to be verified against the signature. + * @param headerBytes an array of bytes representing the base64 encoded header content + * to be verified against the signature. + * @param payloadBytes an array of bytes representing the base64 encoded payload content + * to be verified against the signature. * @return the signature in a base64 encoded array of bytes * @throws SignatureGenerationException if the Key is invalid. */ @@ -376,7 +381,8 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene * Sign the given content using this Algorithm instance. * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} * - * @param contentBytes an array of bytes representing the base64 encoded content to be verified against the signature. + * @param contentBytes an array of bytes representing the base64 encoded content + * to be verified against the signature. * @return the signature in a base64 encoded array of bytes * @throws SignatureGenerationException if the Key is invalid. */ diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java index 26a87bc4..7b8c5c2a 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java @@ -12,93 +12,98 @@ */ class CryptoHelper { - private static final byte JWT_PART_SEPARATOR = (byte)46; + private static final byte JWT_PART_SEPARATOR = (byte) 46; /** * Verify signature for JWT header and payload. * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param header JWT header. - * @param payload JWT payload. + * @param algorithm algorithm name. + * @param secretBytes algorithm secret. + * @param header JWT header. + * @param payload JWT payload. * @param signatureBytes JWT signature. * @return true if signature is valid. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - boolean verifySignatureFor(String algorithm, byte[] secretBytes, String header, String payload, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { - return verifySignatureFor(algorithm, secretBytes, header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8), signatureBytes); + boolean verifySignatureFor( + String algorithm, + byte[] secretBytes, + String header, + String payload, + byte[] signatureBytes + ) throws NoSuchAlgorithmException, InvalidKeyException { + return verifySignatureFor(algorithm, secretBytes, + header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8), signatureBytes); } /** * Verify signature for JWT header and payload. * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. + * @param algorithm algorithm name. + * @param secretBytes algorithm secret. + * @param headerBytes JWT header. + * @param payloadBytes JWT payload. * @param signatureBytes JWT signature. * @return true if signature is valid. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] headerBytes, byte[] payloadBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { - return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, headerBytes, payloadBytes), signatureBytes); - } - - /** - * Create signature for JWT header and payload. - * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. - * @return the signature bytes. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - */ - - byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] headerBytes, byte[] payloadBytes) throws NoSuchAlgorithmException, InvalidKeyException { - final Mac mac = Mac.getInstance(algorithm); - mac.init(new SecretKeySpec(secretBytes, algorithm)); - mac.update(headerBytes); - mac.update(JWT_PART_SEPARATOR); - return mac.doFinal(payloadBytes); + boolean verifySignatureFor( + String algorithm, + byte[] secretBytes, + byte[] headerBytes, + byte[] payloadBytes, + byte[] signatureBytes + ) throws NoSuchAlgorithmException, InvalidKeyException { + return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, headerBytes, payloadBytes), + signatureBytes); } /** * Verify signature for JWT header and payload. * - * @param algorithm algorithm name. - * @param publicKey algorithm public key. - * @param header JWT header. - * @param payload JWT payload. + * @param algorithm algorithm name. + * @param publicKey algorithm public key. + * @param header JWT header. + * @param payload JWT payload. * @param signatureBytes JWT signature. * @return true if signature is valid. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - - boolean verifySignatureFor(String algorithm, PublicKey publicKey, String header, String payload, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - return verifySignatureFor(algorithm, publicKey, header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8), signatureBytes); + boolean verifySignatureFor( + String algorithm, + PublicKey publicKey, + String header, + String payload, + byte[] signatureBytes + ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + return verifySignatureFor(algorithm, publicKey, header.getBytes(StandardCharsets.UTF_8), + payload.getBytes(StandardCharsets.UTF_8), signatureBytes); } /** * Verify signature for JWT header and payload using a public key. * - * @param algorithm algorithm name. - * @param publicKey the public key to use for verification. - * @param headerBytes JWT header. - * @param payloadBytes JWT payload. + * @param algorithm algorithm name. + * @param publicKey the public key to use for verification. + * @param headerBytes JWT header. + * @param payloadBytes JWT payload. * @param signatureBytes JWT signature. * @return true if signature is valid. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - - boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] headerBytes, byte[] payloadBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + boolean verifySignatureFor( + String algorithm, + PublicKey publicKey, + byte[] headerBytes, + byte[] payloadBytes, + byte[] signatureBytes + ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initVerify(publicKey); s.update(headerBytes); @@ -110,17 +115,22 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] headerB /** * Create signature for JWT header and payload using a private key. * - * @param algorithm algorithm name. - * @param privateKey the private key to use for signing. - * @param headerBytes JWT header. + * @param algorithm algorithm name. + * @param privateKey the private key to use for signing. + * @param headerBytes JWT header. * @param payloadBytes JWT payload. * @return the signature bytes. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws SignatureException if this signature object is not initialized properly + * or if this signature algorithm is unable to process the input data provided. */ - - byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] headerBytes, byte[] payloadBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + byte[] createSignatureFor( + String algorithm, + PrivateKey privateKey, + byte[] headerBytes, + byte[] payloadBytes + ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initSign(privateKey); s.update(headerBytes); @@ -130,75 +140,66 @@ byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] header } /** - * Verify signature. - * For valid verification, ensure the content is in the format {HEADER}.{PAYLOAD} + * Create signature for JWT header and payload. * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. - * @param contentBytes the content to which the signature applies. - * @param signatureBytes JWT signature. - * @return true if signature is valid. + * @param algorithm algorithm name. + * @param secretBytes algorithm secret. + * @param headerBytes JWT header. + * @param payloadBytes JWT payload. + * @return the signature bytes. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - - boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { - return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, contentBytes), signatureBytes); + byte[] createSignatureFor( + String algorithm, + byte[] secretBytes, + byte[] headerBytes, + byte[] payloadBytes + ) throws NoSuchAlgorithmException, InvalidKeyException { + final Mac mac = Mac.getInstance(algorithm); + mac.init(new SecretKeySpec(secretBytes, algorithm)); + mac.update(headerBytes); + mac.update(JWT_PART_SEPARATOR); + return mac.doFinal(payloadBytes); } /** * Create signature. * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} * - * @param algorithm algorithm name. - * @param secretBytes algorithm secret. + * @param algorithm algorithm name. + * @param secretBytes algorithm secret. * @param contentBytes the content to be signed. * @return the signature bytes. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - - byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException { + byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes) + throws NoSuchAlgorithmException, InvalidKeyException { final Mac mac = Mac.getInstance(algorithm); mac.init(new SecretKeySpec(secretBytes, algorithm)); return mac.doFinal(contentBytes); } - /** - * Verify signature using a public key. - * For valid verification, ensure the content is in the format {HEADER}.{PAYLOAD} - * - * @param algorithm algorithm name. - * @param publicKey algorithm public key. - * @param contentBytes the content to which the signature applies. - * @param signatureBytes JWT signature. - * @return the signature bytes. - * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. - */ - - boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - final Signature s = Signature.getInstance(algorithm); - s.initVerify(publicKey); - s.update(contentBytes); - return s.verify(signatureBytes); - } - /** * Create signature using a private key. * To get the correct JWT Signature, ensure the content is in the format {HEADER}.{PAYLOAD} * - * @param algorithm algorithm name. - * @param privateKey the private key to use for signing. + * @param algorithm algorithm name. + * @param privateKey the private key to use for signing. * @param contentBytes the content to be signed. * @return the signature bytes. * @throws NoSuchAlgorithmException if the algorithm is not supported. - * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. - * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. + * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. + * @throws SignatureException if this signature object is not initialized properly + * or if this signature algorithm is unable to process the input data provided. */ - byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + byte[] createSignatureFor( + String algorithm, + PrivateKey privateKey, + byte[] contentBytes + ) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initSign(privateKey); s.update(contentBytes); diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index 51fa70fa..26700a2a 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -24,7 +24,8 @@ class ECDSAAlgorithm extends Algorithm { private final int ecNumberSize; //Visible for testing - ECDSAAlgorithm(CryptoHelper crypto, String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) throws IllegalArgumentException { + ECDSAAlgorithm(CryptoHelper crypto, String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) + throws IllegalArgumentException { super(id, algorithm); if (keyProvider == null) { throw new IllegalArgumentException("The Key Provider cannot be null."); @@ -34,7 +35,8 @@ class ECDSAAlgorithm extends Algorithm { this.ecNumberSize = ecNumberSize; } - ECDSAAlgorithm(String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) throws IllegalArgumentException { + ECDSAAlgorithm(String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) + throws IllegalArgumentException { this(new CryptoHelper(), id, algorithm, ecNumberSize, keyProvider); } @@ -46,12 +48,14 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { if (publicKey == null) { throw new IllegalStateException("The given Public Key is null."); } - boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), JOSEToDER(signatureBytes)); + boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, jwt.getHeader(), + jwt.getPayload(), JOSEToDER(signatureBytes)); if (!valid) { throw new SignatureVerificationException(this); } - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException | IllegalArgumentException e) { + } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException + | IllegalStateException | IllegalArgumentException e) { throw new SignatureVerificationException(this, e); } } @@ -116,25 +120,27 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { offset++; //Obtain R number length (Includes padding) and skip it - int rLength = derSignature[offset++]; - if (rLength > ecNumberSize + 1) { + int rlength = derSignature[offset++]; + if (rlength > ecNumberSize + 1) { throw new SignatureException("Invalid DER signature format."); } - int rPadding = ecNumberSize - rLength; + int rpadding = ecNumberSize - rlength; //Retrieve R number - System.arraycopy(derSignature, offset + Math.max(-rPadding, 0), joseSignature, Math.max(rPadding, 0), rLength + Math.min(rPadding, 0)); + System.arraycopy(derSignature, offset + Math.max(-rpadding, 0), + joseSignature, Math.max(rpadding, 0), rlength + Math.min(rpadding, 0)); //Skip R number and 0x02 - offset += rLength + 1; + offset += rlength + 1; //Obtain S number length. (Includes padding) - int sLength = derSignature[offset++]; - if (sLength > ecNumberSize + 1) { + int slength = derSignature[offset++]; + if (slength > ecNumberSize + 1) { throw new SignatureException("Invalid DER signature format."); } - int sPadding = ecNumberSize - sLength; + int spadding = ecNumberSize - slength; //Retrieve R number - System.arraycopy(derSignature, offset + Math.max(-sPadding, 0), joseSignature, ecNumberSize + Math.max(sPadding, 0), sLength + Math.min(sPadding, 0)); + System.arraycopy(derSignature, offset + Math.max(-spadding, 0), joseSignature, + ecNumberSize + Math.max(spadding, 0), slength + Math.min(spadding, 0)); return joseSignature; } @@ -146,12 +152,12 @@ byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { } // Retrieve R and S number's length and padding. - int rPadding = countPadding(joseSignature, 0, ecNumberSize); - int sPadding = countPadding(joseSignature, ecNumberSize, joseSignature.length); - int rLength = ecNumberSize - rPadding; - int sLength = ecNumberSize - sPadding; + int rpadding = countPadding(joseSignature, 0, ecNumberSize); + int spadding = countPadding(joseSignature, ecNumberSize, joseSignature.length); + int rlength = ecNumberSize - rpadding; + int slength = ecNumberSize - spadding; - int length = 2 + rLength + 2 + sLength; + int length = 2 + rlength + 2 + slength; if (length > 255) { throw new SignatureException("Invalid JOSE signature format."); } @@ -174,31 +180,32 @@ byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { // Header with "min R" number length derSignature[offset++] = (byte) 0x02; - derSignature[offset++] = (byte) rLength; + derSignature[offset++] = (byte) rlength; // R number - if (rPadding < 0) { + if (rpadding < 0) { //Sign derSignature[offset++] = (byte) 0x00; System.arraycopy(joseSignature, 0, derSignature, offset, ecNumberSize); offset += ecNumberSize; } else { - int copyLength = Math.min(ecNumberSize, rLength); - System.arraycopy(joseSignature, rPadding, derSignature, offset, copyLength); + int copyLength = Math.min(ecNumberSize, rlength); + System.arraycopy(joseSignature, rpadding, derSignature, offset, copyLength); offset += copyLength; } // Header with "min S" number length derSignature[offset++] = (byte) 0x02; - derSignature[offset++] = (byte) sLength; + derSignature[offset++] = (byte) slength; // S number - if (sPadding < 0) { + if (spadding < 0) { //Sign derSignature[offset++] = (byte) 0x00; System.arraycopy(joseSignature, ecNumberSize, derSignature, offset, ecNumberSize); } else { - System.arraycopy(joseSignature, ecNumberSize + sPadding, derSignature, offset, Math.min(ecNumberSize, sLength)); + System.arraycopy(joseSignature, ecNumberSize + spadding, derSignature, offset, + Math.min(ecNumberSize, slength)); } return derSignature; diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java index 26ad6a87..0306e7c4 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java @@ -21,7 +21,8 @@ class HMACAlgorithm extends Algorithm { private final byte[] secret; //Visible for testing - HMACAlgorithm(CryptoHelper crypto, String id, String algorithm, byte[] secretBytes) throws IllegalArgumentException { + HMACAlgorithm(CryptoHelper crypto, String id, String algorithm, byte[] secretBytes) + throws IllegalArgumentException { super(id, algorithm); if (secretBytes == null) { throw new IllegalArgumentException("The Secret cannot be null"); @@ -50,7 +51,8 @@ static byte[] getSecretBytes(String secret) throws IllegalArgumentException { public void verify(DecodedJWT jwt) throws SignatureVerificationException { try { byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); - boolean valid = crypto.verifySignatureFor(getDescription(), secret, jwt.getHeader(), jwt.getPayload(), signatureBytes); + boolean valid = crypto.verifySignatureFor( + getDescription(), secret, jwt.getHeader(), jwt.getPayload(), signatureBytes); if (!valid) { throw new SignatureVerificationException(this); } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java index ade07b0e..5c6c0fc5 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java @@ -3,7 +3,6 @@ import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; - import java.util.Base64; class NoneAlgorithm extends Algorithm { diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java index cd1e97a5..0c7a5b57 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java @@ -24,7 +24,8 @@ class RSAAlgorithm extends Algorithm { private final CryptoHelper crypto; //Visible for testing - RSAAlgorithm(CryptoHelper crypto, String id, String algorithm, RSAKeyProvider keyProvider) throws IllegalArgumentException { + RSAAlgorithm(CryptoHelper crypto, String id, String algorithm, RSAKeyProvider keyProvider) + throws IllegalArgumentException { super(id, algorithm); if (keyProvider == null) { throw new IllegalArgumentException("The Key Provider cannot be null."); @@ -45,11 +46,13 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { if (publicKey == null) { throw new IllegalStateException("The given Public Key is null."); } - boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), signatureBytes); + boolean valid = crypto.verifySignatureFor( + getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), signatureBytes); if (!valid) { throw new SignatureVerificationException(this); } - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalArgumentException | IllegalStateException e) { + } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException + | IllegalArgumentException | IllegalStateException e) { throw new SignatureVerificationException(this, e); } } @@ -66,7 +69,7 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene throw new SignatureGenerationException(this, e); } } - + @Override public byte[] sign(byte[] contentBytes) throws SignatureGenerationException { try { diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java b/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java index 1d7ba1ce..d6b71205 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java @@ -1,5 +1,8 @@ package com.auth0.jwt.exceptions; +/** + * The exception that will be thrown if the exception doesn't match the one mentioned in the JWT Header. + */ public class AlgorithmMismatchException extends JWTVerificationException { public AlgorithmMismatchException(String message) { super(message); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java b/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java index ab348323..f80fb752 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java @@ -1,6 +1,8 @@ package com.auth0.jwt.exceptions; - +/** + * The exception that will be thrown while verifying Claims of a JWT. + */ public class InvalidClaimException extends JWTVerificationException { public InvalidClaimException(String message) { super(message); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java index 5bf4facb..c7e162ea 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java @@ -1,5 +1,8 @@ package com.auth0.jwt.exceptions; +/** + * The exception that is thrown when a JWT cannot be created. + */ public class JWTCreationException extends RuntimeException { public JWTCreationException(String message, Throwable cause) { super(message, cause); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java index 93799d31..448714e9 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java @@ -1,5 +1,8 @@ package com.auth0.jwt.exceptions; +/** + * The exception that is thrown when any part of the token contained an invalid JWT or JSON format. + */ public class JWTDecodeException extends JWTVerificationException { public JWTDecodeException(String message) { this(message, null); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java index 2ccfcccf..dd36dcd3 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java @@ -1,5 +1,8 @@ package com.auth0.jwt.exceptions; +/** + * Parent to all the exception thrown while verifying a JWT. + */ public class JWTVerificationException extends RuntimeException { public JWTVerificationException(String message) { this(message, null); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java index 3637f97a..4b7668a0 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java @@ -2,6 +2,9 @@ import com.auth0.jwt.algorithms.Algorithm; +/** + * The exception that is thrown when signature is not able to be generated. + */ public class SignatureGenerationException extends JWTCreationException { public SignatureGenerationException(Algorithm algorithm, Throwable cause) { super("The Token's Signature couldn't be generated when signing using the Algorithm: " + algorithm, cause); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java index 12bd3429..fa7c3cab 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java @@ -2,6 +2,9 @@ import com.auth0.jwt.algorithms.Algorithm; +/** + * The exception that is thrown if the Signature verification fails. + */ public class SignatureVerificationException extends JWTVerificationException { public SignatureVerificationException(Algorithm algorithm) { this(algorithm, null); diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java b/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java index f5d2e67a..66f28285 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java @@ -1,5 +1,8 @@ package com.auth0.jwt.exceptions; +/** + * The exception that is thrown if the token is expired. + */ public class TokenExpiredException extends JWTVerificationException { private static final long serialVersionUID = -7076928975713577708L; diff --git a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java index 0a782268..3746dcd2 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java +++ b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java @@ -24,8 +24,15 @@ class BasicHeader implements Header, Serializable { private final String keyId; private final Map tree; private final ObjectReader objectReader; - - BasicHeader(String algorithm, String type, String contentType, String keyId, Map tree, ObjectReader objectReader) { + + BasicHeader( + String algorithm, + String type, + String contentType, + String keyId, + Map tree, + ObjectReader objectReader + ) { this.algorithm = algorithm; this.type = type; this.contentType = contentType; diff --git a/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java index 4db20119..b1f8e6d3 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/ClaimsSerializer.java @@ -32,12 +32,12 @@ public void serialize(T holder, JsonGenerator gen, SerializerProvider provider) /** * Writes the given entry to the JSON representation. Custom claim serialization handling can override this method - * to provide use-case specific serialization. Implementors who override this method must write the field name and the - * field value. + * to provide use-case specific serialization. Implementors who override this method must write + * the field name and the field value. * * @param entry The entry that corresponds to the JSON field to write * @param gen The {@code JsonGenerator} to use - * @throws IOException + * @throws IOException if there is either an underlying I/O problem or encoding issue at format layer */ protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { gen.writeFieldName(entry.getKey()); diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java index 6bba2caa..8a6cbcf8 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java @@ -13,10 +13,10 @@ /** * Jackson deserializer implementation for converting from JWT Header parts. - * - * @see JWTParser *

* This class is thread-safe. + * + * @see JWTParser */ class HeaderDeserializer extends StdDeserializer { diff --git a/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java b/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java index 84a8b867..fe1600bd 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java @@ -9,9 +9,12 @@ import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; - import java.io.IOException; +/** + * This class helps in decoding the Header and Payload of the JWT using + * {@link HeaderSerializer} and {@link PayloadSerializer}. + */ public class JWTParser implements JWTPartsParser { private final ObjectReader payloadReader; private final ObjectReader headerReader; diff --git a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java index 0d816128..54a09575 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java @@ -74,24 +74,24 @@ public Instant asInstant() { @Override @SuppressWarnings("unchecked") - public T[] asArray(Class tClazz) throws JWTDecodeException { + public T[] asArray(Class clazz) throws JWTDecodeException { if (!data.isArray()) { return null; } - T[] arr = (T[]) Array.newInstance(tClazz, data.size()); + T[] arr = (T[]) Array.newInstance(clazz, data.size()); for (int i = 0; i < data.size(); i++) { try { - arr[i] = objectReader.treeToValue(data.get(i), tClazz); + arr[i] = objectReader.treeToValue(data.get(i), clazz); } catch (JsonProcessingException e) { - throw new JWTDecodeException("Couldn't map the Claim's array contents to " + tClazz.getSimpleName(), e); + throw new JWTDecodeException("Couldn't map the Claim's array contents to " + clazz.getSimpleName(), e); } } return arr; } @Override - public List asList(Class tClazz) throws JWTDecodeException { + public List asList(Class clazz) throws JWTDecodeException { if (!data.isArray()) { return null; } @@ -99,9 +99,9 @@ public List asList(Class tClazz) throws JWTDecodeException { List list = new ArrayList<>(); for (int i = 0; i < data.size(); i++) { try { - list.add(objectReader.treeToValue(data.get(i), tClazz)); + list.add(objectReader.treeToValue(data.get(i), clazz)); } catch (JsonProcessingException e) { - throw new JWTDecodeException("Couldn't map the Claim's array contents to " + tClazz.getSimpleName(), e); + throw new JWTDecodeException("Couldn't map the Claim's array contents to " + clazz.getSimpleName(), e); } } return list; @@ -124,11 +124,11 @@ public Map asMap() throws JWTDecodeException { } @Override - public T as(Class tClazz) throws JWTDecodeException { + public T as(Class clazz) throws JWTDecodeException { try { - return objectReader.treeAsTokens(data).readValueAs(tClazz); + return objectReader.treeAsTokens(data).readValueAs(clazz); } catch (IOException e) { - throw new JWTDecodeException("Couldn't map the Claim value to " + tClazz.getSimpleName(), e); + throw new JWTDecodeException("Couldn't map the Claim value to " + clazz.getSimpleName(), e); } } diff --git a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java index 664328de..2975b51b 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java @@ -53,12 +53,12 @@ public Instant asInstant() { } @Override - public T[] asArray(Class tClazz) throws JWTDecodeException { + public T[] asArray(Class clazz) throws JWTDecodeException { return null; } @Override - public List asList(Class tClazz) throws JWTDecodeException { + public List asList(Class clazz) throws JWTDecodeException { return null; } @@ -68,7 +68,7 @@ public Map asMap() throws JWTDecodeException { } @Override - public T as(Class tClazz) throws JWTDecodeException { + public T as(Class clazz) throws JWTDecodeException { return null; } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 46bd7ebe..09009267 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -16,10 +16,10 @@ /** * Jackson deserializer implementation for converting from JWT Payload parts. - * - * @see JWTParser *

* This class is thread-safe. + * + * @see JWTParser */ class PayloadDeserializer extends StdDeserializer { @@ -80,7 +80,8 @@ Instant getInstantFromSeconds(Map tree, String claimName) { return null; } if (!node.canConvertToLong()) { - throw new JWTDecodeException(String.format("The claim '%s' contained a non-numeric date value.", claimName)); + throw new JWTDecodeException( + String.format("The claim '%s' contained a non-numeric date value.", claimName)); } return Instant.ofEpochSecond(node.asLong()); } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java index a446741c..75e79474 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java @@ -13,10 +13,10 @@ /** * Decoder of string JSON Web Tokens into their POJO representations. - * - * @see Payload *

* This class is thread-safe. + * + * @see Payload */ class PayloadImpl implements Payload, Serializable { @@ -32,7 +32,17 @@ class PayloadImpl implements Payload, Serializable { private final Map tree; private final ObjectReader objectReader; - PayloadImpl(String issuer, String subject, List audience, Instant expiresAt, Instant notBefore, Instant issuedAt, String jwtId, Map tree, ObjectReader objectReader) { + PayloadImpl( + String issuer, + String subject, + List audience, + Instant expiresAt, + Instant notBefore, + Instant issuedAt, + String jwtId, + Map tree, + ObjectReader objectReader + ) { this.issuer = issuer; this.subject = subject; this.audience = audience != null ? Collections.unmodifiableList(audience) : null; diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index 497a3a94..dc138c08 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -10,10 +10,10 @@ /** * Jackson serializer implementation for converting into JWT Payload parts. - * - * @see com.auth0.jwt.JWTCreator *

* This class is thread-safe. + * + * @see com.auth0.jwt.JWTCreator */ public class PayloadSerializer extends ClaimsSerializer { public PayloadSerializer() { @@ -47,7 +47,7 @@ private void writeAudience(JsonGenerator gen, Map.Entry e) throw List audList = (List) e.getValue(); for (Object aud : audList) { if (aud instanceof String) { - audArray.add((String)aud); + audArray.add((String) aud); } } } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java b/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java index cc2b3db8..ea166b0d 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java @@ -1,6 +1,8 @@ package com.auth0.jwt.impl; - +/** + * Contains the claim name for all Public claims. + */ public interface PublicClaims { //Header diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java index cc5256f4..fdfac715 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java @@ -81,23 +81,24 @@ default Instant asInstant() { /** * Get this Claim as an Array of type T. * If the value isn't an Array, null will be returned. + * * @param type - * @param tClazz the type class + * @param clazz the type class * @return the value as an Array or null. * @throws JWTDecodeException if the values inside the Array can't be converted to a class T. */ - T[] asArray(Class tClazz) throws JWTDecodeException; + T[] asArray(Class clazz) throws JWTDecodeException; /** * Get this Claim as a List of type T. * If the value isn't an Array, null will be returned. * * @param type - * @param tClazz the type class + * @param clazz the type class * @return the value as a List or null. * @throws JWTDecodeException if the values inside the List can't be converted to a class T. */ - List asList(Class tClazz) throws JWTDecodeException; + List asList(Class clazz) throws JWTDecodeException; /** * Get this Claim as a generic Map of values. @@ -111,9 +112,9 @@ default Instant asInstant() { * Get this Claim as a custom type T. * * @param type - * @param tClazz the type class + * @param clazz the type class * @return the value as instance of T. * @throws JWTDecodeException if the value can't be converted to a class T. */ - T as(Class tClazz) throws JWTDecodeException; + T as(Class clazz) throws JWTDecodeException; } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java index 520e35c8..e1c6efcc 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java @@ -3,7 +3,8 @@ import com.auth0.jwt.exceptions.JWTDecodeException; /** - * The JWTPartsParser class defines which parts of the JWT should be converted to it's specific Object representation instance. + * The JWTPartsParser class defines which parts of the JWT should be converted + * to it's specific Object representation instance. */ public interface JWTPartsParser { diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java index a335a83e..3555878e 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java @@ -3,10 +3,13 @@ import com.auth0.jwt.exceptions.JWTVerificationException; +/** + * Used to verify the JWT for it's signature and claims. + */ public interface JWTVerifier { /** - * Performs the verification against the given Token + * Performs the verification against the given Token. * * @param token to verify. * @return a verified and decoded JWT. @@ -15,7 +18,7 @@ public interface JWTVerifier { DecodedJWT verify(String token) throws JWTVerificationException; /** - * Performs the verification against the given decoded JWT + * Performs the verification against the given decoded JWT. * * @param jwt to verify. * @return a verified and decoded JWT. diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java index fa3b13c9..fd8baea5 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java @@ -14,7 +14,8 @@ interface KeyProvider { /** * Getter for the Public Key instance with the given Id. Used to verify the signature on the JWT verification stage. * - * @param keyId the Key Id specified in the Token's Header or null if none is available. Provides a hint on which Public Key to use to verify the token's signature. + * @param keyId the Key Id specified in the Token's Header or null if none is available. + * Provides a hint on which Public Key to use to verify the token's signature. * @return the Public Key instance */ U getPublicKeyById(String keyId); @@ -27,7 +28,8 @@ interface KeyProvider { R getPrivateKey(); /** - * Getter for the Id of the Private Key used to sign the tokens. This represents the `kid` claim and will be placed in the Header. + * Getter for the Id of the Private Key used to sign the tokens. + * This represents the `kid` claim and will be placed in the Header. * * @return the Key Id that identifies the Private Key or null if it's not specified. */ diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index 1fb6aece..071b3e9c 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -60,7 +60,7 @@ default Verification withIssuer(String issuer) { * will have to provide their own implementation. * * The default implementation throws an {@linkplain UnsupportedOperationException}. - * + * * @param audience the required Audience value for which the "aud" claim must contain at least one value. * @return this same Verification instance. */ @@ -69,8 +69,8 @@ default Verification withAnyOfAudience(String... audience) { } /** - * Define the default window in seconds in which the Not Before, Issued At and Expires At Claims will still be valid. - * Setting a specific leeway value on a given Claim will override this value for that Claim. + * Define the default window in seconds in which the Not Before, Issued At and Expires At Claims + * will still be valid. Setting a specific leeway value on a given Claim will override this value for that Claim. * * @param leeway the window in seconds in which the Not Before, Issued At and Expires At Claims will still be valid. * @return this same Verification instance. @@ -80,7 +80,8 @@ default Verification withAnyOfAudience(String... audience) { /** * Set a specific leeway window in seconds in which the Expires At ("exp") Claim will still be valid. - * Expiration Date is always verified when the value is present. This method overrides the value set with acceptLeeway + * Expiration Date is always verified when the value is present. + * This method overrides the value set with acceptLeeway * * @param leeway the window in seconds in which the Expires At Claim will still be valid. * @return this same Verification instance. @@ -90,7 +91,8 @@ default Verification withAnyOfAudience(String... audience) { /** * Set a specific leeway window in seconds in which the Not Before ("nbf") Claim will still be valid. - * Not Before Date is always verified when the value is present. This method overrides the value set with acceptLeeway + * Not Before Date is always verified when the value is present. + * This method overrides the value set with acceptLeeway * * @param leeway the window in seconds in which the Not Before Claim will still be valid. * @return this same Verification instance. @@ -101,8 +103,10 @@ default Verification withAnyOfAudience(String... audience) { /** * Set a specific leeway window in seconds in which the Issued At ("iat") Claim will still be valid. * This method overrides the value set with {@link #acceptLeeway(long)}. - * By default, the Issued At claim is always verified when the value is present, unless disabled with {@link #ignoreIssuedAt()}. - * If Issued At verification has been disabled, no verification of the Issued At claim will be performed, and this method has no effect. + * By default, the Issued At claim is always verified when the value is present, + * unless disabled with {@link #ignoreIssuedAt()}. + * If Issued At verification has been disabled, no verification of the Issued At claim will be performed, + * and this method has no effect. * * @param leeway the window in seconds in which the Issued At Claim will still be valid. * @return this same Verification instance. @@ -120,6 +124,7 @@ default Verification withAnyOfAudience(String... audience) { /** * Require a claim to be present, with any value. + * * @param name the Claim's name. * @return this same Verification instance * @throws IllegalArgumentException if the name is null. @@ -177,8 +182,8 @@ default Verification withAnyOfAudience(String... audience) { Verification withClaim(String name, String value) throws IllegalArgumentException; /** - * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; when verifying - * date-time claim value, any time units more granular than seconds will not be considered. + * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; + * when verifying date-time claim value, any time units more granular than seconds will not be considered. * * @param name the Claim's name. * @param value the Claim's value. @@ -188,8 +193,8 @@ default Verification withAnyOfAudience(String... audience) { Verification withClaim(String name, Date value) throws IllegalArgumentException; /** - * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; when verifying - * a date-time claim value, any time units more granular than seconds will not be considered. + * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; + * when verifying a date-time claim value, any time units more granular than seconds will not be considered. * * @param name the Claim's name. * @param value the Claim's value. diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java index 120f6a9d..77d573bc 100644 --- a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java @@ -71,12 +71,12 @@ public Date asDate() { } @Override - public T[] asArray(Class tClazz) throws JWTDecodeException { + public T[] asArray(Class clazz) throws JWTDecodeException { return null; } @Override - public List asList(Class tClazz) throws JWTDecodeException { + public List asList(Class clazz) throws JWTDecodeException { return null; } From 0029a6363f89c1af43db64a76a002e8169c2656c Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 25 Mar 2022 16:25:50 +0530 Subject: [PATCH 018/134] [SDK-3155] Predicate based Claim verification (#562) * Rename claims -> expectedClaims in verifier for clarity * added method to validate claim value using predicate * Using Predicates for Verification (#560) * Use predicates for verification * Code review changes * Add additional tests for predicate based verification * Fixed Lint issues --- .../main/java/com/auth0/jwt/JWTVerifier.java | 366 ++++++++---------- .../auth0/jwt/interfaces/Verification.java | 12 + .../java/com/auth0/jwt/JWTVerifierTest.java | 207 +++++----- .../jwt/interfaces/VerificationTest.java | 6 + 4 files changed, 283 insertions(+), 308 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 77dfef4e..8b14ff86 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -14,6 +14,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.function.BiPredicate; /** * The JWTVerifier class holds the verify method to assert that a given Token has not only a proper JWT format, @@ -25,17 +26,12 @@ */ public final class JWTVerifier implements com.auth0.jwt.interfaces.JWTVerifier { private final Algorithm algorithm; - final Map claims; - private final Clock clock; + final Map> expectedChecks; private final JWTParser parser; - static final String AUDIENCE_EXACT = "AUDIENCE_EXACT"; - static final String AUDIENCE_CONTAINS = "AUDIENCE_CONTAINS"; - - JWTVerifier(Algorithm algorithm, Map claims, Clock clock) { + JWTVerifier(Algorithm algorithm, Map> expectedChecks) { this.algorithm = algorithm; - this.claims = Collections.unmodifiableMap(claims); - this.clock = clock; + this.expectedChecks = Collections.unmodifiableMap(expectedChecks); this.parser = new JWTParser(); } @@ -55,9 +51,11 @@ static Verification init(Algorithm algorithm) throws IllegalArgumentException { */ public static class BaseVerification implements Verification { private final Algorithm algorithm; - private final Map claims; + private final Map> expectedChecks; private long defaultLeeway; + private final Map customLeeways; private boolean ignoreIssuedAt; + private Clock clock; BaseVerification(Algorithm algorithm) throws IllegalArgumentException { if (algorithm == null) { @@ -65,33 +63,42 @@ public static class BaseVerification implements Verification { } this.algorithm = algorithm; - this.claims = new HashMap<>(); + this.expectedChecks = new LinkedHashMap<>(); + this.customLeeways = new HashMap<>(); this.defaultLeeway = 0; } @Override public Verification withIssuer(String... issuer) { - requireClaim(PublicClaims.ISSUER, isNullOrEmpty(issuer) ? null : Arrays.asList(issuer)); + List value = isNullOrEmpty(issuer) ? null : Arrays.asList(issuer); + checkIfNeedToRemove(PublicClaims.ISSUER, value, ((claim, decodedJWT) -> { + if (value == null || !value.contains(claim.asString())) { + throw new InvalidClaimException("The Claim 'iss' value doesn't match the required issuer."); + } + return true; + })); return this; } @Override public Verification withSubject(String subject) { - requireClaim(PublicClaims.SUBJECT, subject); + checkIfNeedToRemove(PublicClaims.SUBJECT, subject, (claim, decodedJWT) -> subject.equals(claim.asString())); return this; } @Override public Verification withAudience(String... audience) { - claims.remove(AUDIENCE_CONTAINS); - requireClaim(AUDIENCE_EXACT, isNullOrEmpty(audience) ? null : Arrays.asList(audience)); + List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); + checkIfNeedToRemove(PublicClaims.AUDIENCE, value, ((claim, decodedJWT) -> + assertValidAudienceClaim(decodedJWT.getAudience(), value, true))); return this; } @Override public Verification withAnyOfAudience(String... audience) { - claims.remove(AUDIENCE_EXACT); - requireClaim(AUDIENCE_CONTAINS, isNullOrEmpty(audience) ? null : Arrays.asList(audience)); + List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); + checkIfNeedToRemove(PublicClaims.AUDIENCE, value, ((claim, decodedJWT) -> + assertValidAudienceClaim(decodedJWT.getAudience(), value, false))); return this; } @@ -105,21 +112,21 @@ public Verification acceptLeeway(long leeway) throws IllegalArgumentException { @Override public Verification acceptExpiresAt(long leeway) throws IllegalArgumentException { assertPositive(leeway); - requireClaim(PublicClaims.EXPIRES_AT, leeway); + customLeeways.put(PublicClaims.EXPIRES_AT, leeway); return this; } @Override public Verification acceptNotBefore(long leeway) throws IllegalArgumentException { assertPositive(leeway); - requireClaim(PublicClaims.NOT_BEFORE, leeway); + customLeeways.put(PublicClaims.NOT_BEFORE, leeway); return this; } @Override public Verification acceptIssuedAt(long leeway) throws IllegalArgumentException { assertPositive(leeway); - requireClaim(PublicClaims.ISSUED_AT, leeway); + customLeeways.put(PublicClaims.ISSUED_AT, leeway); return this; } @@ -131,49 +138,54 @@ public Verification ignoreIssuedAt() { @Override public Verification withJWTId(String jwtId) { - requireClaim(PublicClaims.JWT_ID, jwtId); + checkIfNeedToRemove(PublicClaims.JWT_ID, jwtId, ((claim, decodedJWT) -> jwtId.equals(claim.asString()))); return this; } @Override public Verification withClaimPresence(String name) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, NonEmptyClaim.getInstance()); + withClaim(name, ((claim, decodedJWT) -> { + if (claim instanceof NullClaim) { + throw new InvalidClaimException(String.format("The Claim '%s' is not present in the JWT.", name)); + } + return true; + })); return this; } @Override public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, value); + checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asBoolean()))); return this; } @Override public Verification withClaim(String name, Integer value) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, value); + checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asInt()))); return this; } @Override public Verification withClaim(String name, Long value) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, value); + checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asLong()))); return this; } @Override public Verification withClaim(String name, Double value) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, value); + checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asDouble()))); return this; } @Override public Verification withClaim(String name, String value) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, value); + checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asString()))); return this; } @@ -187,28 +199,37 @@ public Verification withClaim(String name, Instant value) throws IllegalArgument assertNonNull(name); // Since date-time claims are serialized as epoch seconds, // we need to compare them with only seconds-granularity - requireClaim(name, value != null ? value.truncatedTo(ChronoUnit.SECONDS) : null); + checkIfNeedToRemove(name, value, + ((claim, decodedJWT) -> value.truncatedTo(ChronoUnit.SECONDS).equals(claim.asInstant()))); + return this; + } + + @Override + public Verification withClaim(String name, BiPredicate predicate) + throws IllegalArgumentException { + assertNonNull(name); + checkIfNeedToRemove(name, predicate, predicate); return this; } @Override public Verification withArrayClaim(String name, String... items) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, items); + checkIfNeedToRemove(name, items, ((claim, decodedJWT) -> assertValidCollectionClaim(claim, items))); return this; } @Override public Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, items); + checkIfNeedToRemove(name, items, ((claim, decodedJWT) -> assertValidCollectionClaim(claim, items))); return this; } @Override public Verification withArrayClaim(String name, Long... items) throws IllegalArgumentException { assertNonNull(name); - requireClaim(name, items); + checkIfNeedToRemove(name, items, ((claim, decodedJWT) -> assertValidCollectionClaim(claim, items))); return this; } @@ -225,59 +246,122 @@ public JWTVerifier build() { * @return a new JWTVerifier instance with a custom {@link java.time.Clock} */ public JWTVerifier build(Clock clock) { - addLeewayToDateClaims(); - return new JWTVerifier(algorithm, claims, clock); + this.clock = clock; + addMandatoryClaimChecks(); + return new JWTVerifier(algorithm, expectedChecks); } - private void assertPositive(long leeway) { - if (leeway < 0) { - throw new IllegalArgumentException("Leeway value can't be negative."); + /** + * Fetches the Leeway set for claim or returns the {@link BaseVerification#defaultLeeway}. + * + * @param name Claim for which leeway is fetched + * @return Leeway value set for the claim + */ + public long getLeewayFor(String name) { + return customLeeways.getOrDefault(name, defaultLeeway); + } + + private void addMandatoryClaimChecks() { + long expiresAtLeeway = getLeewayFor(PublicClaims.EXPIRES_AT); + long notBeforeLeeway = getLeewayFor(PublicClaims.NOT_BEFORE); + long issuedAtLeeway = getLeewayFor(PublicClaims.ISSUED_AT); + + checkIfNeedToRemove(PublicClaims.EXPIRES_AT, expiresAtLeeway, ((claim, decodedJWT) -> + assertValidInstantClaim(claim.asInstant(), expiresAtLeeway, true))); + checkIfNeedToRemove(PublicClaims.NOT_BEFORE, notBeforeLeeway, ((claim, decodedJWT) -> + assertValidInstantClaim(claim.asInstant(), notBeforeLeeway, false))); + if (!ignoreIssuedAt) { + checkIfNeedToRemove(PublicClaims.ISSUED_AT, issuedAtLeeway, ((claim, decodedJWT) -> + assertValidInstantClaim(claim.asInstant(), issuedAtLeeway, false))); } } - private void assertNonNull(String name) { - if (name == null) { - throw new IllegalArgumentException("The Custom Claim's name can't be null."); + private boolean assertValidCollectionClaim(Claim claim, Object[] expectedClaimValue) { + List claimArr; + Object[] claimAsObject = claim.as(Object[].class); + + // Jackson uses 'natural' mapping which uses Integer if value fits in 32 bits. + if (expectedClaimValue instanceof Long[]) { + // convert Integers to Longs for comparison with equals + claimArr = new ArrayList<>(claimAsObject.length); + for (Object cao : claimAsObject) { + if (cao instanceof Integer) { + claimArr.add(((Integer) cao).longValue()); + } else { + claimArr.add(cao); + } + } + } else { + claimArr = claim.isNull() ? Collections.emptyList() : Arrays.asList(claim.as(Object[].class)); } + List valueArr = Arrays.asList(expectedClaimValue); + return claimArr.containsAll(valueArr); } - private void addLeewayToDateClaims() { - if (!claims.containsKey(PublicClaims.EXPIRES_AT)) { - claims.put(PublicClaims.EXPIRES_AT, defaultLeeway); + private boolean assertValidInstantClaim(Instant claimVal, long leeway, boolean shouldBeFuture) { + Instant now = clock.instant().truncatedTo(ChronoUnit.SECONDS); + if (shouldBeFuture) { + return assertInstantIsFuture(claimVal, leeway, now); + } else { + return assertInstantIsPast(claimVal, leeway, now); } - if (!claims.containsKey(PublicClaims.NOT_BEFORE)) { - claims.put(PublicClaims.NOT_BEFORE, defaultLeeway); + } + + private boolean assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { + if (claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)) { + throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal)); } - if (ignoreIssuedAt) { - claims.remove(PublicClaims.ISSUED_AT); - return; + return true; + } + + private boolean assertInstantIsPast(Instant claimVal, long leeway, Instant now) { + if (claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)) { + throw new InvalidClaimException(String.format("The Token can't be used before %s.", claimVal)); + } + return true; + } + + private boolean assertValidAudienceClaim(List audience, List values, boolean shouldContainAll) { + if (audience == null || (shouldContainAll && !audience.containsAll(values)) + || (!shouldContainAll && Collections.disjoint(audience, values))) { + throw new InvalidClaimException("The Claim 'aud' value doesn't contain the required audience."); } - if (!claims.containsKey(PublicClaims.ISSUED_AT)) { - claims.put(PublicClaims.ISSUED_AT, defaultLeeway); + return true; + } + + private void assertPositive(long leeway) { + if (leeway < 0) { + throw new IllegalArgumentException("Leeway value can't be negative."); + } + } + + private void assertNonNull(String name) { + if (name == null) { + throw new IllegalArgumentException("The Custom Claim's name can't be null."); } } - private void requireClaim(String name, Object value) { + private void checkIfNeedToRemove(String name, Object value, BiPredicate predicate) { if (value == null) { - claims.remove(name); + expectedChecks.remove(name); return; } - claims.put(name, value); + expectedChecks.put(name, predicate); } - } - private static boolean isNullOrEmpty(String[] args) { - if (args == null || args.length == 0) { - return true; - } - boolean isAllNull = true; - for (String arg : args) { - if (arg != null) { - isAllNull = false; - break; + private boolean isNullOrEmpty(String[] args) { + if (args == null || args.length == 0) { + return true; + } + boolean isAllNull = true; + for (String arg : args) { + if (arg != null) { + isAllNull = false; + break; + } } + return isAllNull; } - return isAllNull; } @@ -313,7 +397,7 @@ public DecodedJWT verify(String token) throws JWTVerificationException { public DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException { verifyAlgorithm(jwt, algorithm); algorithm.verify(jwt); - verifyClaims(jwt, claims); + verifyClaims(jwt, expectedChecks); return jwt; } @@ -324,156 +408,20 @@ private void verifyAlgorithm(DecodedJWT jwt, Algorithm expectedAlgorithm) throws } } - private void verifyClaims(DecodedJWT jwt, Map claims) + private void verifyClaims(DecodedJWT jwt, Map> claims) throws TokenExpiredException, InvalidClaimException { - for (Map.Entry entry : claims.entrySet()) { - if (entry.getValue() instanceof NonEmptyClaim) { - assertClaimPresent(jwt.getClaim(entry.getKey()), entry.getKey()); - } else { - verifyClaimValues(jwt, entry); - } - } - } - - private void verifyClaimValues(DecodedJWT jwt, Map.Entry expectedClaim) { - switch (expectedClaim.getKey()) { - // We use custom keys for audience in the expected claims to differentiate between - // validating that the audience contains all expected values, or validating that the audience contains - // at least one of the expected values. - case AUDIENCE_EXACT: - assertValidAudienceClaim(jwt.getAudience(), (List) expectedClaim.getValue(), true); - break; - case AUDIENCE_CONTAINS: - assertValidAudienceClaim(jwt.getAudience(), (List) expectedClaim.getValue(), false); - break; - case PublicClaims.EXPIRES_AT: - assertValidInstantClaim(jwt.getExpiresAtAsInstant(), (Long) expectedClaim.getValue(), true); - break; - case PublicClaims.ISSUED_AT: - assertValidInstantClaim(jwt.getIssuedAtAsInstant(), (Long) expectedClaim.getValue(), false); - break; - case PublicClaims.NOT_BEFORE: - assertValidInstantClaim(jwt.getNotBeforeAsInstant(), (Long) expectedClaim.getValue(), false); - break; - case PublicClaims.ISSUER: - assertValidIssuerClaim(jwt.getIssuer(), (List) expectedClaim.getValue()); - break; - case PublicClaims.JWT_ID: - assertValidStringClaim(expectedClaim.getKey(), jwt.getId(), (String) expectedClaim.getValue()); - break; - case PublicClaims.SUBJECT: - assertValidStringClaim(expectedClaim.getKey(), jwt.getSubject(), (String) expectedClaim.getValue()); - break; - default: - assertValidClaim(jwt.getClaim(expectedClaim.getKey()), expectedClaim.getKey(), - expectedClaim.getValue()); - break; - } - } - - private void assertClaimPresent(Claim claim, String claimName) { - if (claim instanceof NullClaim) { - throw new InvalidClaimException(String.format("The Claim '%s' is not present in the JWT.", claimName)); - } - } - - private void assertValidClaim(Claim claim, String claimName, Object value) { - boolean isValid = false; - if (value instanceof String) { - isValid = value.equals(claim.asString()); - } else if (value instanceof Integer) { - isValid = value.equals(claim.asInt()); - } else if (value instanceof Long) { - isValid = value.equals(claim.asLong()); - } else if (value instanceof Boolean) { - isValid = value.equals(claim.asBoolean()); - } else if (value instanceof Double) { - isValid = value.equals(claim.asDouble()); - } else if (value instanceof Instant) { - isValid = value.equals(claim.asInstant()); - } else if (value instanceof Object[]) { - List claimArr; - Object[] claimAsObject = claim.as(Object[].class); - - // Jackson uses 'natural' mapping which uses Integer if value fits in 32 bits. - if (value instanceof Long[]) { - // convert Integers to Longs for comparison with equals - claimArr = new ArrayList<>(claimAsObject.length); - for (Object cao : claimAsObject) { - if (cao instanceof Integer) { - claimArr.add(((Integer) cao).longValue()); - } else { - claimArr.add(cao); - } - } - } else { - claimArr = claim.isNull() ? Collections.emptyList() : Arrays.asList(claim.as(Object[].class)); - } - List valueArr = Arrays.asList((Object[]) value); - isValid = claimArr.containsAll(valueArr); - } - - if (!isValid) { - throw new InvalidClaimException( - String.format("The Claim '%s' value doesn't match the required one.", claimName)); - } - } - - private void assertValidStringClaim(String claimName, String value, String expectedValue) { - if (!expectedValue.equals(value)) { - throw new InvalidClaimException( - String.format("The Claim '%s' value doesn't match the required one.", claimName)); - } - } - - private void assertValidInstantClaim(Instant claimVal, long leeway, boolean shouldBeFuture) { - Instant now = clock.instant().truncatedTo(ChronoUnit.SECONDS); - if (shouldBeFuture) { - assertInstantIsFuture(claimVal, leeway, now); - } else { - assertInstantIsPast(claimVal, leeway, now); - } - } - - private void assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { - if (claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)) { - throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal)); - } - } - - private void assertInstantIsPast(Instant claimVal, long leeway, Instant now) { - if (claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)) { - throw new InvalidClaimException(String.format("The Token can't be used before %s.", claimVal)); - } - } - - private void assertValidAudienceClaim(List audience, List values, boolean shouldContainAll) { - if (audience == null || (shouldContainAll && !audience.containsAll(values)) - || (!shouldContainAll && Collections.disjoint(audience, values))) { - throw new InvalidClaimException("The Claim 'aud' value doesn't contain the required audience."); - } - } + for (Map.Entry> entry : claims.entrySet()) { + boolean isValid; + String claimName = entry.getKey(); + BiPredicate expectedCheck = entry.getValue(); + Claim claim = jwt.getClaim(claimName); - private void assertValidIssuerClaim(String issuer, List value) { - if (issuer == null || !value.contains(issuer)) { - throw new InvalidClaimException("The Claim 'iss' value doesn't match the required issuer."); - } - } - - /** - * Simple singleton used to mark that a claim should only be verified for presence. - */ - private static class NonEmptyClaim { - private static NonEmptyClaim nonEmptyClaim; - - private NonEmptyClaim() { - } + isValid = expectedCheck.test(claim, jwt); - public static NonEmptyClaim getInstance() { - if (nonEmptyClaim == null) { - nonEmptyClaim = new NonEmptyClaim(); + if (!isValid) { + throw new InvalidClaimException( + String.format("The Claim '%s' value doesn't match the required one.", claimName)); } - return nonEmptyClaim; } } } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index 071b3e9c..ffe0b920 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -4,6 +4,7 @@ import java.time.Instant; import java.util.Date; +import java.util.function.BiPredicate; /** * Holds the Claims and claim-based configurations required for a JWT to be considered valid. @@ -205,6 +206,17 @@ default Verification withClaim(String name, Instant value) throws IllegalArgumen return withClaim(name, value != null ? Date.from(value) : null); } + /** + * Executes the predicate provided during the verification + * and passes the verification if the predicate returns true. + * + * @param name the Claim's name + * @param predicate the predicate check to be done. + * @return this same Verification instance. + * @throws IllegalArgumentException if the name is null. + */ + Verification withClaim(String name, BiPredicate predicate) throws IllegalArgumentException; + /** * Require a specific Array Claim to contain at least the given items. * diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 93a7bcd1..1d80d802 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -4,6 +4,8 @@ import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.InvalidClaimException; import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.impl.PublicClaims; +import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; import org.junit.Rule; @@ -16,11 +18,11 @@ import java.time.ZoneId; import java.util.Collections; import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import java.util.function.BiPredicate; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.mock; public class JWTVerifierTest { @@ -263,63 +265,29 @@ public void shouldRemoveAudienceWhenPassingNullReference() { .withAudience((String) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey(JWTVerifier.AUDIENCE_EXACT))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey(PublicClaims.AUDIENCE))); verifier = JWTVerifier.init(algorithm) .withAudience((String[]) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey(JWTVerifier.AUDIENCE_EXACT))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey(PublicClaims.AUDIENCE))); verifier = JWTVerifier.init(algorithm) .withAudience() .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey(JWTVerifier.AUDIENCE_EXACT))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey(PublicClaims.AUDIENCE))); String emptyAud = " "; verifier = JWTVerifier.init(algorithm) .withAudience(emptyAud) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry(JWTVerifier.AUDIENCE_EXACT, Collections.singletonList(emptyAud))); - } - - @Test - public void shouldRemoveAudienceWhenPassingNullReferenceWithAnyOfAudience() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) - .withAnyOfAudience((String) null) - .build(); - - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey(JWTVerifier.AUDIENCE_CONTAINS))); - - verifier = JWTVerifier.init(algorithm) - .withAnyOfAudience((String[]) null) - .build(); - - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey(JWTVerifier.AUDIENCE_CONTAINS))); - - verifier = JWTVerifier.init(algorithm) - .withAnyOfAudience() - .build(); - - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey(JWTVerifier.AUDIENCE_CONTAINS))); - - String emptyAud = " "; - verifier = JWTVerifier.init(algorithm) - .withAnyOfAudience(emptyAud) - .build(); - - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry(JWTVerifier.AUDIENCE_CONTAINS, Collections.singletonList(emptyAud))); + assertThat(verifier.expectedChecks, is(notNullValue())); } @Test @@ -330,16 +298,16 @@ public void shouldRemoveAudienceWhenPassingNull() { .withAudience((String) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("aud"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("aud"))); verifier = JWTVerifier.init(algorithm) .withAudience("John") .withAudience((String[]) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("aud"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("aud"))); } @Test @@ -350,16 +318,16 @@ public void shouldRemoveAudienceWhenPassingNullWithAnyAudience() { .withAnyOfAudience((String) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("aud"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("aud"))); verifier = JWTVerifier.init(algorithm) .withAnyOfAudience("John") .withAnyOfAudience((String[]) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("aud"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("aud"))); } @Test @@ -453,10 +421,10 @@ public void shouldThrowOnInvalidCustomClaimValue() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - Map map = new HashMap<>(); - map.put("name", new Object()); - JWTVerifier verifier = new JWTVerifier(Algorithm.HMAC256("secret"), map, Clock.systemUTC()); - verifier.verify(token); + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", "check") + .build() + .verify(token); } @Test @@ -533,8 +501,8 @@ public void shouldRemoveCustomClaimOfTypeDateWhenNull() { .withClaim("name", (Date) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("iss"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("iss"))); } @Test @@ -593,76 +561,76 @@ public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsIntegerAndLong() } // Generic Delta - @SuppressWarnings("RedundantCast") @Test public void shouldAddDefaultLeewayToDateClaims() { Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); + JWTVerifier verifier = verification .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry("iat", (Object) 0L)); - assertThat(verifier.claims, hasEntry("exp", (Object) 0L)); - assertThat(verifier.claims, hasEntry("nbf", (Object) 0L)); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(0L)); + assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(0L)); + assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(0L)); } - @SuppressWarnings("RedundantCast") @Test public void shouldAddCustomLeewayToDateClaims() { Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); + JWTVerifier verifier = verification .acceptLeeway(1234L) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry("iat", (Object) 1234L)); - assertThat(verifier.claims, hasEntry("exp", (Object) 1234L)); - assertThat(verifier.claims, hasEntry("nbf", (Object) 1234L)); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(1234L)); } - @SuppressWarnings("RedundantCast") @Test public void shouldOverrideDefaultIssuedAtLeeway() { Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); + JWTVerifier verifier = verification .acceptLeeway(1234L) .acceptIssuedAt(9999L) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry("iat", (Object) 9999L)); - assertThat(verifier.claims, hasEntry("exp", (Object) 1234L)); - assertThat(verifier.claims, hasEntry("nbf", (Object) 1234L)); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(9999L)); + assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(1234L)); } - @SuppressWarnings("RedundantCast") @Test public void shouldOverrideDefaultExpiresAtLeeway() { Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); + JWTVerifier verifier = verification .acceptLeeway(1234L) .acceptExpiresAt(9999L) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry("iat", (Object) 1234L)); - assertThat(verifier.claims, hasEntry("exp", (Object) 9999L)); - assertThat(verifier.claims, hasEntry("nbf", (Object) 1234L)); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(9999L)); + assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(1234L)); } - @SuppressWarnings("RedundantCast") @Test public void shouldOverrideDefaultNotBeforeLeeway() { Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(algorithm); + JWTVerifier verifier = verification .acceptLeeway(1234L) .acceptNotBefore(9999L) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry("iat", (Object) 1234L)); - assertThat(verifier.claims, hasEntry("exp", (Object) 1234L)); - assertThat(verifier.claims, hasEntry("nbf", (Object) 9999L)); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(9999L)); } @Test @@ -860,16 +828,16 @@ public void shouldRemoveClaimWhenPassingNull() { .withIssuer((String) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("iss"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("iss"))); verifier = JWTVerifier.init(algorithm) .withIssuer("iss") .withIssuer((String[]) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("iss"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("iss"))); } @Test @@ -879,30 +847,29 @@ public void shouldRemoveIssuerWhenPassingNullReference() { .withIssuer((String) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("iss"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("iss"))); verifier = JWTVerifier.init(algorithm) .withIssuer((String[]) null) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("iss"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("iss"))); verifier = JWTVerifier.init(algorithm) .withIssuer() .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, not(hasKey("iss"))); + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("iss"))); String emptyIss = " "; verifier = JWTVerifier.init(algorithm) .withIssuer(emptyIss) .build(); - assertThat(verifier.claims, is(notNullValue())); - assertThat(verifier.claims, hasEntry("iss", Collections.singletonList(emptyIss))); + assertThat(verifier.expectedChecks, is(notNullValue())); } @Test @@ -1055,4 +1022,46 @@ public void shouldVerifyStandardClaimPresence() { DecodedJWT decodedJWT = verifier.verify(jwt); assertThat(decodedJWT, is(notNullValue())); } + + @Test + public void shouldSuccessfullyVerifyClaimWithPredicate() { + String jwt = JWTCreator.init() + .withClaim("claimName", "claimValue") + .sign(Algorithm.HMAC256("secret")); + + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("claimName", (claim, decodedJWT) -> "claimValue".equals(claim.asString())) + .withClaim(PublicClaims.ISSUED_AT, ((claim, decodedJWT) -> false)) + .build(); + + DecodedJWT decodedJWT = verifier.verify(jwt); + assertThat(decodedJWT, is(notNullValue())); + } + + @Test + public void shouldThrowWhenPredicateReturnsFalse() { + exception.expect(InvalidClaimException.class); + exception.expectMessage("The Claim 'claimName' value doesn't match the required one."); + + String jwt = JWTCreator.init() + .withClaim("claimName", "claimValue") + .sign(Algorithm.HMAC256("secret")); + + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) + .build() + .verify(jwt); + } + + @Test + public void shouldRemovePredicateCheckForNull() { + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) + .withClaim("claimName", (BiPredicate) null) + .build(); + + assertThat(verifier.expectedChecks, is(notNullValue())); + assertThat(verifier.expectedChecks, not(hasKey("claimName"))); + } + } diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java index e9f4f815..c7f89763 100644 --- a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java +++ b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java @@ -7,6 +7,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.function.BiPredicate; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; @@ -149,6 +150,11 @@ public Verification withArrayClaim(String name, Long... items) throws IllegalArg return null; } + @Override + public Verification withClaim(String name, BiPredicate predicate) throws IllegalArgumentException { + return null; + } + @Override public Verification ignoreIssuedAt() { return null; From e37301aad52681174bcd2dc39844ab56408e7b8a Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 25 Mar 2022 16:38:56 +0530 Subject: [PATCH 019/134] [SDK-3158] Null claim handling (#564) * Handle claim difference between missing and null * Verification with null claims * JWT creation support for null values * Test cases for JWT verification and construction * Add JWT decode test cases * Fix broken tests * Fixed Lint issues * Fixed formatting errors * Add test case to check Claim toString conversion --- .../main/java/com/auth0/jwt/JWTCreator.java | 45 ++++-- .../main/java/com/auth0/jwt/JWTVerifier.java | 13 +- .../com/auth0/jwt/impl/JsonNodeClaim.java | 39 +++-- .../java/com/auth0/jwt/impl/NullClaim.java | 79 --------- .../java/com/auth0/jwt/interfaces/Claim.java | 10 ++ .../auth0/jwt/interfaces/Verification.java | 9 ++ .../java/com/auth0/jwt/JWTCreatorTest.java | 152 +++++++++--------- .../java/com/auth0/jwt/JWTDecoderTest.java | 21 ++- .../java/com/auth0/jwt/JWTVerifierTest.java | 43 +++++ .../com/auth0/jwt/impl/BasicHeaderTest.java | 3 +- .../com/auth0/jwt/impl/JsonNodeClaimTest.java | 45 +++++- .../com/auth0/jwt/impl/NullClaimTest.java | 82 ---------- .../com/auth0/jwt/impl/PayloadImplTest.java | 3 +- .../com/auth0/jwt/interfaces/ClaimTest.java | 5 + .../jwt/interfaces/VerificationTest.java | 5 + 15 files changed, 273 insertions(+), 281 deletions(-) delete mode 100644 lib/src/main/java/com/auth0/jwt/impl/NullClaim.java delete mode 100644 lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index 6b355b36..e1159ae4 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -75,7 +75,6 @@ public static class Builder { /** * Add specific Claims to set as the Header. * If provided map is null then nothing is changed - * If provided map contains a claim with null value then that claim will be removed from the header * * @param headerClaims the values to use as Claims in the token's Header. * @return this same Builder instance. @@ -362,7 +361,6 @@ public Builder withClaim(String name, Map map) throws IllegalArgument * @return this same Builder instance. * @throws IllegalArgumentException if the name is null, or if the list contents does not validate. */ - public Builder withClaim(String name, List list) throws IllegalArgumentException { assertNonNull(name); // validate list contents @@ -374,6 +372,19 @@ public Builder withClaim(String name, List list) throws IllegalArgumentExcept return this; } + /** + * Add a custom claim with null value. + * + * @param name the Claim's name. + * @return this same Builder instance. + * @throws IllegalArgumentException if the name is null + */ + public Builder withNullClaim(String name) throws IllegalArgumentException { + assertNonNull(name); + addClaim(name, null); + return this; + } + /** * Add a custom Array Claim with the given items. * @@ -422,8 +433,8 @@ public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentE *

* Accepted types are {@linkplain Map} and {@linkplain List} with basic types * {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double}, - * {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values. - * {@linkplain List}s can contain null elements. + * {@linkplain String} and {@linkplain Date}. + * {@linkplain Map}s and {@linkplain List}s can contain null elements. *

* *

@@ -442,7 +453,7 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE if (!validatePayload(payloadClaims)) { throw new IllegalArgumentException("Claim values must only be of types Map, List, Boolean, Integer, " - + "Long, Double, String and Date"); + + "Long, Double, String, Date and Null"); } // add claims only after validating all claims so as not to corrupt the claims map of this builder @@ -463,7 +474,7 @@ private boolean validatePayload(Map payload) { return false; } else if (value instanceof Map && !validateClaim((Map) value)) { return false; - } else if (value != null && !isSupportedType(value)) { + } else if (!isSupportedType(value)) { return false; } } @@ -474,7 +485,7 @@ private static boolean validateClaim(Map map) { // do not accept null values in maps for (Entry entry : map.entrySet()) { Object value = entry.getValue(); - if (value == null || !isSupportedType(value)) { + if (!isSupportedType(value)) { return false; } @@ -488,7 +499,7 @@ private static boolean validateClaim(Map map) { private static boolean validateClaim(List list) { // accept null values in list for (Object object : list) { - if (object != null && !isSupportedType(object)) { + if (!isSupportedType(object)) { return false; } } @@ -506,13 +517,17 @@ private static boolean isSupportedType(Object value) { } private static boolean isBasicType(Object value) { - Class c = value.getClass(); + if (value == null) { + return true; + } else { + Class c = value.getClass(); - if (c.isArray()) { - return c == Integer[].class || c == Long[].class || c == String[].class; + if (c.isArray()) { + return c == Integer[].class || c == Long[].class || c == String[].class; + } + return c == String.class || c == Integer.class || c == Long.class || c == Double.class + || c == Date.class || c == Instant.class || c == Boolean.class; } - return c == String.class || c == Integer.class || c == Long.class || c == Double.class - || c == Date.class || c == Instant.class || c == Boolean.class; } /** @@ -546,10 +561,6 @@ private void assertNonNull(String name) { } private void addClaim(String name, Object value) { - if (value == null) { - payloadClaims.remove(name); - return; - } payloadClaims.put(name, value); } } diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 8b14ff86..947c9e25 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -3,7 +3,6 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.*; import com.auth0.jwt.impl.JWTParser; -import com.auth0.jwt.impl.NullClaim; import com.auth0.jwt.impl.PublicClaims; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; @@ -146,7 +145,7 @@ public Verification withJWTId(String jwtId) { public Verification withClaimPresence(String name) throws IllegalArgumentException { assertNonNull(name); withClaim(name, ((claim, decodedJWT) -> { - if (claim instanceof NullClaim) { + if (claim.isMissing()) { throw new InvalidClaimException(String.format("The Claim '%s' is not present in the JWT.", name)); } return true; @@ -154,6 +153,13 @@ public Verification withClaimPresence(String name) throws IllegalArgumentExcepti return this; } + @Override + public Verification withNullClaim(String name) throws IllegalArgumentException { + assertNonNull(name); + withClaim(name, ((claim, decodedJWT) -> claim.isNull())); + return this; + } + @Override public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { assertNonNull(name); @@ -292,7 +298,8 @@ private boolean assertValidCollectionClaim(Claim claim, Object[] expectedClaimVa } } } else { - claimArr = claim.isNull() ? Collections.emptyList() : Arrays.asList(claim.as(Object[].class)); + claimArr = claim.isNull() || claim.isMissing() + ? Collections.emptyList() : Arrays.asList(claim.as(Object[].class)); } List valueArr = Arrays.asList(expectedClaimValue); return claimArr.containsAll(valueArr); diff --git a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java index 54a09575..5bb3dbbc 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java @@ -31,32 +31,32 @@ private JsonNodeClaim(JsonNode node, ObjectReader objectReader) { @Override public Boolean asBoolean() { - return !data.isBoolean() ? null : data.asBoolean(); + return isMissing() || isNull() || !data.isBoolean() ? null : data.asBoolean(); } @Override public Integer asInt() { - return !data.isNumber() ? null : data.asInt(); + return isMissing() || isNull() || !data.isNumber() ? null : data.asInt(); } @Override public Long asLong() { - return !data.isNumber() ? null : data.asLong(); + return isMissing() || isNull() || !data.isNumber() ? null : data.asLong(); } @Override public Double asDouble() { - return !data.isNumber() ? null : data.asDouble(); + return isMissing() || isNull() || !data.isNumber() ? null : data.asDouble(); } @Override public String asString() { - return !data.isTextual() ? null : data.asText(); + return isMissing() || isNull() || !data.isTextual() ? null : data.asText(); } @Override public Date asDate() { - if (!data.canConvertToLong()) { + if (isMissing() || isNull() || !data.canConvertToLong()) { return null; } long seconds = data.asLong(); @@ -65,7 +65,7 @@ public Date asDate() { @Override public Instant asInstant() { - if (!data.canConvertToLong()) { + if (isMissing() || isNull() || !data.canConvertToLong()) { return null; } long seconds = data.asLong(); @@ -75,7 +75,7 @@ public Instant asInstant() { @Override @SuppressWarnings("unchecked") public T[] asArray(Class clazz) throws JWTDecodeException { - if (!data.isArray()) { + if (isMissing() || isNull() || !data.isArray()) { return null; } @@ -92,7 +92,7 @@ public T[] asArray(Class clazz) throws JWTDecodeException { @Override public List asList(Class clazz) throws JWTDecodeException { - if (!data.isArray()) { + if (isMissing() || isNull() || !data.isArray()) { return null; } @@ -109,7 +109,7 @@ public List asList(Class clazz) throws JWTDecodeException { @Override public Map asMap() throws JWTDecodeException { - if (!data.isObject()) { + if (isMissing() || isNull() || !data.isObject()) { return null; } @@ -126,6 +126,9 @@ public Map asMap() throws JWTDecodeException { @Override public T as(Class clazz) throws JWTDecodeException { try { + if (isMissing() || isNull()) { + return null; + } return objectReader.treeAsTokens(data).readValueAs(clazz); } catch (IOException e) { throw new JWTDecodeException("Couldn't map the Claim value to " + clazz.getSimpleName(), e); @@ -134,11 +137,21 @@ public T as(Class clazz) throws JWTDecodeException { @Override public boolean isNull() { - return false; + return !isMissing() && data.isNull(); + } + + @Override + public boolean isMissing() { + return data == null || data.isMissingNode(); } @Override public String toString() { + if (isMissing()) { + return "Missing claim"; + } else if (isNull()) { + return "Null claim"; + } return data.toString(); } @@ -161,10 +174,8 @@ static Claim extractClaim(String claimName, Map tree, ObjectRe * @return a valid Claim instance. If the node is null or missing, a NullClaim will be returned. */ static Claim claimFromNode(JsonNode node, ObjectReader objectReader) { - if (node == null || node.isNull() || node.isMissingNode()) { - return new NullClaim(); - } return new JsonNodeClaim(node, objectReader); } } +//todo test all as* methods in JsonNodeClaim to ensure isMissing isNull calls are made \ No newline at end of file diff --git a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java deleted file mode 100644 index 2975b51b..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.auth0.jwt.impl; - -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.Claim; - -import java.time.Instant; -import java.util.Date; -import java.util.List; -import java.util.Map; - -/** - * The {@code NullClaim} class is a Claim implementation that returns null when any of it's methods is called. - */ -public class NullClaim implements Claim { - @Override - public boolean isNull() { - return true; - } - - @Override - public Boolean asBoolean() { - return null; - } - - @Override - public Integer asInt() { - return null; - } - - @Override - public Long asLong() { - return null; - } - - @Override - public Double asDouble() { - return null; - } - - @Override - public String asString() { - return null; - } - - @Override - public Date asDate() { - return null; - } - - @Override - public Instant asInstant() { - return null; - } - - @Override - public T[] asArray(Class clazz) throws JWTDecodeException { - return null; - } - - @Override - public List asList(Class clazz) throws JWTDecodeException { - return null; - } - - @Override - public Map asMap() throws JWTDecodeException { - return null; - } - - @Override - public T as(Class clazz) throws JWTDecodeException { - return null; - } - - @Override - public String toString() { - return "Null Claim"; - } -} diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java index fdfac715..f6ccfdcd 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java @@ -14,11 +14,20 @@ public interface Claim { /** * Whether this Claim has a null value or not. + * If the claim is not present, it will return false hence checking {@link Claim#isMissing} is advised as well * * @return whether this Claim has a null value or not. */ boolean isNull(); + /** + * Can be used to verify whether the Claim is found or not. + * This will be true even if the Claim has null value associated to it. + * + * @return whether this Claim is present or not + */ + boolean isMissing(); + /** * Get this Claim as a Boolean. * If the value isn't of type Boolean or it can't be converted to a Boolean, null will be returned. @@ -110,6 +119,7 @@ default Instant asInstant() { /** * Get this Claim as a custom type T. + * This method will return null if {@link Claim#isMissing()} or {@link Claim#isNull()} is true * * @param type * @param clazz the type class diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index ffe0b920..8b0416dc 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -132,6 +132,15 @@ default Verification withAnyOfAudience(String... audience) { */ Verification withClaimPresence(String name) throws IllegalArgumentException; + /** + * Require a specific Claim value to be null. + * + * @param name the Claim's name. + * @return this same Verification instance. + * @throws IllegalArgumentException if the name is null. + */ + Verification withNullClaim(String name) throws IllegalArgumentException; + /** * Require a specific Claim value. * diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 6c870656..3cccbf7b 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -326,17 +326,6 @@ public void shouldAddJWTId() { assertThat(TokenUtils.splitToken(signed)[1], is("eyJqdGkiOiJqd3RfaWRfMTIzIn0")); } - @Test - public void shouldRemoveClaimWhenPassingNull() { - String signed = JWTCreator.init() - .withIssuer("iss") - .withIssuer(null) - .sign(Algorithm.HMAC256("secret")); - - assertThat(signed, is(notNullValue())); - assertThat(TokenUtils.splitToken(signed)[1], is("e30")); - } - @Test public void shouldSetCorrectAlgorithmInTheHeader() { String signed = JWTCreator.init() @@ -615,7 +604,7 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); - + String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); ObjectMapper mapper = new ObjectMapper(); List list = (List) mapper.readValue(body, Map.class).get("data"); @@ -648,52 +637,6 @@ public void shouldAcceptCustomClaimForNullListItem() { .sign(Algorithm.HMAC256("secret")); } - @Test - @SuppressWarnings("unchecked") - public void shouldAcceptCustomClaimWithNullMapAndRemoveClaim() throws Exception { - String jwt = JWTCreator.init() - .withClaim("map", "stubValue") - .withClaim("map", (Map) null) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - - String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - Map map = (Map) mapper.readValue(body, Map.class); - assertThat(map, anEmptyMap()); - } - - @Test - @SuppressWarnings("unchecked") - public void shouldAcceptCustomClaimWithNullListAndRemoveClaim() throws Exception { - String jwt = JWTCreator.init() - .withClaim("list", "stubValue") - .withClaim("list", (List) null) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - - String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - Map map = (Map) mapper.readValue(body, Map.class); - assertThat(map, anEmptyMap()); - } - - @Test - public void shouldRefuseCustomClaimForNullMapValue() { - Map data = new HashMap<>(); - data.put("subKey", null); - - exception.expect(IllegalArgumentException.class); - - JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); - } - @Test public void shouldRefuseCustomClaimForNullMapKey() { Map data = new HashMap<>(); @@ -814,26 +757,10 @@ public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { assertThat(payloadJson, JsonMatcher.hasEntry(PublicClaims.ISSUER, "abc")); } - @Test - public void shouldRemovePayloadIfTheValueIsNull() throws Exception { - String jwt = JWTCreator.init() - .withClaim("key", "stubValue") - .withPayload(Collections.singletonMap("key", (Map) null)) - .sign(Algorithm.HMAC256("secret")); - - assertThat(jwt, is(notNullValue())); - String[] parts = jwt.split("\\."); - - String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - Map map = (Map) mapper.readValue(body, Map.class); - assertThat(map, anEmptyMap()); - } - @Test public void withPayloadShouldNotAllowCustomType() { exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String and Date"); + exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date and Null"); Map payload = new HashMap<>(); payload.put("entry", "value"); @@ -860,7 +787,7 @@ public void withPayloadShouldAllowNullListItems() { @Test public void withPayloadShouldNotAllowListWithCustomType() { exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String and Date"); + exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date and Null"); Map payload = new HashMap<>(); payload.put("list", Arrays.asList("item1", new UserPojo("name", 42))); @@ -872,7 +799,7 @@ public void withPayloadShouldNotAllowListWithCustomType() { @Test public void withPayloadShouldNotAllowMapWithCustomType() { exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String and Date"); + exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date and Null"); Map payload = new HashMap<>(); payload.put("entry", "value"); @@ -922,4 +849,75 @@ public void withPayloadShouldAllowNestedSupportedTypes() { assertThat(payloadJson, JsonMatcher.hasEntry("listClaim", listClaim)); assertThat(payloadJson, JsonMatcher.hasEntry("objClaim", mapClaim)); } + + @Test + public void withPayloadShouldSupportNullValuesEverywhere() { + /* + JWT: + { + "listClaim": [ + "answer to ultimate question of life", + 42, + null + ], + "claim": null, + "listNestedClaim": [ + 1, + 2, + { + "nestedObjKey": null + } + ], + "objClaim": { + "nestedObjKey": null, + "objObjKey": { + "nestedObjKey": null, + "objListKey": [ + null, + "nestedList2" + ] + }, + "objListKey": [ + null, + "nestedList2" + ] + } + } + */ + + List listClaim = Arrays.asList("answer to ultimate question of life", 42, null); + List listNestedClaim = Arrays.asList(1, 2, Collections.singletonMap("nestedObjKey", null)); + List objListKey = Arrays.asList(null, "nestedList2"); + HashMap objClaim = new HashMap<>(); + objClaim.put("nestedObjKey", null); + objClaim.put("objListKey", objListKey); + objClaim.put("objObjKey", new HashMap<>(objClaim)); + + + Map payload = new HashMap<>(); + payload.put("claim", null); + payload.put("listClaim", listClaim); + payload.put("listNestedClaim", listNestedClaim); + payload.put("objClaim", objClaim); + + String jwt = JWTCreator.init() + .withPayload(payload) + .withHeader(payload) + .sign(Algorithm.HMAC256("secret")); + + assertThat(jwt, is(notNullValue())); + String[] parts = jwt.split("\\."); + String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); + + assertThat(payloadJson, JsonMatcher.hasEntry("claim", null)); + assertThat(payloadJson, JsonMatcher.hasEntry("listClaim", listClaim)); + assertThat(payloadJson, JsonMatcher.hasEntry("listNestedClaim", listNestedClaim)); + assertThat(payloadJson, JsonMatcher.hasEntry("objClaim", objClaim)); + + assertThat(headerJson, JsonMatcher.hasEntry("claim", null)); + assertThat(headerJson, JsonMatcher.hasEntry("listClaim", listClaim)); + assertThat(headerJson, JsonMatcher.hasEntry("listNestedClaim", listNestedClaim)); + assertThat(headerJson, JsonMatcher.hasEntry("objClaim", objClaim)); + } } diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 32db703e..5ea2b4ef 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -1,7 +1,6 @@ package com.auth0.jwt; import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.impl.NullClaim; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import org.hamcrest.collection.IsCollectionWithSize; @@ -216,7 +215,8 @@ public void shouldGetMissingClaimIfClaimDoesNotExist() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.K17vlwhE8FCMShdl1_65jEYqsQqBOVMPUU9IgG-QlTM"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("notExisting"), is(notNullValue())); - assertThat(jwt.getClaim("notExisting"), is(instanceOf(NullClaim.class))); + assertThat(jwt.getClaim("notExisting").isMissing(), is(true)); + assertThat(jwt.getClaim("notExisting").isNull(), is(false)); } @Test @@ -295,13 +295,28 @@ public void shouldGetCustomArrayClaimOfTypeInteger() { @Test public void shouldGetCustomMapClaim() { - String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjp7InN0cmluZyI6InZhbHVlIiwibnVtYmVyIjoxLCJib29sZWFuIjp0cnVlfX0.-8aIaXd2-rp1lLuDEQmCeisCBX9X_zbqdPn2llGxNoc"; + String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjp7InN0cmluZyI6InZhbHVlIiwibnVtYmVyIjoxLCJib29sZWFuIjp0cnVlLCJlbXB0eSI6bnVsbH19.6xkCuYZnu4RA0xZSxlYSYAqzy9JDWsDtIWqSCUZlPt8"; DecodedJWT jwt = JWT.decode(token); assertThat(jwt, is(notNullValue())); Map map = jwt.getClaim("name").asMap(); assertThat(map, hasEntry("string", "value")); assertThat(map, hasEntry("number", 1)); assertThat(map, hasEntry("boolean", true)); + assertThat(map, hasEntry("empty", null)); + } + + @Test + public void shouldGetCustomNullClaim() { + String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpudWxsfQ.X4ALHe7uYqEcXWFBnwBUNRKwmwrtDEGZ2aynRYYUx8c"; + DecodedJWT jwt = JWT.decode(token); + assertThat(jwt.getClaim("name").isNull(), is(true)); + } + + @Test + public void shouldGetListClaim() { + String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbbnVsbCwiaGVsbG8iXX0.SpcuQRBGdTV0ofHdxBSnhWEUsQi89noZUXin2Thwb70"; + DecodedJWT jwt = JWT.decode(token); + assertThat(jwt.getClaim("name").asList(String.class), contains(null, "hello")); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 1d80d802..7d2123a9 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -1064,4 +1064,47 @@ public void shouldRemovePredicateCheckForNull() { assertThat(verifier.expectedChecks, not(hasKey("claimName"))); } + @Test + public void shouldSuccessfullyVerifyClaimWithNull() { + String jwt = JWTCreator.init() + .withNullClaim("claimName") + .sign(Algorithm.HMAC256("secret")); + + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withNullClaim("claimName") + .build(); + + DecodedJWT decodedJWT = verifier.verify(jwt); + assertThat(decodedJWT, is(notNullValue())); + } + + @Test + public void shouldThrowWhenNullClaimHasValue() { + exception.expect(InvalidClaimException.class); + exception.expectMessage("The Claim 'claimName' value doesn't match the required one."); + + String jwt = JWTCreator.init() + .withClaim("claimName", "value") + .sign(Algorithm.HMAC256("secret")); + + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withNullClaim("claimName") + .build() + .verify(jwt); + } + + @Test + public void shouldThrowWhenNullClaimIsMissing() { + exception.expect(InvalidClaimException.class); + exception.expectMessage("The Claim 'anotherClaimName' value doesn't match the required one."); + + String jwt = JWTCreator.init() + .withClaim("claimName", "value") + .sign(Algorithm.HMAC256("secret")); + + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withNullClaim("anotherClaimName") + .build() + .verify(jwt); + } } diff --git a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java index e3d04c77..c4a04d81 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java @@ -135,6 +135,7 @@ public void shouldGetNotNullExtraClaimIfMissing() { assertThat(header, is(notNullValue())); assertThat(header.getHeaderClaim("missing"), is(notNullValue())); - assertThat(header.getHeaderClaim("missing"), is(instanceOf(NullClaim.class))); + assertThat(header.getHeaderClaim("missing").isMissing(), is(true)); + assertThat(header.getHeaderClaim("missing").isNull(), is(false)); } } \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java index 3c744487..44ef2b9f 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java @@ -331,8 +331,8 @@ public void shouldReturnBaseClaimWhenParsingMissingNode() { Claim claim = claimFromNode(value); assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(NullClaim.class))); - assertThat(claim.isNull(), is(true)); + assertThat(claim.isMissing(), is(true)); + assertThat(claim.isNull(), is(false)); } @Test @@ -341,8 +341,8 @@ public void shouldReturnBaseClaimWhenParsingNullNode() { Claim claim = claimFromNode(value); assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(NullClaim.class))); assertThat(claim.isNull(), is(true)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -351,8 +351,8 @@ public void shouldReturnBaseClaimWhenParsingNullValue() { Claim claim = claimFromNode(value); assertThat(claim, is(notNullValue())); - assertThat(claim, is(instanceOf(NullClaim.class))); assertThat(claim.isNull(), is(true)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -363,6 +363,7 @@ public void shouldReturnNonNullClaimWhenParsingObject() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -373,6 +374,7 @@ public void shouldReturnNonNullClaimWhenParsingArray() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -383,6 +385,7 @@ public void shouldReturnNonNullClaimWhenParsingList() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -393,6 +396,7 @@ public void shouldReturnNonNullClaimWhenParsingStringValue() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -403,6 +407,7 @@ public void shouldReturnNonNullClaimWhenParsingIntValue() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -413,6 +418,7 @@ public void shouldReturnNonNullClaimWhenParsingDoubleValue() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -423,6 +429,7 @@ public void shouldReturnNonNullClaimWhenParsingDateValue() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -433,6 +440,18 @@ public void shouldReturnNonNullClaimWhenParsingBooleanValue() { assertThat(claim, is(notNullValue())); assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); + assertThat(claim.isMissing(), is(false)); + } + + @Test + public void shouldReturnNullIsTrue() { + JsonNode value = mapper.valueToTree(null); + Claim claim = claimFromNode(value); + + assertThat(claim, is(notNullValue())); + assertThat(claim, is(instanceOf(JsonNodeClaim.class))); + assertThat(claim.isNull(), is(true)); + assertThat(claim.isMissing(), is(false)); } @Test @@ -441,4 +460,22 @@ public void shouldDelegateToJsonNodeToString() { Claim claim = claimFromNode(value); assertThat(claim.toString(), is(value.toString())); } + + @Test + public void shouldConvertToString() { + JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); + JsonNode nullValue = mapper.valueToTree(null); + JsonNode missingValue = MissingNode.getInstance(); + + Claim claim = claimFromNode(value); + Claim nullClaim = claimFromNode(nullValue); + Claim missingClaim = claimFromNode(missingValue); + + assertThat(claim.toString(), is("{\"name\":\"john\",\"id\":123}")); + assertThat(nullClaim.isNull(), is(true)); + assertThat(nullClaim.toString(), is("Null claim")); + assertThat(missingClaim.isMissing(), is(true)); + assertThat(missingClaim.toString(), is("Missing claim")); + + } } \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java deleted file mode 100644 index bd478130..00000000 --- a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.auth0.jwt.impl; - -import org.junit.Before; -import org.junit.Test; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class NullClaimTest { - private NullClaim claim; - - @Before - public void setUp() { - claim = new NullClaim(); - } - - @Test - public void shouldBeNull() { - assertThat(claim.isNull(), is(true)); - } - - @Test - public void shouldGetAsBoolean() { - assertThat(claim.asBoolean(), is(nullValue())); - } - - @Test - public void shouldGetAsInt() { - assertThat(claim.asInt(), is(nullValue())); - } - - @Test - public void shouldGetAsLong() { - assertThat(claim.asLong(), is(nullValue())); - } - - @Test - public void shouldGetAsDouble() { - assertThat(claim.asDouble(), is(nullValue())); - } - - @Test - public void shouldGetAsString() { - assertThat(claim.asString(), is(nullValue())); - } - - @Test - public void shouldGetAsDate() { - assertThat(claim.asDate(), is(nullValue())); - } - - @Test - public void shouldGetAsInstant() { - assertThat(claim.asInstant(), is(nullValue())); - } - - @Test - public void shouldGetAsArray() { - assertThat(claim.asArray(Object.class), is(nullValue())); - } - - @Test - public void shouldGetAsList() { - assertThat(claim.asList(Object.class), is(nullValue())); - } - - @Test - public void shouldGetAsMap() { - assertThat(claim.asMap(), is(nullValue())); - } - - @Test - public void shouldGetAsCustomClass() { - assertThat(claim.as(Object.class), is(nullValue())); - } - - @Test - public void shouldHaveToString() { - assertThat(claim.toString(), is("Null Claim")); - } -} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java index 9e2e6902..da0c880e 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java @@ -166,7 +166,8 @@ public void shouldGetNotNullExtraClaimIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getClaim("missing"), is(notNullValue())); - assertThat(payload.getClaim("missing"), is(instanceOf(NullClaim.class))); + assertThat(payload.getClaim("missing").isMissing(), is(true)); + assertThat(payload.getClaim("missing").isNull(), is(false)); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java index 77d573bc..61541ccf 100644 --- a/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/interfaces/ClaimTest.java @@ -40,6 +40,11 @@ public boolean isNull() { return false; } + @Override + public boolean isMissing() { + return false; + } + @Override public Boolean asBoolean() { return null; diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java index c7f89763..fb0c74a9 100644 --- a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java +++ b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java @@ -104,6 +104,11 @@ public Verification withClaimPresence(String name) throws IllegalArgumentExcepti return null; } + @Override + public Verification withNullClaim(String name) throws IllegalArgumentException { + return null; + } + @Override public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { return null; From 67df3d476024cbe697b3a54893f5383945c7670d Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 29 Mar 2022 13:08:11 +0530 Subject: [PATCH 020/134] [SDK-3154] Improved Exception Handling (#568) * Improved exception handling * Fixed issues thrown by Linter * Fixed Lint Issue (Missing Period) * Improved Code Coverage --- .../main/java/com/auth0/jwt/JWTVerifier.java | 85 ++++++---- .../exceptions/IncorrectClaimException.java | 44 +++++ .../jwt/exceptions/InvalidClaimException.java | 2 +- .../jwt/exceptions/MissingClaimException.java | 23 +++ .../jwt/exceptions/TokenExpiredException.java | 11 +- .../com/auth0/jwt/impl/JsonNodeClaim.java | 3 +- .../java/com/auth0/jwt/JWTVerifierTest.java | 159 ++++++++++++++---- .../com/auth0/jwt/impl/JsonNodeClaimTest.java | 43 +++++ .../auth0/jwt/matchers/CustomMatchers.java | 114 +++++++++++++ 9 files changed, 410 insertions(+), 74 deletions(-) create mode 100644 lib/src/main/java/com/auth0/jwt/exceptions/IncorrectClaimException.java create mode 100644 lib/src/main/java/com/auth0/jwt/exceptions/MissingClaimException.java create mode 100644 lib/src/test/java/com/auth0/jwt/matchers/CustomMatchers.java diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 947c9e25..ba19feb9 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -72,7 +72,8 @@ public Verification withIssuer(String... issuer) { List value = isNullOrEmpty(issuer) ? null : Arrays.asList(issuer); checkIfNeedToRemove(PublicClaims.ISSUER, value, ((claim, decodedJWT) -> { if (value == null || !value.contains(claim.asString())) { - throw new InvalidClaimException("The Claim 'iss' value doesn't match the required issuer."); + throw new IncorrectClaimException( + "The Claim 'iss' value doesn't match the required issuer.", PublicClaims.ISSUER, claim); } return true; })); @@ -89,7 +90,7 @@ public Verification withSubject(String subject) { public Verification withAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); checkIfNeedToRemove(PublicClaims.AUDIENCE, value, ((claim, decodedJWT) -> - assertValidAudienceClaim(decodedJWT.getAudience(), value, true))); + assertValidAudienceClaim(claim, decodedJWT.getAudience(), value, true))); return this; } @@ -97,7 +98,7 @@ public Verification withAudience(String... audience) { public Verification withAnyOfAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); checkIfNeedToRemove(PublicClaims.AUDIENCE, value, ((claim, decodedJWT) -> - assertValidAudienceClaim(decodedJWT.getAudience(), value, false))); + assertValidAudienceClaim(claim, decodedJWT.getAudience(), value, false))); return this; } @@ -144,12 +145,7 @@ public Verification withJWTId(String jwtId) { @Override public Verification withClaimPresence(String name) throws IllegalArgumentException { assertNonNull(name); - withClaim(name, ((claim, decodedJWT) -> { - if (claim.isMissing()) { - throw new InvalidClaimException(String.format("The Claim '%s' is not present in the JWT.", name)); - } - return true; - })); + withClaim(name, ((claim, decodedJWT) -> assertClaimPresence(name, claim))); return this; } @@ -272,13 +268,13 @@ private void addMandatoryClaimChecks() { long notBeforeLeeway = getLeewayFor(PublicClaims.NOT_BEFORE); long issuedAtLeeway = getLeewayFor(PublicClaims.ISSUED_AT); - checkIfNeedToRemove(PublicClaims.EXPIRES_AT, expiresAtLeeway, ((claim, decodedJWT) -> - assertValidInstantClaim(claim.asInstant(), expiresAtLeeway, true))); - checkIfNeedToRemove(PublicClaims.NOT_BEFORE, notBeforeLeeway, ((claim, decodedJWT) -> - assertValidInstantClaim(claim.asInstant(), notBeforeLeeway, false))); + expectedChecks.put(PublicClaims.EXPIRES_AT, (claim, decodedJWT) -> + assertValidInstantClaim(PublicClaims.EXPIRES_AT, claim, expiresAtLeeway, true)); + expectedChecks.put(PublicClaims.NOT_BEFORE, (claim, decodedJWT) -> + assertValidInstantClaim(PublicClaims.NOT_BEFORE, claim, notBeforeLeeway, false)); if (!ignoreIssuedAt) { - checkIfNeedToRemove(PublicClaims.ISSUED_AT, issuedAtLeeway, ((claim, decodedJWT) -> - assertValidInstantClaim(claim.asInstant(), issuedAtLeeway, false))); + expectedChecks.put(PublicClaims.ISSUED_AT, (claim, decodedJWT) -> + assertValidInstantClaim(PublicClaims.ISSUED_AT, claim, issuedAtLeeway, false)); } } @@ -305,33 +301,50 @@ private boolean assertValidCollectionClaim(Claim claim, Object[] expectedClaimVa return claimArr.containsAll(valueArr); } - private boolean assertValidInstantClaim(Instant claimVal, long leeway, boolean shouldBeFuture) { + private boolean assertValidInstantClaim(String claimName, Claim claim, long leeway, boolean shouldBeFuture) { + Instant claimVal = claim.asInstant(); Instant now = clock.instant().truncatedTo(ChronoUnit.SECONDS); + boolean isValid; if (shouldBeFuture) { - return assertInstantIsFuture(claimVal, leeway, now); + isValid = assertInstantIsFuture(claimVal, leeway, now); + if (!isValid) { + throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal), claimVal); + } } else { - return assertInstantIsPast(claimVal, leeway, now); + isValid = assertInstantIsPast(claimVal, leeway, now); + if (!isValid) { + throw new IncorrectClaimException( + String.format("The Token can't be used before %s.", claimVal), claimName, claim); + } } + return true; } private boolean assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { - if (claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)) { - throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal)); - } - return true; + return !(claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)); } private boolean assertInstantIsPast(Instant claimVal, long leeway, Instant now) { - if (claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)) { - throw new InvalidClaimException(String.format("The Token can't be used before %s.", claimVal)); - } - return true; + return !(claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)); } - private boolean assertValidAudienceClaim(List audience, List values, boolean shouldContainAll) { + private boolean assertValidAudienceClaim( + Claim claim, + List audience, + List values, + boolean shouldContainAll + ) { if (audience == null || (shouldContainAll && !audience.containsAll(values)) || (!shouldContainAll && Collections.disjoint(audience, values))) { - throw new InvalidClaimException("The Claim 'aud' value doesn't contain the required audience."); + throw new IncorrectClaimException( + "The Claim 'aud' value doesn't contain the required audience.", PublicClaims.AUDIENCE, claim); + } + return true; + } + + private boolean assertClaimPresence(String name, Claim claim) { + if (claim.isMissing()) { + throw new MissingClaimException(name); } return true; } @@ -353,7 +366,8 @@ private void checkIfNeedToRemove(String name, Object value, BiPredicate assertClaimPresence(name, claim) + && predicate.test(claim, decodedJWT)); } private boolean isNullOrEmpty(String[] args) { @@ -381,7 +395,8 @@ private boolean isNullOrEmpty(String[] args) { * the one defined in the {@link JWTVerifier}. * @throws SignatureVerificationException if the signature is invalid. * @throws TokenExpiredException if the token has expired. - * @throws InvalidClaimException if a claim contained a different value than the expected one. + * @throws MissingClaimException if a claim to be verified is missing. + * @throws IncorrectClaimException if a claim contained a different value than the expected one. */ @Override public DecodedJWT verify(String token) throws JWTVerificationException { @@ -398,7 +413,8 @@ public DecodedJWT verify(String token) throws JWTVerificationException { * the one defined in the {@link JWTVerifier}. * @throws SignatureVerificationException if the signature is invalid. * @throws TokenExpiredException if the token has expired. - * @throws InvalidClaimException if a claim contained a different value than the expected one. + * @throws MissingClaimException if a claim to be verified is missing. + * @throws IncorrectClaimException if a claim contained a different value than the expected one. */ @Override public DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException { @@ -426,8 +442,11 @@ private void verifyClaims(DecodedJWT jwt, Map hasMissingClaimName(final String claimName) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("MissingClaimException with claim name: "+claimName); + } + + @Override + protected boolean matchesSafely(MissingClaimException item) { + return item.getClaimName().equals(claimName); + } + }; + } + + public static Matcher hasTokenExpiredOn(final Instant instant) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("TokenExpiredException with expired time as: "+instant.getEpochSecond()); + } + + @Override + protected boolean matchesSafely(TokenExpiredException item) { + return item.getExpiredOn().equals(instant); + } + }; + } + + public static Matcher hasClaimName(final String claimName) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("IncorrectClaimException with claim name: "+claimName); + } + + @Override + protected boolean matchesSafely(IncorrectClaimException item) { + return item.getClaimName().equals(claimName); + } + }; + } + + public static Matcher hasClaimValue(final Object value, final Class clazz) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("IncorrectClaimException with claim : "+value); + } + + @Override + protected boolean matchesSafely(IncorrectClaimException item) { + return item.getClaimValue().as(clazz).equals(value); + } + }; + } + + public static Matcher hasClaimInstant(final Instant value, final Class clazz) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("IncorrectClaimException with claim : "+value); + } + + @Override + protected boolean matchesSafely(IncorrectClaimException item) { + return item.getClaimValue().as(clazz).equals(value); + } + }; + } + + public static Matcher hasClaimValueArray(final Object value, final Class clazz) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("IncorrectClaimException with claim : "+value); + } + + @Override + protected boolean matchesSafely(IncorrectClaimException item) { + return Arrays.equals((Object[]) item.getClaimValue().as(clazz), (Object[])value); + } + }; + } + + public static Matcher hasNullClaim() { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("IncorrectClaimException with claim as null"); + } + + @Override + protected boolean matchesSafely(IncorrectClaimException item) { + boolean a = item.getClaimValue().isNull(); + String b = item.getClaimValue().toString(); + return item.getClaimValue().isNull(); + } + }; + } +} From ed58ef33d1ed800b84678acee2cab172684198d1 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 1 Apr 2022 15:35:37 +0530 Subject: [PATCH 021/134] Improved README structure --- README.md | 193 +++++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 0f847cca..fb489d9b 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,29 @@ If you're looking for an **Android** version of the JWT Decoder take a look at o > This library requires Java 8 or higher. The last version that supported Java 7 was 3.11.0. +## Table of Contents +- [**Installation**](#installation) +- [**Available Algorithms**](#available-algorithms) +- [**Quickstart**](#quickstart) + + [**Create and Sign a Token**](#create-and-sign-a-token) + + [**Verify a Token**](#verify-a-token) + + [**Decode a Token**](#decode-a-token) +- [**Usage**](#usage) + + [**Pick the algorithm**](#pick-the-algorithm) + + [**Time Validation**](#time-validation) + + [**Header Claims**](#header-claims) + + [**Payload Claims**](#payload-claims) + + [**Claim Class**](#claim-class) +- [**Javadoc**](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html) + ## Installation -The library is available on both Maven Central and Bintray, and the Javadoc is published [here](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html). - +### Gradle + +```gradle +implementation 'com.auth0:java-jwt:3.19.0' +``` + ### Maven ```xml @@ -27,12 +46,6 @@ The library is available on both Maven Central and Bintray, and the Javadoc is p ``` -### Gradle - -```gradle -implementation 'com.auth0:java-jwt:3.19.0' -``` - ## Available Algorithms The library implements JWT Verification and Signing using the following algorithms: @@ -49,73 +62,9 @@ The library implements JWT Verification and Signing using the following algorith | ES384 | ECDSA384 | ECDSA with curve P-384 and SHA-384 | | ES512 | ECDSA512 | ECDSA with curve P-521 and SHA-512 | -⚠️ Note - ECDSA with curve secp256k1 and SHA-256 will not be supported for Java 15+ by this library since it has been (disabled in Java 15)[https://www.oracle.com/java/technologies/javase/15-relnote-issues.html#JDK-8237219] - -## Usage - -### Pick the Algorithm - -The Algorithm defines how a token is signed and verified. It can be instantiated with the raw value of the secret in the case of HMAC algorithms, or the key pairs or `KeyProvider` in the case of RSA and ECDSA algorithms. Once created, the instance is reusable for token signing and verification operations. - -When using RSA or ECDSA algorithms and you just need to **sign** JWTs you can avoid specifying a Public Key by passing a `null` value. The same can be done with the Private Key when you just need to **verify** JWTs. - - -#### Using static secrets or keys: - -```java -//HMAC -Algorithm algorithmHS = Algorithm.HMAC256("secret"); - -//RSA -RSAPublicKey publicKey = //Get the key instance -RSAPrivateKey privateKey = //Get the key instance -Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); -``` - -> Note: How you obtain or read keys is not in the scope of this library. For an example of how you might implement this, see [this gist](https://gist.github.com/lbalmaceda/9a0c7890c2965826c04119dcfb1a5469). - -##### HMAC Key Length and Security - -When using a Hash-based Message Authenticaton Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recomendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. - -#### Using a KeyProvider: - -By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: - -- `getPublicKeyById(String kid)`: Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. [JWK](https://tools.ietf.org/html/rfc7517) it can fetch the correct rotation key using the id. (Or just return the same key all the time). -- `getPrivateKey()`: Its called during token signing and it should return the key that will be used to sign the JWT. -- `getPrivateKeyId()`: Its called during token signing and it should return the id of the key that identifies the one returned by `getPrivateKey()`. This value is preferred over the one set in the `JWTCreator.Builder#withKeyId(String)` method. If you don't need to set a `kid` value avoid instantiating an Algorithm using a `KeyProvider`. - - -The following example shows how this would work with `JwkStore`, an imaginary [JWK Set](https://auth0.com/docs/jwks) implementation. For simple key rotation using JWKS, try the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. - -```java -final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}"); -final RSAPrivateKey privateKey = //Get the key instance -final String privateKeyId = //Create an Id for the above key +> Note - Support for ECDSA with curve secp256k1 and SHA-256 (ES256K) has been dropped since it has been [disabled in Java 15](https://www.oracle.com/java/technologies/javase/15-relnote-issues.html#JDK-8237219) -RSAKeyProvider keyProvider = new RSAKeyProvider() { - @Override - public RSAPublicKey getPublicKeyById(String kid) { - //Received 'kid' value might be null if it wasn't defined in the Token's header - RSAPublicKey publicKey = jwkStore.get(kid); - return (RSAPublicKey) publicKey; - } - - @Override - public RSAPrivateKey getPrivateKey() { - return privateKey; - } - - @Override - public String getPrivateKeyId() { - return privateKeyId; - } -}; - -Algorithm algorithm = Algorithm.RSA256(keyProvider); -//Use the Algorithm to create and verify JWTs. -``` +## Quickstart ### Create and Sign a Token @@ -151,7 +100,6 @@ You'll first need to create a `JWTCreator` instance by calling `JWT.create()`. U If a Claim couldn't be converted to JSON or the Key used in the signing process was invalid a `JWTCreationException` will raise. - ### Verify a Token You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` and passing the `Algorithm` instance. If you require the token to have specific Claim values, use the builder to define them. The instance returned by the method `build()` is reusable, so you can define it once and use it to verify different tokens. Finally call `verifier.verify()` passing the token. @@ -190,8 +138,87 @@ You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` If the token has an invalid signature or the Claim requirement is not met, a `JWTVerificationException` will raise. +### Decode a Token -#### Time Validation +```java +String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; +try { + DecodedJWT jwt = JWT.decode(token); +} catch (JWTDecodeException exception){ + //Invalid token +} +``` + +If the token has an invalid syntax or the header or payload are not JSONs, a `JWTDecodeException` will raise. + +## Usage + +### Pick the Algorithm + +The Algorithm defines how a token is signed and verified. It can be instantiated with the raw value of the secret in the case of HMAC algorithms, or the key pairs or `KeyProvider` in the case of RSA and ECDSA algorithms. Once created, the instance is reusable for token signing and verification operations. + +When using RSA or ECDSA algorithms and you just need to **sign** JWTs you can avoid specifying a Public Key by passing a `null` value. The same can be done with the Private Key when you just need to **verify** JWTs. + + +#### Using static secrets or keys: + +```java +//HMAC +Algorithm algorithmHS = Algorithm.HMAC256("secret"); + +//RSA +RSAPublicKey publicKey = //Get the key instance +RSAPrivateKey privateKey = //Get the key instance +Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); +``` + +> Note: How you obtain or read keys is not in the scope of this library. For an example of how you might implement this, see [this gist](https://gist.github.com/lbalmaceda/9a0c7890c2965826c04119dcfb1a5469). + +##### HMAC Key Length and Security + +When using a Hash-based Message Authenticaton Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recomendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. + +#### Using a KeyProvider: +//todo need to be updated +By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: + +- `getPublicKeyById(String kid)`: Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. [JWK](https://tools.ietf.org/html/rfc7517) it can fetch the correct rotation key using the id. (Or just return the same key all the time). +- `getPrivateKey()`: Its called during token signing and it should return the key that will be used to sign the JWT. +- `getPrivateKeyId()`: Its called during token signing and it should return the id of the key that identifies the one returned by `getPrivateKey()`. This value is preferred over the one set in the `JWTCreator.Builder#withKeyId(String)` method. If you don't need to set a `kid` value avoid instantiating an Algorithm using a `KeyProvider`. + + +The following example shows how this would work with `JwkStore`, an imaginary [JWK Set](https://auth0.com/docs/jwks) implementation. For simple key rotation using JWKS, try the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. + +```java +final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}"); +final RSAPrivateKey privateKey = //Get the key instance +final String privateKeyId = //Create an Id for the above key + +RSAKeyProvider keyProvider = new RSAKeyProvider() { + @Override + public RSAPublicKey getPublicKeyById(String kid) { + //Received 'kid' value might be null if it wasn't defined in the Token's header + RSAPublicKey publicKey = jwkStore.get(kid); + return (RSAPublicKey) publicKey; + } + + @Override + public RSAPrivateKey getPrivateKey() { + return privateKey; + } + + @Override + public String getPrivateKeyId() { + return privateKeyId; + } +}; + +Algorithm algorithm = Algorithm.RSA256(keyProvider); +//Use the Algorithm to create and verify JWTs. +``` + + +### Time Validation The JWT token may include DateNumber fields that can be used to validate that: * The token was issued in a past date `"iat" < TODAY` @@ -227,20 +254,6 @@ Clock clock = new CustomClock(); //Must implement Clock interface JWTVerifier verifier = verification.build(clock); ``` -### Decode a Token - -```java -String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; -try { - DecodedJWT jwt = JWT.decode(token); -} catch (JWTDecodeException exception){ - //Invalid token -} -``` - -If the token has an invalid syntax or the header or payload are not JSONs, a `JWTDecodeException` will raise. - - ### Header Claims #### Algorithm ("alg") From c1942944b3b906d749128279808ad86cd24b8b9f Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 12 Apr 2022 18:55:31 +0530 Subject: [PATCH 022/134] Add README instructions for new APIs --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb489d9b..065899f1 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,6 @@ Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); When using a Hash-based Message Authenticaton Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recomendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. #### Using a KeyProvider: -//todo need to be updated By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: - `getPublicKeyById(String kid)`: Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. [JWK](https://tools.ietf.org/html/rfc7517) it can fetch the correct rotation key using the id. (Or just return the same key all the time). @@ -388,6 +387,7 @@ When creating a Token with the `JWT.create()` you can specify a custom Claim by String token = JWT.create() .withClaim("name", 123) .withArrayClaim("array", new Integer[]{1, 2, 3}) + .withNullClaim("claim_name") .sign(algorithm); ``` @@ -407,6 +407,9 @@ You can also verify custom Claims on the `JWT.require()` by calling `withClaim() JWTVerifier verifier = JWT.require(algorithm) .withClaim("name", 123) .withArrayClaim("array", 1, 2, 3) + .withNullClaim("null_value") //checks if the claim name provided has null value + .withClaimPresence("claim_presence") //checks if the claim name provided is in the payload + .withClaim("predicate", (claim, decodedJWT) -> "custom_check".equals(claim.asString())) //can be used to run custom verification .build(); DecodedJWT jwt = verifier.verify("my.jwt.token"); ``` @@ -423,7 +426,10 @@ The Claim class is a wrapper for the Claim values. It allows you to get the Clai * **asDouble()**: Returns the Double value or null if it can't be converted. * **asLong()**: Returns the Long value or null if it can't be converted. * **asString()**: Returns the String value or null if it can't be converted. -* **asDate()**: Returns the Date value or null if it can't be converted. This must be a NumericDate (Unix Epoch/Timestamp). Note that the [JWT Standard](https://tools.ietf.org/html/rfc7519#section-2) specified that all the *NumericDate* values must be in seconds. +* **asInstant()**: Returns the Instant value or null if it can't be converted. +* **asDate()**: Returns the Date value or null if it can't be converted. + +> For `asInstant()` and `asDate()` the value must be a NumericDate (Unix Epoch/Timestamp). Note that the [JWT Standard](https://tools.ietf.org/html/rfc7519#section-2) specified that all the *NumericDate* values must be in seconds. #### Custom Classes and Collections To obtain a Claim as a Collection you'll need to provide the **Class Type** of the contents to convert from. From 0f8a9bf20f215f9cdb78c50d7edbfe9d811cfdbc Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 12 Apr 2022 19:18:46 +0530 Subject: [PATCH 023/134] Replace expected exception with assertThrows (#572) * Replace expected exception with assertThrows --- .../java/com/auth0/jwt/JWTVerifierTest.java | 550 +++++++++--------- .../auth0/jwt/matchers/CustomMatchers.java | 114 ---- 2 files changed, 275 insertions(+), 389 deletions(-) delete mode 100644 lib/src/test/java/com/auth0/jwt/matchers/CustomMatchers.java diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 1cf79c8f..9dcb2cb1 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -19,9 +19,9 @@ import java.util.Date; import java.util.function.BiPredicate; -import static com.auth0.jwt.matchers.CustomMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.mock; public class JWTVerifierTest { @@ -35,17 +35,18 @@ public class JWTVerifierTest { @Test public void shouldThrowWhenInitializedWithoutAlgorithm() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("The Algorithm cannot be null"); - JWTVerifier.init(null); + IllegalArgumentException e = assertThrows(null, IllegalArgumentException.class, () -> + JWTVerifier.init(null)); + assertThat(e.getMessage(), is("The Algorithm cannot be null.")); } @Test public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() { - exception.expect(AlgorithmMismatchException.class); - exception.expectMessage("The provided Algorithm doesn't match the one defined in the JWT's Header."); - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC512("secret")).build(); - verifier.verify("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho"); + AlgorithmMismatchException e = assertThrows(null, AlgorithmMismatchException.class, () -> { + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC512("secret")).build(); + verifier.verify("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.s69x7Mmu4JqwmdxiK6sesALO7tcedbFsKEEITUxw9ho"); + }); + assertThat(e.getMessage(), is("The provided Algorithm doesn't match the one defined in the JWT's Header.")); } @Test @@ -73,45 +74,45 @@ public void shouldValidateMultipleIssuers() { @Test public void shouldThrowOnInvalidIssuer() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'iss' value doesn't match the required issuer."); - exception.expect(hasClaimName(PublicClaims.ISSUER)); - exception.expect(hasClaimValue("auth0", String.class)); - - String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("invalid") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withIssuer("invalid") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); + assertThat(e.getClaimName(), is(PublicClaims.ISSUER)); + assertThat(e.getClaimValue().asString(), is("auth0")); } @Test public void shouldThrowOnNullIssuer() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'iss' value doesn't match the required issuer."); - exception.expect(hasClaimName(PublicClaims.ISSUER)); - exception.expect(hasNullClaim()); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOm51bGx9.OoiCLipSfflWxkFX2rytvtwEiJ8eAL0opkdXY_ap0qA"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("auth0") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOm51bGx9.OoiCLipSfflWxkFX2rytvtwEiJ8eAL0opkdXY_ap0qA"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withIssuer("auth0") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); + assertThat(e.getClaimName(), is(PublicClaims.ISSUER)); + assertThat(e.getClaimValue().isNull(), is(true)); } @Test public void shouldThrowOnMissingIssuer() { - exception.expect(MissingClaimException.class); - exception.expectMessage("The Claim 'iss' is not present in the JWT."); - exception.expect(hasMissingClaimName("iss")); - - String jwt = JWTCreator.init() - .sign(Algorithm.HMAC256("secret")); + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String jwt = JWTCreator.init() + .sign(Algorithm.HMAC256("secret")); - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withIssuer("nope") - .build() - .verify(jwt); + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withIssuer("nope") + .build() + .verify(jwt); + }); + assertThat(e.getMessage(), is("The Claim 'iss' is not present in the JWT.")); + assertThat(e.getClaimName(), is("iss")); } @Test @@ -127,16 +128,16 @@ public void shouldValidateSubject() { @Test public void shouldThrowOnInvalidSubject() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'sub' value doesn't match the required one."); - exception.expect(hasClaimName(PublicClaims.SUBJECT)); - exception.expect(hasClaimValue("1234567890", String.class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withSubject("invalid") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withSubject("invalid") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'sub' value doesn't match the required one.")); + assertThat(e.getClaimName(), is(PublicClaims.SUBJECT)); + assertThat(e.getClaimValue().asString(), is("1234567890")); } @Test @@ -230,76 +231,75 @@ public void shouldAcceptAudienceWhenAnyOfAudienceAndAllContained() { @Test public void shouldThrowWhenAudienceHasNoneOfExpectedAnyOfAudience() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); - exception.expect(hasClaimName(PublicClaims.AUDIENCE)); - exception.expect(hasClaimValueArray(new String[] {"Mark","David","John"}, String[].class)); - - // Token 'aud' = ["Mark", "David", "John"] - String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAnyOfAudience("Joe", "Jim") - .build() - .verify(tokenArr); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + // Token 'aud' = ["Mark", "David", "John"] + String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAnyOfAudience("Joe", "Jim") + .build() + .verify(tokenArr); + }); + assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); + assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); } @Test public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); - exception.expect(hasClaimName(PublicClaims.AUDIENCE)); - exception.expect(hasClaimValueArray(new String[] {"Mark","David","John"}, String[].class)); - - // Token 'aud' = ["Mark", "David", "John"] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("Mark", "Joe") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + // Token 'aud' = ["Mark", "David", "John"] + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAudience("Mark", "Joe") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); + assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); } @Test public void shouldThrowWhenAudienceClaimIsNull() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); - exception.expect(hasClaimName(PublicClaims.AUDIENCE)); - exception.expect(hasNullClaim()); - - // Token 'aud': null - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("nope") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + // Token 'aud': null + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAudience("nope") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); + assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimValue().isNull(), is(true)); } @Test public void shouldThrowWhenAudienceClaimIsMissing(){ - exception.expect(MissingClaimException.class); - exception.expectMessage("The Claim 'aud' is not present in the JWT."); - exception.expect(hasMissingClaimName("aud")); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAudience("nope") - .build() - .verify(token); + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAudience("nope") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'aud' is not present in the JWT.")); + assertThat(e.getClaimName(), is("aud")); } @Test public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); - exception.expect(hasClaimName(PublicClaims.AUDIENCE)); - exception.expect(hasClaimValueArray(new String[] {null}, String[].class)); - - // Token 'aud': [null] - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpbbnVsbF19.2cBf7FbkX52h8Vmjnl1DY1PYe_J_YP0KsyeoeYmuca8"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withAnyOfAudience("nope") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + // Token 'aud': [null] + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpbbnVsbF19.2cBf7FbkX52h8Vmjnl1DY1PYe_J_YP0KsyeoeYmuca8"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAnyOfAudience("nope") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); + assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {null})); } @Test @@ -384,113 +384,113 @@ public void shouldThrowOnNullCustomClaimName() { @Test public void shouldThrowWhenExpectedArrayClaimIsMissing() { - exception.expect(MissingClaimException.class); - exception.expectMessage("The Claim 'missing' is not present in the JWT."); - exception.expect(hasMissingClaimName("missing")); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcnJheSI6WzEsMiwzXX0.wKNFBcMdwIpdF9rXRxvexrzSM6umgSFqRO1WZj992YM"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withArrayClaim("missing", 1, 2, 3) - .build() - .verify(token); + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcnJheSI6WzEsMiwzXX0.wKNFBcMdwIpdF9rXRxvexrzSM6umgSFqRO1WZj992YM"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withArrayClaim("missing", 1, 2, 3) + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'missing' is not present in the JWT.")); + assertThat(e.getClaimName(), is("missing")); } @Test public void shouldThrowWhenExpectedClaimIsMissing() { - exception.expect(MissingClaimException.class); - exception.expectMessage("The Claim 'missing' is not present in the JWT."); - exception.expect(hasMissingClaimName("missing")); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbSI6InRleHQifQ.aZ27Ze35VvTqxpaSIK5ZcnYHr4SrvANlUbDR8fw9qsQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("missing", "text") - .build() - .verify(token); + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbSI6InRleHQifQ.aZ27Ze35VvTqxpaSIK5ZcnYHr4SrvANlUbDR8fw9qsQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("missing", "text") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'missing' is not present in the JWT.")); + assertThat(e.getClaimName(), is("missing")); } @Test public void shouldThrowOnInvalidCustomClaimValueOfTypeString() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'name' value doesn't match the required one."); - exception.expect(hasClaimName("name")); - exception.expect(hasClaimValueArray(new String[] {"something"}, String[].class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", "value") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", "value") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("name")); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); } @Test public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'name' value doesn't match the required one."); - exception.expect(hasClaimName("name")); - exception.expect(hasClaimValueArray(new String[] {"something"}, String[].class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 123) - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", 123) + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("name")); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); } @Test public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'name' value doesn't match the required one."); - exception.expect(hasClaimName("name")); - exception.expect(hasClaimValueArray(new String[] {"something"}, String[].class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", 23.45) - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", 23.45) + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("name")); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); } @Test public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'name' value doesn't match the required one."); - exception.expect(hasClaimName("name")); - exception.expect(hasClaimValueArray(new String[] {"something"}, String[].class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", true) - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", true) + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("name")); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); } @Test public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'name' value doesn't match the required one."); - exception.expect(hasClaimName("name")); - exception.expect(hasClaimValueArray(new String[] {"something"}, String[].class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", new Date()) - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", new Date()) + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("name")); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); } @Test public void shouldThrowOnInvalidCustomClaimValue() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'name' value doesn't match the required one."); - exception.expect(hasClaimName("name")); - exception.expect(hasClaimValueArray(new String[] {"something"}, String[].class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", "check") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", "check") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'name' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("name")); + assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"something"})); } @Test @@ -734,15 +734,15 @@ public void shouldValidateExpiresAtIfPresent() { @Test public void shouldThrowOnInvalidExpiresAtIfPresent() { - exception.expect(TokenExpiredException.class); - exception.expectMessage(startsWith("The Token has expired on")); - exception.expect(hasTokenExpiredOn(Instant.ofEpochSecond(1477592L))); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockOneSecondLater) - .verify(token); + TokenExpiredException e = assertThrows(null, TokenExpiredException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(mockOneSecondLater) + .verify(token); + }); + assertThat(e.getMessage(), is("The Token has expired on 1970-01-18T02:26:32Z.")); + assertThat(e.getExpiredOn(), is(Instant.ofEpochSecond(1477592L))); } @Test @@ -769,16 +769,16 @@ public void shouldValidateNotBeforeWithLeeway() { @Test public void shouldThrowOnInvalidNotBeforeIfPresent() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Token can't be used before 1970-01-18T02:26:32Z."); - exception.expect(hasClaimName(PublicClaims.NOT_BEFORE)); - exception.expect(hasClaimValue(1477592L, Long.class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockOneSecondEarlier) - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(mockOneSecondEarlier) + .verify(token); + }); + assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); + assertThat(e.getClaimName(), is(PublicClaims.NOT_BEFORE)); + assertThat(e.getClaimValue().asLong(), is(1477592L)); } @Test @@ -804,16 +804,16 @@ public void shouldThrowOnNegativeNotBeforeLeeway() { // Issued At with future date @Test public void shouldThrowOnFutureIssuedAt() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Token can't be used before 1970-01-18T02:26:32Z."); - exception.expect(hasClaimName(PublicClaims.ISSUED_AT)); - exception.expect(hasClaimValue(1477592L, Long.class)); - - String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - DecodedJWT jwt = verification.build(mockOneSecondEarlier).verify(token); - assertThat(jwt, is(notNullValue())); + DecodedJWT jwt = verification.build(mockOneSecondEarlier).verify(token); + assertThat(jwt, is(notNullValue())); + }); + assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); + assertThat(e.getClaimName(), is(PublicClaims.ISSUED_AT)); + assertThat(e.getClaimValue().asLong(), is(1477592L)); } // Issued At with future date and ignore flag @@ -829,16 +829,16 @@ public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() { @Test public void shouldThrowOnInvalidIssuedAtIfPresent() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Token can't be used before 1970-01-18T02:26:32Z."); - exception.expect(hasClaimName(PublicClaims.ISSUED_AT)); - exception.expect(hasClaimValue(1477592L, Long.class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - verification - .build(mockOneSecondEarlier) - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(mockOneSecondEarlier) + .verify(token); + }); + assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); + assertThat(e.getClaimName(), is(PublicClaims.ISSUED_AT)); + assertThat(e.getClaimValue().asLong(), is(1477592L)); } @Test @@ -887,16 +887,16 @@ public void shouldValidateJWTId() { @Test public void shouldThrowOnInvalidJWTId() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'jti' value doesn't match the required one."); - exception.expect(hasClaimName("jti")); - exception.expect(hasClaimValue("jwt_id_123", String.class)); - - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withJWTId("invalid") - .build() - .verify(token); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withJWTId("invalid") + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'jti' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("jti")); + assertThat(e.getClaimValue().asString(), is("jwt_id_123")); } @Test @@ -963,19 +963,19 @@ public void shouldSkipClaimValidationsIfNoClaimsRequired() { @Test public void shouldThrowWhenVerifyingClaimPresenceButClaimNotPresent() { - exception.expect(MissingClaimException.class); - exception.expectMessage("The Claim 'missing' is not present in the JWT."); - exception.expect(hasMissingClaimName("missing")); + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String jwt = JWTCreator.init() + .withClaim("custom", "") + .sign(Algorithm.HMAC256("secret")); - String jwt = JWTCreator.init() - .withClaim("custom", "") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaimPresence("missing") - .build(); + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaimPresence("missing") + .build(); - verifier.verify(jwt); + verifier.verify(jwt); + }); + assertThat(e.getMessage(), is("The Claim 'missing' is not present in the JWT.")); + assertThat(e.getClaimName(), is("missing")); } @Test @@ -1120,19 +1120,19 @@ public void shouldSuccessfullyVerifyClaimWithPredicate() { @Test public void shouldThrowWhenPredicateReturnsFalse() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'claimName' value doesn't match the required one."); - exception.expect(hasClaimName("claimName")); - exception.expect(hasClaimValue("claimValue", String.class)); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String jwt = JWTCreator.init() + .withClaim("claimName", "claimValue") + .sign(Algorithm.HMAC256("secret")); - String jwt = JWTCreator.init() - .withClaim("claimName", "claimValue") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) - .build() - .verify(jwt); + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) + .build() + .verify(jwt); + }); + assertThat(e.getMessage(), is("The Claim 'claimName' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("claimName")); + assertThat(e.getClaimValue().asString(), is("claimValue")); } @Test @@ -1162,34 +1162,34 @@ public void shouldSuccessfullyVerifyClaimWithNull() { @Test public void shouldThrowWhenNullClaimHasValue() { - exception.expect(IncorrectClaimException.class); - exception.expectMessage("The Claim 'claimName' value doesn't match the required one."); - exception.expect(hasClaimName("claimName")); - exception.expect(hasClaimValue("value", String.class)); + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String jwt = JWTCreator.init() + .withClaim("claimName", "value") + .sign(Algorithm.HMAC256("secret")); - String jwt = JWTCreator.init() - .withClaim("claimName", "value") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withNullClaim("claimName") - .build() - .verify(jwt); + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withNullClaim("claimName") + .build() + .verify(jwt); + }); + assertThat(e.getMessage(), is("The Claim 'claimName' value doesn't match the required one.")); + assertThat(e.getClaimName(), is("claimName")); + assertThat(e.getClaimValue().asString(), is("value")); } @Test public void shouldThrowWhenNullClaimIsMissing() { - exception.expect(MissingClaimException.class); - exception.expectMessage("The Claim 'anotherClaimName' is not present in the JWT."); - exception.expect(hasMissingClaimName("anotherClaimName")); - - String jwt = JWTCreator.init() - .withClaim("claimName", "value") - .sign(Algorithm.HMAC256("secret")); - - JWTVerifier.init(Algorithm.HMAC256("secret")) - .withNullClaim("anotherClaimName") - .build() - .verify(jwt); + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String jwt = JWTCreator.init() + .withClaim("claimName", "value") + .sign(Algorithm.HMAC256("secret")); + + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withNullClaim("anotherClaimName") + .build() + .verify(jwt); + }); + assertThat(e.getMessage(), is("The Claim 'anotherClaimName' is not present in the JWT.")); + assertThat(e.getClaimName(), is("anotherClaimName")); } } diff --git a/lib/src/test/java/com/auth0/jwt/matchers/CustomMatchers.java b/lib/src/test/java/com/auth0/jwt/matchers/CustomMatchers.java deleted file mode 100644 index acff9b0f..00000000 --- a/lib/src/test/java/com/auth0/jwt/matchers/CustomMatchers.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.auth0.jwt.matchers; - -import com.auth0.jwt.exceptions.IncorrectClaimException; -import com.auth0.jwt.exceptions.MissingClaimException; -import com.auth0.jwt.exceptions.TokenExpiredException; -import com.auth0.jwt.interfaces.Claim; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -import java.time.Instant; -import java.util.Arrays; - -public class CustomMatchers { - public static Matcher hasMissingClaimName(final String claimName) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("MissingClaimException with claim name: "+claimName); - } - - @Override - protected boolean matchesSafely(MissingClaimException item) { - return item.getClaimName().equals(claimName); - } - }; - } - - public static Matcher hasTokenExpiredOn(final Instant instant) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("TokenExpiredException with expired time as: "+instant.getEpochSecond()); - } - - @Override - protected boolean matchesSafely(TokenExpiredException item) { - return item.getExpiredOn().equals(instant); - } - }; - } - - public static Matcher hasClaimName(final String claimName) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("IncorrectClaimException with claim name: "+claimName); - } - - @Override - protected boolean matchesSafely(IncorrectClaimException item) { - return item.getClaimName().equals(claimName); - } - }; - } - - public static Matcher hasClaimValue(final Object value, final Class clazz) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("IncorrectClaimException with claim : "+value); - } - - @Override - protected boolean matchesSafely(IncorrectClaimException item) { - return item.getClaimValue().as(clazz).equals(value); - } - }; - } - - public static Matcher hasClaimInstant(final Instant value, final Class clazz) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("IncorrectClaimException with claim : "+value); - } - - @Override - protected boolean matchesSafely(IncorrectClaimException item) { - return item.getClaimValue().as(clazz).equals(value); - } - }; - } - - public static Matcher hasClaimValueArray(final Object value, final Class clazz) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("IncorrectClaimException with claim : "+value); - } - - @Override - protected boolean matchesSafely(IncorrectClaimException item) { - return Arrays.equals((Object[]) item.getClaimValue().as(clazz), (Object[])value); - } - }; - } - - public static Matcher hasNullClaim() { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("IncorrectClaimException with claim as null"); - } - - @Override - protected boolean matchesSafely(IncorrectClaimException item) { - boolean a = item.getClaimValue().isNull(); - String b = item.getClaimValue().toString(); - return item.getClaimValue().isNull(); - } - }; - } -} From af04b229327f863cdde7c41c77c076e39a6b3742 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 13 Apr 2022 15:05:02 +0530 Subject: [PATCH 024/134] [SDK-3231] Added support for multiple checks on a single claim (#573) * Added support for multiple checks on a single claim * Fix codecov CI failure * Allow pseudo comparison for codecov * Remove newly added parameters and check codecov disabled * Reenabled changes check in codecov * Trigger Build * Refactor ExpectedCheckHolder from interfaces to impl package * Refactored code to improve coverage report --- .../main/java/com/auth0/jwt/JWTVerifier.java | 153 ++++++----- .../auth0/jwt/impl/ExpectedCheckHolder.java | 25 ++ .../java/com/auth0/jwt/JWTVerifierTest.java | 241 ++++++++++++------ 3 files changed, 282 insertions(+), 137 deletions(-) create mode 100644 lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index ba19feb9..801dac24 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -6,6 +6,7 @@ import com.auth0.jwt.impl.PublicClaims; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; +import com.auth0.jwt.impl.ExpectedCheckHolder; import com.auth0.jwt.interfaces.Verification; import java.time.Clock; @@ -25,12 +26,12 @@ */ public final class JWTVerifier implements com.auth0.jwt.interfaces.JWTVerifier { private final Algorithm algorithm; - final Map> expectedChecks; + final List expectedChecks; private final JWTParser parser; - JWTVerifier(Algorithm algorithm, Map> expectedChecks) { + JWTVerifier(Algorithm algorithm, List expectedChecks) { this.algorithm = algorithm; - this.expectedChecks = Collections.unmodifiableMap(expectedChecks); + this.expectedChecks = Collections.unmodifiableList(expectedChecks); this.parser = new JWTParser(); } @@ -50,7 +51,7 @@ static Verification init(Algorithm algorithm) throws IllegalArgumentException { */ public static class BaseVerification implements Verification { private final Algorithm algorithm; - private final Map> expectedChecks; + private final List expectedChecks; private long defaultLeeway; private final Map customLeeways; private boolean ignoreIssuedAt; @@ -62,7 +63,7 @@ public static class BaseVerification implements Verification { } this.algorithm = algorithm; - this.expectedChecks = new LinkedHashMap<>(); + this.expectedChecks = new ArrayList<>(); this.customLeeways = new HashMap<>(); this.defaultLeeway = 0; } @@ -70,7 +71,10 @@ public static class BaseVerification implements Verification { @Override public Verification withIssuer(String... issuer) { List value = isNullOrEmpty(issuer) ? null : Arrays.asList(issuer); - checkIfNeedToRemove(PublicClaims.ISSUER, value, ((claim, decodedJWT) -> { + addCheck(PublicClaims.ISSUER, ((claim, decodedJWT) -> { + if (verifyNull(claim, value)) { + return true; + } if (value == null || !value.contains(claim.asString())) { throw new IncorrectClaimException( "The Claim 'iss' value doesn't match the required issuer.", PublicClaims.ISSUER, claim); @@ -82,23 +86,40 @@ public Verification withIssuer(String... issuer) { @Override public Verification withSubject(String subject) { - checkIfNeedToRemove(PublicClaims.SUBJECT, subject, (claim, decodedJWT) -> subject.equals(claim.asString())); + addCheck(PublicClaims.SUBJECT, (claim, decodedJWT) -> + verifyNull(claim, subject) || subject.equals(claim.asString())); return this; } @Override public Verification withAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - checkIfNeedToRemove(PublicClaims.AUDIENCE, value, ((claim, decodedJWT) -> - assertValidAudienceClaim(claim, decodedJWT.getAudience(), value, true))); + addCheck(PublicClaims.AUDIENCE, ((claim, decodedJWT) -> { + if (verifyNull(claim, value)) { + return true; + } + if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, true)) { + throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", + PublicClaims.AUDIENCE, claim); + } + return true; + })); return this; } @Override public Verification withAnyOfAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - checkIfNeedToRemove(PublicClaims.AUDIENCE, value, ((claim, decodedJWT) -> - assertValidAudienceClaim(claim, decodedJWT.getAudience(), value, false))); + addCheck(PublicClaims.AUDIENCE, ((claim, decodedJWT) -> { + if (verifyNull(claim, value)) { + return true; + } + if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, false)) { + throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", + PublicClaims.AUDIENCE, claim); + } + return true; + })); return this; } @@ -138,14 +159,16 @@ public Verification ignoreIssuedAt() { @Override public Verification withJWTId(String jwtId) { - checkIfNeedToRemove(PublicClaims.JWT_ID, jwtId, ((claim, decodedJWT) -> jwtId.equals(claim.asString()))); + addCheck(PublicClaims.JWT_ID, ((claim, decodedJWT) -> + verifyNull(claim, jwtId) || jwtId.equals(claim.asString()))); return this; } @Override public Verification withClaimPresence(String name) throws IllegalArgumentException { assertNonNull(name); - withClaim(name, ((claim, decodedJWT) -> assertClaimPresence(name, claim))); + //since addCheck already checks presence, we just return true + withClaim(name, ((claim, decodedJWT) -> true)); return this; } @@ -159,35 +182,40 @@ public Verification withNullClaim(String name) throws IllegalArgumentException { @Override public Verification withClaim(String name, Boolean value) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asBoolean()))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) + || value.equals(claim.asBoolean()))); return this; } @Override public Verification withClaim(String name, Integer value) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asInt()))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) + || value.equals(claim.asInt()))); return this; } @Override public Verification withClaim(String name, Long value) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asLong()))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) + || value.equals(claim.asLong()))); return this; } @Override public Verification withClaim(String name, Double value) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asDouble()))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) + || value.equals(claim.asDouble()))); return this; } @Override public Verification withClaim(String name, String value) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, value, ((claim, decodedJWT) -> value.equals(claim.asString()))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, value) + || value.equals(claim.asString()))); return this; } @@ -201,8 +229,9 @@ public Verification withClaim(String name, Instant value) throws IllegalArgument assertNonNull(name); // Since date-time claims are serialized as epoch seconds, // we need to compare them with only seconds-granularity - checkIfNeedToRemove(name, value, - ((claim, decodedJWT) -> value.truncatedTo(ChronoUnit.SECONDS).equals(claim.asInstant()))); + addCheck(name, + ((claim, decodedJWT) -> verifyNull(claim, value) + || value.truncatedTo(ChronoUnit.SECONDS).equals(claim.asInstant()))); return this; } @@ -210,28 +239,32 @@ public Verification withClaim(String name, Instant value) throws IllegalArgument public Verification withClaim(String name, BiPredicate predicate) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, predicate, predicate); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, predicate) + || predicate.test(claim, decodedJWT))); return this; } @Override public Verification withArrayClaim(String name, String... items) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, items, ((claim, decodedJWT) -> assertValidCollectionClaim(claim, items))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, items) + || assertValidCollectionClaim(claim, items))); return this; } @Override public Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, items, ((claim, decodedJWT) -> assertValidCollectionClaim(claim, items))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, items) + || assertValidCollectionClaim(claim, items))); return this; } @Override public Verification withArrayClaim(String name, Long... items) throws IllegalArgumentException { assertNonNull(name); - checkIfNeedToRemove(name, items, ((claim, decodedJWT) -> assertValidCollectionClaim(claim, items))); + addCheck(name, ((claim, decodedJWT) -> verifyNull(claim, items) + || assertValidCollectionClaim(claim, items))); return this; } @@ -268,13 +301,13 @@ private void addMandatoryClaimChecks() { long notBeforeLeeway = getLeewayFor(PublicClaims.NOT_BEFORE); long issuedAtLeeway = getLeewayFor(PublicClaims.ISSUED_AT); - expectedChecks.put(PublicClaims.EXPIRES_AT, (claim, decodedJWT) -> - assertValidInstantClaim(PublicClaims.EXPIRES_AT, claim, expiresAtLeeway, true)); - expectedChecks.put(PublicClaims.NOT_BEFORE, (claim, decodedJWT) -> - assertValidInstantClaim(PublicClaims.NOT_BEFORE, claim, notBeforeLeeway, false)); + expectedChecks.add(constructExpectedCheck(PublicClaims.EXPIRES_AT, (claim, decodedJWT) -> + assertValidInstantClaim(PublicClaims.EXPIRES_AT, claim, expiresAtLeeway, true))); + expectedChecks.add(constructExpectedCheck(PublicClaims.NOT_BEFORE, (claim, decodedJWT) -> + assertValidInstantClaim(PublicClaims.NOT_BEFORE, claim, notBeforeLeeway, false))); if (!ignoreIssuedAt) { - expectedChecks.put(PublicClaims.ISSUED_AT, (claim, decodedJWT) -> - assertValidInstantClaim(PublicClaims.ISSUED_AT, claim, issuedAtLeeway, false)); + expectedChecks.add(constructExpectedCheck(PublicClaims.ISSUED_AT, (claim, decodedJWT) -> + assertValidInstantClaim(PublicClaims.ISSUED_AT, claim, issuedAtLeeway, false))); } } @@ -294,8 +327,7 @@ private boolean assertValidCollectionClaim(Claim claim, Object[] expectedClaimVa } } } else { - claimArr = claim.isNull() || claim.isMissing() - ? Collections.emptyList() : Arrays.asList(claim.as(Object[].class)); + claimArr = Arrays.asList(claim.as(Object[].class)); } List valueArr = Arrays.asList(expectedClaimValue); return claimArr.containsAll(valueArr); @@ -329,24 +361,12 @@ private boolean assertInstantIsPast(Instant claimVal, long leeway, Instant now) } private boolean assertValidAudienceClaim( - Claim claim, List audience, List values, boolean shouldContainAll ) { - if (audience == null || (shouldContainAll && !audience.containsAll(values)) - || (!shouldContainAll && Collections.disjoint(audience, values))) { - throw new IncorrectClaimException( - "The Claim 'aud' value doesn't contain the required audience.", PublicClaims.AUDIENCE, claim); - } - return true; - } - - private boolean assertClaimPresence(String name, Claim claim) { - if (claim.isMissing()) { - throw new MissingClaimException(name); - } - return true; + return !(audience == null || (shouldContainAll && !audience.containsAll(values)) + || (!shouldContainAll && Collections.disjoint(audience, values))); } private void assertPositive(long leeway) { @@ -361,13 +381,31 @@ private void assertNonNull(String name) { } } - private void checkIfNeedToRemove(String name, Object value, BiPredicate predicate) { - if (value == null) { - expectedChecks.remove(name); - return; - } - expectedChecks.put(name, (claim, decodedJWT) -> assertClaimPresence(name, claim) - && predicate.test(claim, decodedJWT)); + private void addCheck(String name, BiPredicate predicate) { + expectedChecks.add(constructExpectedCheck(name, (claim, decodedJWT) -> { + if (claim.isMissing()) { + throw new MissingClaimException(name); + } + return predicate.test(claim, decodedJWT); + })); + } + + private ExpectedCheckHolder constructExpectedCheck(String claimName, BiPredicate check) { + return new ExpectedCheckHolder() { + @Override + public String getClaimName() { + return claimName; + } + + @Override + public boolean verify(Claim claim, DecodedJWT decodedJWT) { + return check.test(claim, decodedJWT); + } + }; + } + + private boolean verifyNull(Claim claim, Object value) { + return value == null && claim.isNull(); } private boolean isNullOrEmpty(String[] args) { @@ -431,15 +469,14 @@ private void verifyAlgorithm(DecodedJWT jwt, Algorithm expectedAlgorithm) throws } } - private void verifyClaims(DecodedJWT jwt, Map> claims) + private void verifyClaims(DecodedJWT jwt, List expectedChecks) throws TokenExpiredException, InvalidClaimException { - for (Map.Entry> entry : claims.entrySet()) { + for (ExpectedCheckHolder expectedCheck : expectedChecks) { boolean isValid; - String claimName = entry.getKey(); - BiPredicate expectedCheck = entry.getValue(); + String claimName = expectedCheck.getClaimName(); Claim claim = jwt.getClaim(claimName); - isValid = expectedCheck.test(claim, jwt); + isValid = expectedCheck.verify(claim, jwt); if (!isValid) { throw new IncorrectClaimException( diff --git a/lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java b/lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java new file mode 100644 index 00000000..6737031c --- /dev/null +++ b/lib/src/main/java/com/auth0/jwt/impl/ExpectedCheckHolder.java @@ -0,0 +1,25 @@ +package com.auth0.jwt.impl; + +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; + +/** + * This holds the checks that are run to verify a JWT. + */ +public interface ExpectedCheckHolder { + /** + * The claim name that will be checked. + * + * @return the claim name + */ + String getClaimName(); + + /** + * The verification that will be run. + * + * @param claim the claim for which verification is done + * @param decodedJWT the JWT on which verification is done + * @return whether the verification passed or not + */ + boolean verify(Claim claim, DecodedJWT decodedJWT); +} diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 9dcb2cb1..72e5656f 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -56,8 +56,18 @@ public void shouldValidateIssuer() { .withIssuer("auth0") .build() .verify(token); - assertThat(jwt, is(notNullValue())); + + // "iss": ["auth0", "okta"] + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, ()-> { + String token1 = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withIssuer((String[]) null) + .build() + .verify(token1); + }); + + assertThat(e.getClaimName(), is("iss")); } @Test @@ -179,7 +189,7 @@ public void shouldAllowWithAnyOfAudienceVerificationToOverrideWithAudience() { assertThat(exception, is(instanceOf(IncorrectClaimException.class))); assertThat(exception.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - DecodedJWT jwt = verification.withAnyOfAudience("Mark", "Jim").build().verify(token); + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")).withAnyOfAudience("Mark", "Jim").build().verify(token); assertThat(jwt, is(notNullValue())); } @@ -201,7 +211,7 @@ public void shouldAllowWithAudienceVerificationToOverrideWithAnyOfAudience() { assertThat(exception, is(instanceOf(IncorrectClaimException.class))); assertThat(exception.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - DecodedJWT jwt = verification.withAudience("Mark").build().verify(token); + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")).withAudience("Mark").build().verify(token); assertThat(jwt, is(notNullValue())); } @@ -303,75 +313,15 @@ public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { } @Test - public void shouldRemoveAudienceWhenPassingNullReference() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) - .withAudience((String) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey(PublicClaims.AUDIENCE))); - - verifier = JWTVerifier.init(algorithm) + public void shouldNotReplaceWhenMultipleChecksAreAdded() { + JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) .withAudience((String[]) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey(PublicClaims.AUDIENCE))); - - verifier = JWTVerifier.init(algorithm) .withAudience() - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey(PublicClaims.AUDIENCE))); - - String emptyAud = " "; - verifier = JWTVerifier.init(algorithm) - .withAudience(emptyAud) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - } - - @Test - public void shouldRemoveAudienceWhenPassingNull() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) - .withAudience("John") - .withAudience((String) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("aud"))); - - verifier = JWTVerifier.init(algorithm) - .withAudience("John") - .withAudience((String[]) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("aud"))); - } - - @Test - public void shouldRemoveAudienceWhenPassingNullWithAnyAudience() { - Algorithm algorithm = mock(Algorithm.class); - JWTVerifier verifier = JWTVerifier.init(algorithm) - .withAnyOfAudience("John") - .withAnyOfAudience((String) null) - .build(); - - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("aud"))); - - verifier = JWTVerifier.init(algorithm) - .withAnyOfAudience("John") .withAnyOfAudience((String[]) null) + .withAnyOfAudience() .build(); - assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("aud"))); + assertThat(verifier.expectedChecks.size(), is(7)); //3 extra mandatory checks exp, nbf, iat } @Test @@ -561,14 +511,14 @@ public void shouldValidateCustomClaimOfTypeDate() { } @Test - public void shouldRemoveCustomClaimOfTypeDateWhenNull() { + public void shouldNotRemoveCustomClaimOfTypeDateWhenNull() { JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", new Date()) .withClaim("name", (Date) null) .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("iss"))); + assertThat(verifier.expectedChecks.size(), is(5)); } @Test @@ -900,7 +850,7 @@ public void shouldThrowOnInvalidJWTId() { } @Test - public void shouldRemoveClaimWhenPassingNull() { + public void shouldNotRemoveClaimWhenPassingNull() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withIssuer("iss") @@ -908,7 +858,7 @@ public void shouldRemoveClaimWhenPassingNull() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("iss"))); + assertThat(verifier.expectedChecks.size(), is(5)); verifier = JWTVerifier.init(algorithm) .withIssuer("iss") @@ -916,32 +866,32 @@ public void shouldRemoveClaimWhenPassingNull() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("iss"))); + assertThat(verifier.expectedChecks.size(), is(5)); } @Test - public void shouldRemoveIssuerWhenPassingNullReference() { + public void shouldNotRemoveIssuerWhenPassingNullReference() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withIssuer((String) null) .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("iss"))); + assertThat(verifier.expectedChecks.size(), is(4)); verifier = JWTVerifier.init(algorithm) .withIssuer((String[]) null) .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("iss"))); + assertThat(verifier.expectedChecks.size(), is(4)); verifier = JWTVerifier.init(algorithm) .withIssuer() .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("iss"))); + assertThat(verifier.expectedChecks.size(), is(4)); String emptyIss = " "; verifier = JWTVerifier.init(algorithm) @@ -1111,7 +1061,6 @@ public void shouldSuccessfullyVerifyClaimWithPredicate() { JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("claimName", (claim, decodedJWT) -> "claimValue".equals(claim.asString())) - .withClaim(PublicClaims.ISSUED_AT, ((claim, decodedJWT) -> false)) .build(); DecodedJWT decodedJWT = verifier.verify(jwt); @@ -1136,14 +1085,14 @@ public void shouldThrowWhenPredicateReturnsFalse() { } @Test - public void shouldRemovePredicateCheckForNull() { + public void shouldNotRemovePredicateCheckForNull() { JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("claimName", (claim, decodedJWT) -> "nope".equals(claim.asString())) .withClaim("claimName", (BiPredicate) null) .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verifier.expectedChecks, not(hasKey("claimName"))); + assertThat(verifier.expectedChecks.size(), is(5)); } @Test @@ -1192,4 +1141,138 @@ public void shouldThrowWhenNullClaimIsMissing() { assertThat(e.getMessage(), is("The Claim 'anotherClaimName' is not present in the JWT.")); assertThat(e.getClaimName(), is("anotherClaimName")); } + + @Test + public void shouldCheckForNullValuesForSubject() { + // sub = null + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOm51bGx9.y5brmQQ05OYwVvlTg83njUrz6tfpdyWNh17LHU6DxmI"; + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withSubject(null) + .build() + .verify(token); + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldCheckForNullValuesInIssuer() { + // iss = null + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOm51bGx9.OoiCLipSfflWxkFX2rytvtwEiJ8eAL0opkdXY_ap0qA"; + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withIssuer((String) null) + .withIssuer((String[]) null) + .withIssuer() + .build() + .verify(token); + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldCheckForNullValuesInJwtId() { + // jti = null + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOm51bGx9.z_MDyl8uPGH0q0jeB54wbYt3bwKXamU_3MO8LofGvZs"; + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withJWTId(null) + .build() + .verify(token); + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldCheckForNullValuesInCustomClaims() { + // jti = null + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOm51bGx9.inAuN3Q9UZ6WgbB63O43B1ero2MTqnfzzumr_5qYIls"; + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("custom", (Boolean) null) + .withClaim("custom", (Integer) null) + .withClaim("custom", (Long) null) + .withClaim("custom", (Double) null) + .withClaim("custom", (String) null) + .withClaim("custom", (Date) null) + .withClaim("custom", (Instant) null) + .withClaim("custom", (BiPredicate) null) + .withArrayClaim("custom", (String[]) null) + .withArrayClaim("custom", (Integer[]) null) + .withArrayClaim("custom", (Long[]) null) + .build() + .verify(token); + assertThat(jwt, is(notNullValue())); + } + + + @Test + public void shouldCheckForNullValuesForAudience() { + // aud = null + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; + DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAudience((String[]) null) + .withAudience((String) null) + .withAudience() + .withAnyOfAudience((String[]) null) + .withAnyOfAudience((String) null) + .withAnyOfAudience() + .build() + .verify(token); + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldCheckForClaimPresenceEvenForNormalClaimChecks() { + MissingClaimException e = assertThrows(null, MissingClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjpudWxsfQ.bpPyquk3b8KepErKgTidjJ1ZwiOGuoTxam2_x7cElKI"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("custom", true) + .build() + .verify(token); + }); + assertThat(e.getClaimName(), is("custom")); + } + + @Test + public void shouldCheckForWrongLongClaim() { + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOjF9.00btiK0sv8pQ2T-hOr9GC5x2osi7--Bsk4pS5cTikqQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("custom", 2L) + .build() + .verify(token); + }); + assertThat(e.getClaimName(), is("custom")); + assertThat(e.getClaimValue().asLong(), is(1L)); + } + + @Test + public void shouldCheckForWrongLongArrayClaim() { + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOlsxXX0.R9ZSmgtJng062rcEc59u4VKCq89Yk5VlkN9BuMTMvr0"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withArrayClaim("custom", 2L) + .build() + .verify(token); + }); + assertThat(e.getClaimName(), is("custom")); + } + + @Test + public void shouldCheckForWrongStringArrayClaim() { + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOlsxXX0.R9ZSmgtJng062rcEc59u4VKCq89Yk5VlkN9BuMTMvr0"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withArrayClaim("custom", "2L") + .build() + .verify(token); + }); + assertThat(e.getClaimName(), is("custom")); + } + + @Test + public void shouldCheckForWrongIntegerArrayClaim() { + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b20iOlsxXX0.R9ZSmgtJng062rcEc59u4VKCq89Yk5VlkN9BuMTMvr0"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withArrayClaim("custom", 2) + .build() + .verify(token); + }); + assertThat(e.getClaimName(), is("custom")); + } } From 05c925edc68eb072e6910055891d1317be2325a2 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Wed, 13 Apr 2022 09:58:21 -0500 Subject: [PATCH 025/134] [SDK-3226] Expose claim header constants --- lib/src/main/java/HeaderParams.java | 29 +++++++++++ .../main/java/com/auth0/jwt/JWTCreator.java | 28 +++++----- .../main/java/com/auth0/jwt/JWTVerifier.java | 43 ++++++++------- .../java/com/auth0/jwt/StandardClaims.java | 48 +++++++++++++++++ .../auth0/jwt/impl/HeaderDeserializer.java | 9 ++-- .../auth0/jwt/impl/PayloadDeserializer.java | 15 +++--- .../com/auth0/jwt/impl/PayloadSerializer.java | 3 +- .../java/com/auth0/jwt/impl/PublicClaims.java | 23 -------- .../java/com/auth0/jwt/JWTCreatorTest.java | 21 ++++---- .../java/com/auth0/jwt/JWTDecoderTest.java | 4 +- lib/src/test/java/com/auth0/jwt/JWTTest.java | 6 +-- .../java/com/auth0/jwt/JWTVerifierTest.java | 52 +++++++++---------- 12 files changed, 166 insertions(+), 115 deletions(-) create mode 100644 lib/src/main/java/HeaderParams.java create mode 100644 lib/src/main/java/com/auth0/jwt/StandardClaims.java delete mode 100644 lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java diff --git a/lib/src/main/java/HeaderParams.java b/lib/src/main/java/HeaderParams.java new file mode 100644 index 00000000..e15877a2 --- /dev/null +++ b/lib/src/main/java/HeaderParams.java @@ -0,0 +1,29 @@ +package com.auth0.jwt; + +/** + * Contains constants representing the JWT header parameter names. + */ +public final class HeaderParams { + + private HeaderParams() {} + + /** + * The algorithm used to sign a JWT. + */ + public static String ALGORITHM = "alg"; + + /** + * The content type of a JWT. + */ + public static String CONTENT_TYPE = "cty"; + + /** + * The media type of a JWT. + */ + public static String TYPE = "typ"; + + /** + * The key ID of a JWT used to specify the key for signature validation. + */ + public static String KEY_ID = "kid"; +} diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index e1159ae4..f0299d22 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -104,7 +104,7 @@ public Builder withHeader(Map headerClaims) { * @return this same Builder instance. */ public Builder withKeyId(String keyId) { - this.headerClaims.put(PublicClaims.KEY_ID, keyId); + this.headerClaims.put(HeaderParams.KEY_ID, keyId); return this; } @@ -115,7 +115,7 @@ public Builder withKeyId(String keyId) { * @return this same Builder instance. */ public Builder withIssuer(String issuer) { - addClaim(PublicClaims.ISSUER, issuer); + addClaim(StandardClaims.ISSUER, issuer); return this; } @@ -126,7 +126,7 @@ public Builder withIssuer(String issuer) { * @return this same Builder instance. */ public Builder withSubject(String subject) { - addClaim(PublicClaims.SUBJECT, subject); + addClaim(StandardClaims.SUBJECT, subject); return this; } @@ -137,7 +137,7 @@ public Builder withSubject(String subject) { * @return this same Builder instance. */ public Builder withAudience(String... audience) { - addClaim(PublicClaims.AUDIENCE, audience); + addClaim(StandardClaims.AUDIENCE, audience); return this; } @@ -149,7 +149,7 @@ public Builder withAudience(String... audience) { * @return this same Builder instance. */ public Builder withExpiresAt(Date expiresAt) { - addClaim(PublicClaims.EXPIRES_AT, expiresAt); + addClaim(StandardClaims.EXPIRES_AT, expiresAt); return this; } @@ -161,7 +161,7 @@ public Builder withExpiresAt(Date expiresAt) { * @return this same Builder instance. */ public Builder withExpiresAt(Instant expiresAt) { - addClaim(PublicClaims.EXPIRES_AT, expiresAt); + addClaim(StandardClaims.EXPIRES_AT, expiresAt); return this; } @@ -173,7 +173,7 @@ public Builder withExpiresAt(Instant expiresAt) { * @return this same Builder instance. */ public Builder withNotBefore(Date notBefore) { - addClaim(PublicClaims.NOT_BEFORE, notBefore); + addClaim(StandardClaims.NOT_BEFORE, notBefore); return this; } @@ -185,7 +185,7 @@ public Builder withNotBefore(Date notBefore) { * @return this same Builder instance. */ public Builder withNotBefore(Instant notBefore) { - addClaim(PublicClaims.NOT_BEFORE, notBefore); + addClaim(StandardClaims.NOT_BEFORE, notBefore); return this; } @@ -197,7 +197,7 @@ public Builder withNotBefore(Instant notBefore) { * @return this same Builder instance. */ public Builder withIssuedAt(Date issuedAt) { - addClaim(PublicClaims.ISSUED_AT, issuedAt); + addClaim(StandardClaims.ISSUED_AT, issuedAt); return this; } @@ -209,7 +209,7 @@ public Builder withIssuedAt(Date issuedAt) { * @return this same Builder instance. */ public Builder withIssuedAt(Instant issuedAt) { - addClaim(PublicClaims.ISSUED_AT, issuedAt); + addClaim(StandardClaims.ISSUED_AT, issuedAt); return this; } @@ -220,7 +220,7 @@ public Builder withIssuedAt(Instant issuedAt) { * @return this same Builder instance. */ public Builder withJWTId(String jwtId) { - addClaim(PublicClaims.JWT_ID, jwtId); + addClaim(StandardClaims.JWT_ID, jwtId); return this; } @@ -543,9 +543,9 @@ public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCrea if (algorithm == null) { throw new IllegalArgumentException("The Algorithm cannot be null."); } - headerClaims.put(PublicClaims.ALGORITHM, algorithm.getName()); - if (!headerClaims.containsKey(PublicClaims.TYPE)) { - headerClaims.put(PublicClaims.TYPE, "JWT"); + headerClaims.put(HeaderParams.ALGORITHM, algorithm.getName()); + if (!headerClaims.containsKey(HeaderParams.TYPE)) { + headerClaims.put(HeaderParams.TYPE, "JWT"); } String signingKeyId = algorithm.getSigningKeyId(); if (signingKeyId != null) { diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 801dac24..223de7f5 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -3,7 +3,6 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.*; import com.auth0.jwt.impl.JWTParser; -import com.auth0.jwt.impl.PublicClaims; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.impl.ExpectedCheckHolder; @@ -71,13 +70,13 @@ public static class BaseVerification implements Verification { @Override public Verification withIssuer(String... issuer) { List value = isNullOrEmpty(issuer) ? null : Arrays.asList(issuer); - addCheck(PublicClaims.ISSUER, ((claim, decodedJWT) -> { + addCheck(StandardClaims.ISSUER, ((claim, decodedJWT) -> { if (verifyNull(claim, value)) { return true; } if (value == null || !value.contains(claim.asString())) { throw new IncorrectClaimException( - "The Claim 'iss' value doesn't match the required issuer.", PublicClaims.ISSUER, claim); + "The Claim 'iss' value doesn't match the required issuer.", StandardClaims.ISSUER, claim); } return true; })); @@ -86,7 +85,7 @@ public Verification withIssuer(String... issuer) { @Override public Verification withSubject(String subject) { - addCheck(PublicClaims.SUBJECT, (claim, decodedJWT) -> + addCheck(StandardClaims.SUBJECT, (claim, decodedJWT) -> verifyNull(claim, subject) || subject.equals(claim.asString())); return this; } @@ -94,13 +93,13 @@ public Verification withSubject(String subject) { @Override public Verification withAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - addCheck(PublicClaims.AUDIENCE, ((claim, decodedJWT) -> { + addCheck(StandardClaims.AUDIENCE, ((claim, decodedJWT) -> { if (verifyNull(claim, value)) { return true; } if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, true)) { throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", - PublicClaims.AUDIENCE, claim); + StandardClaims.AUDIENCE, claim); } return true; })); @@ -110,13 +109,13 @@ public Verification withAudience(String... audience) { @Override public Verification withAnyOfAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - addCheck(PublicClaims.AUDIENCE, ((claim, decodedJWT) -> { + addCheck(StandardClaims.AUDIENCE, ((claim, decodedJWT) -> { if (verifyNull(claim, value)) { return true; } if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, false)) { throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", - PublicClaims.AUDIENCE, claim); + StandardClaims.AUDIENCE, claim); } return true; })); @@ -133,21 +132,21 @@ public Verification acceptLeeway(long leeway) throws IllegalArgumentException { @Override public Verification acceptExpiresAt(long leeway) throws IllegalArgumentException { assertPositive(leeway); - customLeeways.put(PublicClaims.EXPIRES_AT, leeway); + customLeeways.put(StandardClaims.EXPIRES_AT, leeway); return this; } @Override public Verification acceptNotBefore(long leeway) throws IllegalArgumentException { assertPositive(leeway); - customLeeways.put(PublicClaims.NOT_BEFORE, leeway); + customLeeways.put(StandardClaims.NOT_BEFORE, leeway); return this; } @Override public Verification acceptIssuedAt(long leeway) throws IllegalArgumentException { assertPositive(leeway); - customLeeways.put(PublicClaims.ISSUED_AT, leeway); + customLeeways.put(StandardClaims.ISSUED_AT, leeway); return this; } @@ -159,7 +158,7 @@ public Verification ignoreIssuedAt() { @Override public Verification withJWTId(String jwtId) { - addCheck(PublicClaims.JWT_ID, ((claim, decodedJWT) -> + addCheck(StandardClaims.JWT_ID, ((claim, decodedJWT) -> verifyNull(claim, jwtId) || jwtId.equals(claim.asString()))); return this; } @@ -297,17 +296,17 @@ public long getLeewayFor(String name) { } private void addMandatoryClaimChecks() { - long expiresAtLeeway = getLeewayFor(PublicClaims.EXPIRES_AT); - long notBeforeLeeway = getLeewayFor(PublicClaims.NOT_BEFORE); - long issuedAtLeeway = getLeewayFor(PublicClaims.ISSUED_AT); - - expectedChecks.add(constructExpectedCheck(PublicClaims.EXPIRES_AT, (claim, decodedJWT) -> - assertValidInstantClaim(PublicClaims.EXPIRES_AT, claim, expiresAtLeeway, true))); - expectedChecks.add(constructExpectedCheck(PublicClaims.NOT_BEFORE, (claim, decodedJWT) -> - assertValidInstantClaim(PublicClaims.NOT_BEFORE, claim, notBeforeLeeway, false))); + long expiresAtLeeway = getLeewayFor(StandardClaims.EXPIRES_AT); + long notBeforeLeeway = getLeewayFor(StandardClaims.NOT_BEFORE); + long issuedAtLeeway = getLeewayFor(StandardClaims.ISSUED_AT); + + expectedChecks.add(constructExpectedCheck(StandardClaims.EXPIRES_AT, (claim, decodedJWT) -> + assertValidInstantClaim(StandardClaims.EXPIRES_AT, claim, expiresAtLeeway, true))); + expectedChecks.add(constructExpectedCheck(StandardClaims.NOT_BEFORE, (claim, decodedJWT) -> + assertValidInstantClaim(StandardClaims.NOT_BEFORE, claim, notBeforeLeeway, false))); if (!ignoreIssuedAt) { - expectedChecks.add(constructExpectedCheck(PublicClaims.ISSUED_AT, (claim, decodedJWT) -> - assertValidInstantClaim(PublicClaims.ISSUED_AT, claim, issuedAtLeeway, false))); + expectedChecks.add(constructExpectedCheck(StandardClaims.ISSUED_AT, (claim, decodedJWT) -> + assertValidInstantClaim(StandardClaims.ISSUED_AT, claim, issuedAtLeeway, false))); } } diff --git a/lib/src/main/java/com/auth0/jwt/StandardClaims.java b/lib/src/main/java/com/auth0/jwt/StandardClaims.java new file mode 100644 index 00000000..4fe82d64 --- /dev/null +++ b/lib/src/main/java/com/auth0/jwt/StandardClaims.java @@ -0,0 +1,48 @@ +package com.auth0.jwt; + +/** + * Contains constants representing the name of the Registered Claim Names as defined in Section 4.1.1 of + * RFC 7529 + */ +public final class StandardClaims { + + private StandardClaims() { + } + + /** + * The "iss" (issuer) claim identifies the principal that issued the JWT. + */ + public static String ISSUER = "iss"; + + /** + * The "sub" (subject) claim identifies the principal that is the subject of the JWT. + */ + public static String SUBJECT = "sub"; + + /** + * The "aud" (audience) claim identifies the recipients that the JWT is intended for. + */ + public static String AUDIENCE = "aud"; + + /** + * The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be + * accepted for processing. + */ + public static String EXPIRES_AT = "exp"; + + /** + * The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. + */ + public static String NOT_BEFORE = "nbf"; + + /** + * The "iat" (issued at) claim identifies the time at which the JWT was issued. + */ + public static String ISSUED_AT = "iat"; + + /** + * The "jti" (JWT ID) claim provides a unique identifier for the JWT. + */ + public static String JWT_ID = "jti"; + +} diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java index 8a6cbcf8..9293fd4d 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java @@ -1,5 +1,6 @@ package com.auth0.jwt.impl; +import com.auth0.jwt.HeaderParams; import com.auth0.jwt.exceptions.JWTDecodeException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.type.TypeReference; @@ -40,10 +41,10 @@ public BasicHeader deserialize(JsonParser p, DeserializationContext ctxt) throws throw new JWTDecodeException("Parsing the Header's JSON resulted on a Null map"); } - String algorithm = getString(tree, PublicClaims.ALGORITHM); - String type = getString(tree, PublicClaims.TYPE); - String contentType = getString(tree, PublicClaims.CONTENT_TYPE); - String keyId = getString(tree, PublicClaims.KEY_ID); + String algorithm = getString(tree, HeaderParams.ALGORITHM); + String type = getString(tree, HeaderParams.TYPE); + String contentType = getString(tree, HeaderParams.CONTENT_TYPE); + String keyId = getString(tree, HeaderParams.KEY_ID); return new BasicHeader(algorithm, type, contentType, keyId, tree, objectReader); } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 09009267..4d058826 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -1,5 +1,6 @@ package com.auth0.jwt.impl; +import com.auth0.jwt.StandardClaims; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.Payload; import com.fasterxml.jackson.core.JsonParser; @@ -43,13 +44,13 @@ public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOE throw new JWTDecodeException("Parsing the Payload's JSON resulted on a Null map"); } - String issuer = getString(tree, PublicClaims.ISSUER); - String subject = getString(tree, PublicClaims.SUBJECT); - List audience = getStringOrArray(tree, PublicClaims.AUDIENCE); - Instant expiresAt = getInstantFromSeconds(tree, PublicClaims.EXPIRES_AT); - Instant notBefore = getInstantFromSeconds(tree, PublicClaims.NOT_BEFORE); - Instant issuedAt = getInstantFromSeconds(tree, PublicClaims.ISSUED_AT); - String jwtId = getString(tree, PublicClaims.JWT_ID); + String issuer = getString(tree, StandardClaims.ISSUER); + String subject = getString(tree, StandardClaims.SUBJECT); + List audience = getStringOrArray(tree, StandardClaims.AUDIENCE); + Instant expiresAt = getInstantFromSeconds(tree, StandardClaims.EXPIRES_AT); + Instant notBefore = getInstantFromSeconds(tree, StandardClaims.NOT_BEFORE); + Instant issuedAt = getInstantFromSeconds(tree, StandardClaims.ISSUED_AT); + String jwtId = getString(tree, StandardClaims.JWT_ID); return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, objectReader); } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index dc138c08..1d2ada43 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -1,5 +1,6 @@ package com.auth0.jwt.impl; +import com.auth0.jwt.StandardClaims; import com.fasterxml.jackson.core.JsonGenerator; import java.io.IOException; @@ -22,7 +23,7 @@ public PayloadSerializer() { @Override protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { - if (PublicClaims.AUDIENCE.equals(entry.getKey())) { + if (StandardClaims.AUDIENCE.equals(entry.getKey())) { writeAudience(gen, entry); } else { super.writeClaim(entry, gen); diff --git a/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java b/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java deleted file mode 100644 index ea166b0d..00000000 --- a/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.auth0.jwt.impl; - -/** - * Contains the claim name for all Public claims. - */ -public interface PublicClaims { - - //Header - String ALGORITHM = "alg"; - String CONTENT_TYPE = "cty"; - String TYPE = "typ"; - String KEY_ID = "kid"; - - //Payload - String ISSUER = "iss"; - String SUBJECT = "sub"; - String EXPIRES_AT = "exp"; - String NOT_BEFORE = "nbf"; - String ISSUED_AT = "iat"; - String JWT_ID = "jti"; - String AUDIENCE = "aud"; - -} diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 3cccbf7b..b28035f8 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -1,7 +1,6 @@ package com.auth0.jwt; import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.impl.PublicClaims; import com.auth0.jwt.interfaces.ECDSAKeyProvider; import com.auth0.jwt.interfaces.RSAKeyProvider; import com.fasterxml.jackson.databind.ObjectMapper; @@ -92,7 +91,7 @@ public void shouldReturnBuilderIfNullMapIsProvided() { @Test public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { Map header = new HashMap<>(); - header.put(PublicClaims.KEY_ID, "xyz"); + header.put(HeaderParams.KEY_ID, "xyz"); String signed = JWTCreator.init() .withKeyId("abc") @@ -102,13 +101,13 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry(PublicClaims.KEY_ID, "xyz")); + assertThat(headerJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "xyz")); } @Test public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { Map header = new HashMap<>(); - header.put(PublicClaims.KEY_ID, "xyz"); + header.put(HeaderParams.KEY_ID, "xyz"); String signed = JWTCreator.init() .withHeader(header) @@ -118,13 +117,13 @@ public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.hasEntry(PublicClaims.KEY_ID, "abc")); + assertThat(headerJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "abc")); } @Test public void shouldRemoveHeaderIfTheValueIsNull() { Map header = new HashMap<>(); - header.put(PublicClaims.KEY_ID, null); + header.put(HeaderParams.KEY_ID, null); header.put("test2", "isSet"); String signed = JWTCreator.init() @@ -135,7 +134,7 @@ public void shouldRemoveHeaderIfTheValueIsNull() { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); - assertThat(headerJson, JsonMatcher.isNotPresent(PublicClaims.KEY_ID)); + assertThat(headerJson, JsonMatcher.isNotPresent(HeaderParams.KEY_ID)); assertThat(headerJson, JsonMatcher.hasEntry("test2", "isSet")); } @@ -728,7 +727,7 @@ public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() { @Test public void withPayloadShouldOverwriteExistingClaimIfPayloadMapContainsTheSameKey() { Map payload = new HashMap<>(); - payload.put(PublicClaims.KEY_ID, "xyz"); + payload.put(HeaderParams.KEY_ID, "xyz"); String jwt = JWTCreator.init() .withKeyId("abc") @@ -738,13 +737,13 @@ public void withPayloadShouldOverwriteExistingClaimIfPayloadMapContainsTheSameKe assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry(PublicClaims.KEY_ID, "xyz")); + assertThat(payloadJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "xyz")); } @Test public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { Map payload = new HashMap<>(); - payload.put(PublicClaims.ISSUER, "xyz"); + payload.put(StandardClaims.ISSUER, "xyz"); String jwt = JWTCreator.init() .withPayload(payload) @@ -754,7 +753,7 @@ public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry(PublicClaims.ISSUER, "abc")); + assertThat(payloadJson, JsonMatcher.hasEntry(StandardClaims.ISSUER, "abc")); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 5ea2b4ef..82dc895c 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -121,7 +121,7 @@ public void shouldGetSignature() { assertThat(jwt.getSignature(), is("XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); } - // Public PublicClaims + // Standard Claims @Test public void shouldGetIssuer() { @@ -208,7 +208,7 @@ public void shouldGetAlgorithm() { assertThat(jwt.getAlgorithm(), is("HS256")); } - //Private PublicClaims + // Private Claims @Test public void shouldGetMissingClaimIfClaimDoesNotExist() { diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index 958e89fb..b9f56a2e 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -10,8 +10,6 @@ import java.nio.charset.StandardCharsets; import java.security.interfaces.ECKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAKey; import java.time.Clock; import java.time.Instant; @@ -19,8 +17,8 @@ import java.util.Base64; import java.util.Date; -import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; public class JWTTest { @@ -199,7 +197,7 @@ public void shouldAcceptECDSA512Algorithm() throws Exception { } - // Public Claims + // Standard Claims @Test public void shouldGetAlgorithm() { diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 72e5656f..d2715262 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -2,7 +2,6 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.*; -import com.auth0.jwt.impl.PublicClaims; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; @@ -14,7 +13,6 @@ import java.time.Duration; import java.time.Instant; import java.time.ZoneId; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.function.BiPredicate; @@ -92,7 +90,7 @@ public void shouldThrowOnInvalidIssuer() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); - assertThat(e.getClaimName(), is(PublicClaims.ISSUER)); + assertThat(e.getClaimName(), is(StandardClaims.ISSUER)); assertThat(e.getClaimValue().asString(), is("auth0")); } @@ -106,7 +104,7 @@ public void shouldThrowOnNullIssuer() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); - assertThat(e.getClaimName(), is(PublicClaims.ISSUER)); + assertThat(e.getClaimName(), is(StandardClaims.ISSUER)); assertThat(e.getClaimValue().isNull(), is(true)); } @@ -146,7 +144,7 @@ public void shouldThrowOnInvalidSubject() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'sub' value doesn't match the required one.")); - assertThat(e.getClaimName(), is(PublicClaims.SUBJECT)); + assertThat(e.getClaimName(), is(StandardClaims.SUBJECT)); assertThat(e.getClaimValue().asString(), is("1234567890")); } @@ -250,7 +248,7 @@ public void shouldThrowWhenAudienceHasNoneOfExpectedAnyOfAudience() { .verify(tokenArr); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); } @@ -265,7 +263,7 @@ public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); } @@ -280,7 +278,7 @@ public void shouldThrowWhenAudienceClaimIsNull() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); assertThat(e.getClaimValue().isNull(), is(true)); } @@ -308,7 +306,7 @@ public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(PublicClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); assertThat(e.getClaimValue().asArray(String.class), is(new String[] {null})); } @@ -585,9 +583,9 @@ public void shouldAddDefaultLeewayToDateClaims() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(0L)); - assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(0L)); - assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(0L)); + assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(0L)); + assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(0L)); + assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(0L)); } @Test @@ -599,9 +597,9 @@ public void shouldAddCustomLeewayToDateClaims() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(1234L)); } @Test @@ -614,9 +612,9 @@ public void shouldOverrideDefaultIssuedAtLeeway() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(9999L)); - assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(9999L)); + assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(1234L)); } @Test @@ -629,9 +627,9 @@ public void shouldOverrideDefaultExpiresAtLeeway() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(9999L)); - assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(9999L)); + assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(1234L)); } @Test @@ -644,9 +642,9 @@ public void shouldOverrideDefaultNotBeforeLeeway() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(PublicClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(PublicClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(PublicClaims.NOT_BEFORE), is(9999L)); + assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(9999L)); } @Test @@ -727,7 +725,7 @@ public void shouldThrowOnInvalidNotBeforeIfPresent() { .verify(token); }); assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(PublicClaims.NOT_BEFORE)); + assertThat(e.getClaimName(), is(StandardClaims.NOT_BEFORE)); assertThat(e.getClaimValue().asLong(), is(1477592L)); } @@ -762,7 +760,7 @@ public void shouldThrowOnFutureIssuedAt() { assertThat(jwt, is(notNullValue())); }); assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(PublicClaims.ISSUED_AT)); + assertThat(e.getClaimName(), is(StandardClaims.ISSUED_AT)); assertThat(e.getClaimValue().asLong(), is(1477592L)); } @@ -787,7 +785,7 @@ public void shouldThrowOnInvalidIssuedAtIfPresent() { .verify(token); }); assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(PublicClaims.ISSUED_AT)); + assertThat(e.getClaimName(), is(StandardClaims.ISSUED_AT)); assertThat(e.getClaimValue().asLong(), is(1477592L)); } From 5da2806b592daeef57b37e5d5461de6d0ef2bbe9 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Wed, 13 Apr 2022 12:55:40 -0500 Subject: [PATCH 026/134] fix packaging --- lib/src/main/java/{ => com/auth0/jwt}/HeaderParams.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/src/main/java/{ => com/auth0/jwt}/HeaderParams.java (100%) diff --git a/lib/src/main/java/HeaderParams.java b/lib/src/main/java/com/auth0/jwt/HeaderParams.java similarity index 100% rename from lib/src/main/java/HeaderParams.java rename to lib/src/main/java/com/auth0/jwt/HeaderParams.java From 035f323dc4e0c4654c661c050843f521028aec21 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Wed, 13 Apr 2022 13:01:04 -0500 Subject: [PATCH 027/134] Update class names --- .../main/java/com/auth0/jwt/JWTCreator.java | 20 ++++---- .../main/java/com/auth0/jwt/JWTVerifier.java | 42 ++++++++-------- ...ndardClaims.java => RegisteredClaims.java} | 4 +- .../auth0/jwt/impl/PayloadDeserializer.java | 16 +++--- .../com/auth0/jwt/impl/PayloadSerializer.java | 4 +- .../java/com/auth0/jwt/JWTCreatorTest.java | 4 +- .../java/com/auth0/jwt/JWTVerifierTest.java | 50 +++++++++---------- 7 files changed, 70 insertions(+), 70 deletions(-) rename lib/src/main/java/com/auth0/jwt/{StandardClaims.java => RegisteredClaims.java} (94%) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index f0299d22..cab474f7 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -115,7 +115,7 @@ public Builder withKeyId(String keyId) { * @return this same Builder instance. */ public Builder withIssuer(String issuer) { - addClaim(StandardClaims.ISSUER, issuer); + addClaim(RegisteredClaims.ISSUER, issuer); return this; } @@ -126,7 +126,7 @@ public Builder withIssuer(String issuer) { * @return this same Builder instance. */ public Builder withSubject(String subject) { - addClaim(StandardClaims.SUBJECT, subject); + addClaim(RegisteredClaims.SUBJECT, subject); return this; } @@ -137,7 +137,7 @@ public Builder withSubject(String subject) { * @return this same Builder instance. */ public Builder withAudience(String... audience) { - addClaim(StandardClaims.AUDIENCE, audience); + addClaim(RegisteredClaims.AUDIENCE, audience); return this; } @@ -149,7 +149,7 @@ public Builder withAudience(String... audience) { * @return this same Builder instance. */ public Builder withExpiresAt(Date expiresAt) { - addClaim(StandardClaims.EXPIRES_AT, expiresAt); + addClaim(RegisteredClaims.EXPIRES_AT, expiresAt); return this; } @@ -161,7 +161,7 @@ public Builder withExpiresAt(Date expiresAt) { * @return this same Builder instance. */ public Builder withExpiresAt(Instant expiresAt) { - addClaim(StandardClaims.EXPIRES_AT, expiresAt); + addClaim(RegisteredClaims.EXPIRES_AT, expiresAt); return this; } @@ -173,7 +173,7 @@ public Builder withExpiresAt(Instant expiresAt) { * @return this same Builder instance. */ public Builder withNotBefore(Date notBefore) { - addClaim(StandardClaims.NOT_BEFORE, notBefore); + addClaim(RegisteredClaims.NOT_BEFORE, notBefore); return this; } @@ -185,7 +185,7 @@ public Builder withNotBefore(Date notBefore) { * @return this same Builder instance. */ public Builder withNotBefore(Instant notBefore) { - addClaim(StandardClaims.NOT_BEFORE, notBefore); + addClaim(RegisteredClaims.NOT_BEFORE, notBefore); return this; } @@ -197,7 +197,7 @@ public Builder withNotBefore(Instant notBefore) { * @return this same Builder instance. */ public Builder withIssuedAt(Date issuedAt) { - addClaim(StandardClaims.ISSUED_AT, issuedAt); + addClaim(RegisteredClaims.ISSUED_AT, issuedAt); return this; } @@ -209,7 +209,7 @@ public Builder withIssuedAt(Date issuedAt) { * @return this same Builder instance. */ public Builder withIssuedAt(Instant issuedAt) { - addClaim(StandardClaims.ISSUED_AT, issuedAt); + addClaim(RegisteredClaims.ISSUED_AT, issuedAt); return this; } @@ -220,7 +220,7 @@ public Builder withIssuedAt(Instant issuedAt) { * @return this same Builder instance. */ public Builder withJWTId(String jwtId) { - addClaim(StandardClaims.JWT_ID, jwtId); + addClaim(RegisteredClaims.JWT_ID, jwtId); return this; } diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 223de7f5..8b4639ac 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -70,13 +70,13 @@ public static class BaseVerification implements Verification { @Override public Verification withIssuer(String... issuer) { List value = isNullOrEmpty(issuer) ? null : Arrays.asList(issuer); - addCheck(StandardClaims.ISSUER, ((claim, decodedJWT) -> { + addCheck(RegisteredClaims.ISSUER, ((claim, decodedJWT) -> { if (verifyNull(claim, value)) { return true; } if (value == null || !value.contains(claim.asString())) { throw new IncorrectClaimException( - "The Claim 'iss' value doesn't match the required issuer.", StandardClaims.ISSUER, claim); + "The Claim 'iss' value doesn't match the required issuer.", RegisteredClaims.ISSUER, claim); } return true; })); @@ -85,7 +85,7 @@ public Verification withIssuer(String... issuer) { @Override public Verification withSubject(String subject) { - addCheck(StandardClaims.SUBJECT, (claim, decodedJWT) -> + addCheck(RegisteredClaims.SUBJECT, (claim, decodedJWT) -> verifyNull(claim, subject) || subject.equals(claim.asString())); return this; } @@ -93,13 +93,13 @@ public Verification withSubject(String subject) { @Override public Verification withAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - addCheck(StandardClaims.AUDIENCE, ((claim, decodedJWT) -> { + addCheck(RegisteredClaims.AUDIENCE, ((claim, decodedJWT) -> { if (verifyNull(claim, value)) { return true; } if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, true)) { throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", - StandardClaims.AUDIENCE, claim); + RegisteredClaims.AUDIENCE, claim); } return true; })); @@ -109,13 +109,13 @@ public Verification withAudience(String... audience) { @Override public Verification withAnyOfAudience(String... audience) { List value = isNullOrEmpty(audience) ? null : Arrays.asList(audience); - addCheck(StandardClaims.AUDIENCE, ((claim, decodedJWT) -> { + addCheck(RegisteredClaims.AUDIENCE, ((claim, decodedJWT) -> { if (verifyNull(claim, value)) { return true; } if (!assertValidAudienceClaim(decodedJWT.getAudience(), value, false)) { throw new IncorrectClaimException("The Claim 'aud' value doesn't contain the required audience.", - StandardClaims.AUDIENCE, claim); + RegisteredClaims.AUDIENCE, claim); } return true; })); @@ -132,21 +132,21 @@ public Verification acceptLeeway(long leeway) throws IllegalArgumentException { @Override public Verification acceptExpiresAt(long leeway) throws IllegalArgumentException { assertPositive(leeway); - customLeeways.put(StandardClaims.EXPIRES_AT, leeway); + customLeeways.put(RegisteredClaims.EXPIRES_AT, leeway); return this; } @Override public Verification acceptNotBefore(long leeway) throws IllegalArgumentException { assertPositive(leeway); - customLeeways.put(StandardClaims.NOT_BEFORE, leeway); + customLeeways.put(RegisteredClaims.NOT_BEFORE, leeway); return this; } @Override public Verification acceptIssuedAt(long leeway) throws IllegalArgumentException { assertPositive(leeway); - customLeeways.put(StandardClaims.ISSUED_AT, leeway); + customLeeways.put(RegisteredClaims.ISSUED_AT, leeway); return this; } @@ -158,7 +158,7 @@ public Verification ignoreIssuedAt() { @Override public Verification withJWTId(String jwtId) { - addCheck(StandardClaims.JWT_ID, ((claim, decodedJWT) -> + addCheck(RegisteredClaims.JWT_ID, ((claim, decodedJWT) -> verifyNull(claim, jwtId) || jwtId.equals(claim.asString()))); return this; } @@ -296,17 +296,17 @@ public long getLeewayFor(String name) { } private void addMandatoryClaimChecks() { - long expiresAtLeeway = getLeewayFor(StandardClaims.EXPIRES_AT); - long notBeforeLeeway = getLeewayFor(StandardClaims.NOT_BEFORE); - long issuedAtLeeway = getLeewayFor(StandardClaims.ISSUED_AT); - - expectedChecks.add(constructExpectedCheck(StandardClaims.EXPIRES_AT, (claim, decodedJWT) -> - assertValidInstantClaim(StandardClaims.EXPIRES_AT, claim, expiresAtLeeway, true))); - expectedChecks.add(constructExpectedCheck(StandardClaims.NOT_BEFORE, (claim, decodedJWT) -> - assertValidInstantClaim(StandardClaims.NOT_BEFORE, claim, notBeforeLeeway, false))); + long expiresAtLeeway = getLeewayFor(RegisteredClaims.EXPIRES_AT); + long notBeforeLeeway = getLeewayFor(RegisteredClaims.NOT_BEFORE); + long issuedAtLeeway = getLeewayFor(RegisteredClaims.ISSUED_AT); + + expectedChecks.add(constructExpectedCheck(RegisteredClaims.EXPIRES_AT, (claim, decodedJWT) -> + assertValidInstantClaim(RegisteredClaims.EXPIRES_AT, claim, expiresAtLeeway, true))); + expectedChecks.add(constructExpectedCheck(RegisteredClaims.NOT_BEFORE, (claim, decodedJWT) -> + assertValidInstantClaim(RegisteredClaims.NOT_BEFORE, claim, notBeforeLeeway, false))); if (!ignoreIssuedAt) { - expectedChecks.add(constructExpectedCheck(StandardClaims.ISSUED_AT, (claim, decodedJWT) -> - assertValidInstantClaim(StandardClaims.ISSUED_AT, claim, issuedAtLeeway, false))); + expectedChecks.add(constructExpectedCheck(RegisteredClaims.ISSUED_AT, (claim, decodedJWT) -> + assertValidInstantClaim(RegisteredClaims.ISSUED_AT, claim, issuedAtLeeway, false))); } } diff --git a/lib/src/main/java/com/auth0/jwt/StandardClaims.java b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java similarity index 94% rename from lib/src/main/java/com/auth0/jwt/StandardClaims.java rename to lib/src/main/java/com/auth0/jwt/RegisteredClaims.java index 4fe82d64..d60d9fc5 100644 --- a/lib/src/main/java/com/auth0/jwt/StandardClaims.java +++ b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java @@ -4,9 +4,9 @@ * Contains constants representing the name of the Registered Claim Names as defined in Section 4.1.1 of * RFC 7529 */ -public final class StandardClaims { +public final class RegisteredClaims { - private StandardClaims() { + private RegisteredClaims() { } /** diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 4d058826..37e70f7a 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -1,6 +1,6 @@ package com.auth0.jwt.impl; -import com.auth0.jwt.StandardClaims; +import com.auth0.jwt.RegisteredClaims; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.Payload; import com.fasterxml.jackson.core.JsonParser; @@ -44,13 +44,13 @@ public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOE throw new JWTDecodeException("Parsing the Payload's JSON resulted on a Null map"); } - String issuer = getString(tree, StandardClaims.ISSUER); - String subject = getString(tree, StandardClaims.SUBJECT); - List audience = getStringOrArray(tree, StandardClaims.AUDIENCE); - Instant expiresAt = getInstantFromSeconds(tree, StandardClaims.EXPIRES_AT); - Instant notBefore = getInstantFromSeconds(tree, StandardClaims.NOT_BEFORE); - Instant issuedAt = getInstantFromSeconds(tree, StandardClaims.ISSUED_AT); - String jwtId = getString(tree, StandardClaims.JWT_ID); + String issuer = getString(tree, RegisteredClaims.ISSUER); + String subject = getString(tree, RegisteredClaims.SUBJECT); + List audience = getStringOrArray(tree, RegisteredClaims.AUDIENCE); + Instant expiresAt = getInstantFromSeconds(tree, RegisteredClaims.EXPIRES_AT); + Instant notBefore = getInstantFromSeconds(tree, RegisteredClaims.NOT_BEFORE); + Instant issuedAt = getInstantFromSeconds(tree, RegisteredClaims.ISSUED_AT); + String jwtId = getString(tree, RegisteredClaims.JWT_ID); return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, objectReader); } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index 1d2ada43..c8df2bb9 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -1,6 +1,6 @@ package com.auth0.jwt.impl; -import com.auth0.jwt.StandardClaims; +import com.auth0.jwt.RegisteredClaims; import com.fasterxml.jackson.core.JsonGenerator; import java.io.IOException; @@ -23,7 +23,7 @@ public PayloadSerializer() { @Override protected void writeClaim(Map.Entry entry, JsonGenerator gen) throws IOException { - if (StandardClaims.AUDIENCE.equals(entry.getKey())) { + if (RegisteredClaims.AUDIENCE.equals(entry.getKey())) { writeAudience(gen, entry); } else { super.writeClaim(entry, gen); diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index b28035f8..efe6b94b 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -743,7 +743,7 @@ public void withPayloadShouldOverwriteExistingClaimIfPayloadMapContainsTheSameKe @Test public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { Map payload = new HashMap<>(); - payload.put(StandardClaims.ISSUER, "xyz"); + payload.put(RegisteredClaims.ISSUER, "xyz"); String jwt = JWTCreator.init() .withPayload(payload) @@ -753,7 +753,7 @@ public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); - assertThat(payloadJson, JsonMatcher.hasEntry(StandardClaims.ISSUER, "abc")); + assertThat(payloadJson, JsonMatcher.hasEntry(RegisteredClaims.ISSUER, "abc")); } @Test diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index d2715262..6d8ba201 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -90,7 +90,7 @@ public void shouldThrowOnInvalidIssuer() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); - assertThat(e.getClaimName(), is(StandardClaims.ISSUER)); + assertThat(e.getClaimName(), is(RegisteredClaims.ISSUER)); assertThat(e.getClaimValue().asString(), is("auth0")); } @@ -104,7 +104,7 @@ public void shouldThrowOnNullIssuer() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'iss' value doesn't match the required issuer.")); - assertThat(e.getClaimName(), is(StandardClaims.ISSUER)); + assertThat(e.getClaimName(), is(RegisteredClaims.ISSUER)); assertThat(e.getClaimValue().isNull(), is(true)); } @@ -144,7 +144,7 @@ public void shouldThrowOnInvalidSubject() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'sub' value doesn't match the required one.")); - assertThat(e.getClaimName(), is(StandardClaims.SUBJECT)); + assertThat(e.getClaimName(), is(RegisteredClaims.SUBJECT)); assertThat(e.getClaimValue().asString(), is("1234567890")); } @@ -248,7 +248,7 @@ public void shouldThrowWhenAudienceHasNoneOfExpectedAnyOfAudience() { .verify(tokenArr); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); } @@ -263,7 +263,7 @@ public void shouldThrowWhenAudienceClaimDoesNotContainAllExpected() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); assertThat(e.getClaimValue().asArray(String.class), is(new String[] {"Mark","David","John"})); } @@ -278,7 +278,7 @@ public void shouldThrowWhenAudienceClaimIsNull() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); assertThat(e.getClaimValue().isNull(), is(true)); } @@ -306,7 +306,7 @@ public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { .verify(token); }); assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); - assertThat(e.getClaimName(), is(StandardClaims.AUDIENCE)); + assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); assertThat(e.getClaimValue().asArray(String.class), is(new String[] {null})); } @@ -583,9 +583,9 @@ public void shouldAddDefaultLeewayToDateClaims() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(0L)); - assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(0L)); - assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(0L)); + assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(0L)); + assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(0L)); + assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(0L)); } @Test @@ -597,9 +597,9 @@ public void shouldAddCustomLeewayToDateClaims() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(1234L)); } @Test @@ -612,9 +612,9 @@ public void shouldOverrideDefaultIssuedAtLeeway() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(9999L)); - assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(9999L)); + assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(1234L)); } @Test @@ -627,9 +627,9 @@ public void shouldOverrideDefaultExpiresAtLeeway() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(9999L)); - assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(9999L)); + assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(1234L)); } @Test @@ -642,9 +642,9 @@ public void shouldOverrideDefaultNotBeforeLeeway() { .build(); assertThat(verifier.expectedChecks, is(notNullValue())); - assertThat(verification.getLeewayFor(StandardClaims.ISSUED_AT), is(1234L)); - assertThat(verification.getLeewayFor(StandardClaims.EXPIRES_AT), is(1234L)); - assertThat(verification.getLeewayFor(StandardClaims.NOT_BEFORE), is(9999L)); + assertThat(verification.getLeewayFor(RegisteredClaims.ISSUED_AT), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.EXPIRES_AT), is(1234L)); + assertThat(verification.getLeewayFor(RegisteredClaims.NOT_BEFORE), is(9999L)); } @Test @@ -725,7 +725,7 @@ public void shouldThrowOnInvalidNotBeforeIfPresent() { .verify(token); }); assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(StandardClaims.NOT_BEFORE)); + assertThat(e.getClaimName(), is(RegisteredClaims.NOT_BEFORE)); assertThat(e.getClaimValue().asLong(), is(1477592L)); } @@ -760,7 +760,7 @@ public void shouldThrowOnFutureIssuedAt() { assertThat(jwt, is(notNullValue())); }); assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(StandardClaims.ISSUED_AT)); + assertThat(e.getClaimName(), is(RegisteredClaims.ISSUED_AT)); assertThat(e.getClaimValue().asLong(), is(1477592L)); } @@ -785,7 +785,7 @@ public void shouldThrowOnInvalidIssuedAtIfPresent() { .verify(token); }); assertThat(e.getMessage(), is("The Token can't be used before 1970-01-18T02:26:32Z.")); - assertThat(e.getClaimName(), is(StandardClaims.ISSUED_AT)); + assertThat(e.getClaimName(), is(RegisteredClaims.ISSUED_AT)); assertThat(e.getClaimValue().asLong(), is(1477592L)); } From 537f9863b8d3297d7aa7660094a690e5909afdf8 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 14 Apr 2022 16:32:58 -0400 Subject: [PATCH 028/134] Add Semgrep to continuous integration tests This PR updates the CircleCI workflow for v4 to add Semgrep automated security testing to the continuous integration tests. --- .circleci/config.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a299cb9d..14f9652e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,11 +53,26 @@ jobs: # GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' # _JAVA_OPTIONS: "-Xms512m -Xmx1024m" # TERM: dumb + semgrep: + docker: + - image: returntocorp/semgrep-agent:v1 + environment: + SEMGREP_REPO_NAME: "auth0/java-jwt" + SEMGREP_REPO_URL: "https://github.com/auth0/java-jwt" + steps: + - checkout + - run: + name: Run vulnerabilities tests (Semgrep) + command: | + semgrep-agent --baseline-ref v4-dev --publish-token $SEMGREP_TOKEN workflows: build-and-test: jobs: - build + - semgrep: + context: + - semgrep-env # api-diff: # jobs: -# - api-diff \ No newline at end of file +# - api-diff From 54d97c68ad2e4b57aa21dea6bc3ed6cec0c0479d Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Thu, 14 Apr 2022 16:34:15 -0400 Subject: [PATCH 029/134] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 14f9652e..f47d6efa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -64,7 +64,7 @@ jobs: - run: name: Run vulnerabilities tests (Semgrep) command: | - semgrep-agent --baseline-ref v4-dev --publish-token $SEMGREP_TOKEN + semgrep-agent --baseline-ref master --publish-token $SEMGREP_TOKEN workflows: build-and-test: From 5d8776d7e3d14f9d454404813ae0656c3a8edf2d Mon Sep 17 00:00:00 2001 From: James Anderson Date: Mon, 18 Apr 2022 17:04:19 -0500 Subject: [PATCH 030/134] [SDK-3244] Add Migration Guide --- MIGRATION_GUIDE.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 MIGRATION_GUIDE.md diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 00000000..1f95f323 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,84 @@ +# Migration Guide + +## Upgrading from v3.x -> v4.0 + +The version 4 release contains several improvements: + +- Support for `java.time.Instant` when creating or verifying JWTs with Numeric Date claim values. +- Improvements to JWT claim validation, including support for custom claim validation using Predicates. +- Improved exception handling when validating JWTs, to better inform of the reason for failed validation. +- Consistent handling of `null` claim values both when creating and validation JWTs. + +This guide captures the changes you should be aware of when planning and upgrading to version 4. + +### Compile or runtime breaking changes + +**Classes or methods removed:** +- The `impl` package has been removed as an export in `module-info.java`. This package contains implementation-specific code that may change at any point. +- Support for the ES256K algorithm has been removed, as it is disabled in Java 15+. The `Algorithm#ECDSA256K(ECDSAKeyProvider keyProvider)` and `Algorithm#ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey)` methods have been removed. +- `com.auth0.jwt.interfaces.Clock` has been removed. Instead, an implementation of `java.time.Clock` can be passed to the `BaseVerification` for testing purposes. +- `com.auth0.jwt.impl.NullClaim` has been removed. `Claim#isNull` can be used to determine if a claim's value is `null`. +- `com.auth0.jwt.impl.PublicClaims` was removed, and replaced by `com.auth0.jwt.StandardClaims` and `com.auth0.jwt.HeaderParams`. + +### Behavioral potentially breaking changes + +#### JWT creation + +- All date/time claim values are now serialized as **seconds since the epoch**, in both the payload and header. In version 3, date/time claims nested in a list or map, as well as any header parameters with date/time values, were serialized as milliseconds since the epoch. +- When creating a JWT, passing `null` as the value no longer removes the claim if it was previously added to the builder. It now adds the claim with a `null` value. + +#### JWT validation + +- In version 3, specifying multiple claim expectations for the same claim name would override any previous expectations for that claim. In version 4, all expectations for that claim will be validated. +- In version 3, passing `null` for the value of a claim expectation would remove that expectation from the validation. In version 4, passing `null` does not remove that expectation, but instead validates that the claim has the literal value `null`. +- When validating a JWT, if an expected claim is present in the JWT but contains a value different from the one expected, an `IncorrectClaimException` (subclass of `InvalidClaimException`) will now be thrown instead of an `InvalidClaimException`. +- When validating a JWT, if an expected claim is not present in the JWT, an `MissingClaimException` (subclass of `InvalidClaimException`) will now be thrown instead of an `InvalidClaimException`. +- `withClaimPresence(String claimName)` now validates that the claim is present in the JWT, and a claim with a `null` value is considered present. Previously, a claim with a value of `null` would be considered as missing and fail the validation. +- When validating a date/time claim value, the validation no longer checks for strict equality of the claim's value and the provided `Date` (or `Instant`). Instead, the expected `Date` or `Instant` will be compared to the claim's value only considering seconds (because JWT date/time claims are represented as seconds since the epoch). + +#### Claim changes + +- `com.auth0.jwt.interfaces.Claim#isNull()` now returns true only if the claim is present and its value is `null`. Previously, it returned true if the claim was present and its value was `null`, or if the claim was not present in the JWT. To check if the claim is present or not in the JWT, use `isMissing()`. + +### New classes or methods + +#### `IncorrectClaimException` added + +This class extends `InvalidClaimException` and represents that when validating a JWT, an expected claim exists in the JWT but does not match the expected value. + +#### `MissingClaimException` added + +This class extends `InvalidClaimException` and represents that when validating a JWT, an expected claim is missing from the JWT. + +### `HeaderParams` added + +This class contains constants representing common header parameter names. + +### `StandardClaims` added + +This class contains constants representing the standard claim names. + +#### `JWTCreator` new methods + +- `JWTCreator.Builder#withExpiresAt(Instant expiresAt)` - adds the `exp` claim to the JWT from a `java.time.Instant`. +- `JWTCreator.Builder#withNotBefore(Instant notBefore)` - adds the `nbf` claim to the JWT from a `java.time.Instant`. +- `JWTCreator.Builder#withIssuedAt(Instant issuedAt)` - adds the `iat` claim to the JWT from a `java.time.Instant`. +- `JWTCreator.Builder#withClaim(String claimName, Instant value)` - adds a claim to the JWT from a `java.time.Instant`. +- `JWTCreator.Builder#withNullClaim(String claimName)` - adds a claim to the JWT with the literal value `null`. + +#### `DecodedJWT` new methods + +- `Instant getExpiresAtAsInstant()` - Returns a JWT's `exp` claim as a `java.time.Instant`. +- `Instant getNotBeforeAsInstant()` - Returns a JWT's `nbf` claim as a `java.time.Instant`. +- `Instant getIssuedAtAsInstant()` - Returns a JWT's `iat` claim as a `java.time.Instant`. + +#### `Claim` new methods + +- `Instant asInstant()` - Gets a claim as a `java.time.Instant`. +- `boolean isMissing()` - Returns whether the claim is present or not. + +#### `Verification` new methods + +- `Verification withClaim(String name, Instant value)` - Adds an expectation that a claim with the provided name has a value equal to the provided `java.time.Instant`. +- `Verification withClaim(String name, BiPredicate predicate)` - Allows for a claim to be validated with the supplied predicate. +- `Verification withNullClaim(String name)` - Adds an expectation that a claim with the provided name has a value equal to the literal `null`. From e6565cecb1049c43f5dee0df5a0d545cc369c74e Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 20 Apr 2022 19:05:43 +0530 Subject: [PATCH 031/134] JavaDoc updated --- .../main/java/com/auth0/jwt/HeaderParams.java | 4 +- lib/src/main/java/com/auth0/jwt/JWT.java | 8 +- .../main/java/com/auth0/jwt/JWTCreator.java | 2 + .../main/java/com/auth0/jwt/JWTVerifier.java | 4 +- .../java/com/auth0/jwt/RegisteredClaims.java | 9 +- .../com/auth0/jwt/impl/PayloadSerializer.java | 2 - .../java/com/auth0/jwt/interfaces/Claim.java | 20 ++-- .../java/com/auth0/jwt/interfaces/Header.java | 4 +- .../auth0/jwt/interfaces/JWTPartsParser.java | 6 +- .../com/auth0/jwt/interfaces/JWTVerifier.java | 4 +- .../com/auth0/jwt/interfaces/Payload.java | 6 +- .../auth0/jwt/interfaces/Verification.java | 100 ++++++++---------- .../jwt/interfaces/VerificationTest.java | 5 + 13 files changed, 89 insertions(+), 85 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/HeaderParams.java b/lib/src/main/java/com/auth0/jwt/HeaderParams.java index e15877a2..7af3c442 100644 --- a/lib/src/main/java/com/auth0/jwt/HeaderParams.java +++ b/lib/src/main/java/com/auth0/jwt/HeaderParams.java @@ -13,12 +13,12 @@ private HeaderParams() {} public static String ALGORITHM = "alg"; /** - * The content type of a JWT. + * The content type of the JWT. */ public static String CONTENT_TYPE = "cty"; /** - * The media type of a JWT. + * The media type of the JWT. */ public static String TYPE = "typ"; diff --git a/lib/src/main/java/com/auth0/jwt/JWT.java b/lib/src/main/java/com/auth0/jwt/JWT.java index 9d719d1e..696abe40 100644 --- a/lib/src/main/java/com/auth0/jwt/JWT.java +++ b/lib/src/main/java/com/auth0/jwt/JWT.java @@ -26,7 +26,7 @@ public JWT() { * Decode a given Json Web Token. *

* Note that this method doesn't verify the token's signature! - * Use it only if you trust the token or you already verified it. + * Use it only if you trust the token or if you have already verified it. * * @param token with jwt format as string. * @return a decoded JWT. @@ -41,7 +41,7 @@ public DecodedJWT decodeJwt(String token) throws JWTDecodeException { * Decode a given Json Web Token. *

* Note that this method doesn't verify the token's signature! - * Use it only if you trust the token or you already verified it. + * Use it only if you trust the token or if you have already verified it. * * @param token with jwt format as string. * @return a decoded JWT. @@ -53,10 +53,10 @@ public static DecodedJWT decode(String token) throws JWTDecodeException { } /** - * Returns a {@link JWTVerifier} builder with the algorithm to be used to validate token signature. + * Returns a {@link Verification} builder with the algorithm to be used to validate token signature. * * @param algorithm that will be used to verify the token's signature. - * @return {@link JWTVerifier} builder + * @return {@link Verification} builder * @throws IllegalArgumentException if the provided algorithm is null. */ public static Verification require(Algorithm algorithm) { diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index cab474f7..25624982 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -19,6 +19,8 @@ * from a given Header and Payload content. *

* This class is thread-safe. + * + * TODO Poovam - Should we claim thread safety since KeyProvider implementation can cause signing differ */ @SuppressWarnings("WeakerAccess") public final class JWTCreator { diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 8b4639ac..0bc17fb1 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -35,10 +35,10 @@ public final class JWTVerifier implements com.auth0.jwt.interfaces.JWTVerifier { } /** - * Initialize a JWTVerifier instance using the given Algorithm. + * Initialize a {@link Verification} instance using the given Algorithm. * * @param algorithm the Algorithm to use on the JWT verification. - * @return a JWTVerifier.Verification instance to configure. + * @return a {@link Verification} instance to configure. * @throws IllegalArgumentException if the provided algorithm is null. */ static Verification init(Algorithm algorithm) throws IllegalArgumentException { diff --git a/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java index d60d9fc5..8c47eb51 100644 --- a/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java +++ b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java @@ -1,7 +1,7 @@ package com.auth0.jwt; /** - * Contains constants representing the name of the Registered Claim Names as defined in Section 4.1.1 of + * Contains constants representing the name of the Registered Claim Names as defined in Section 4.1 of * RFC 7529 */ public final class RegisteredClaims { @@ -11,37 +11,44 @@ private RegisteredClaims() { /** * The "iss" (issuer) claim identifies the principal that issued the JWT. + * Refer RFC 7529 Section 4.1.1 */ public static String ISSUER = "iss"; /** * The "sub" (subject) claim identifies the principal that is the subject of the JWT. + * Refer RFC 7529 Section 4.1.2 */ public static String SUBJECT = "sub"; /** * The "aud" (audience) claim identifies the recipients that the JWT is intended for. + * Refer RFC 7529 Section 4.1.3 */ public static String AUDIENCE = "aud"; /** * The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be * accepted for processing. + * Refer RFC 7529 Section 4.1.4 */ public static String EXPIRES_AT = "exp"; /** * The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. + * Refer RFC 7529 Section 4.1.5 */ public static String NOT_BEFORE = "nbf"; /** * The "iat" (issued at) claim identifies the time at which the JWT was issued. + * Refer RFC 7529 Section 4.1.6 */ public static String ISSUED_AT = "iat"; /** * The "jti" (JWT ID) claim provides a unique identifier for the JWT. + * Refer RFC 7529 Section 4.1.7 */ public static String JWT_ID = "jti"; diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index c8df2bb9..24fe37b7 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -34,8 +34,6 @@ protected void writeClaim(Map.Entry entry, JsonGenerator gen) th * Audience may be a list of strings or a single string. This is needed to properly handle the aud claim when * added with the {@linkplain com.auth0.jwt.JWTCreator.Builder#withPayload(Map)} method. */ - - // private void writeAudience(JsonGenerator gen, Map.Entry e) throws IOException { if (e.getValue() instanceof String) { gen.writeFieldName(e.getKey()); diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java index f6ccfdcd..7c4da4f7 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java @@ -22,7 +22,7 @@ public interface Claim { /** * Can be used to verify whether the Claim is found or not. - * This will be true even if the Claim has null value associated to it. + * This will be true even if the Claim has {@code null} value associated to it. * * @return whether this Claim is present or not */ @@ -30,7 +30,7 @@ public interface Claim { /** * Get this Claim as a Boolean. - * If the value isn't of type Boolean or it can't be converted to a Boolean, null will be returned. + * If the value isn't of type Boolean or it can't be converted to a Boolean, {@code null} will be returned. * * @return the value as a Boolean or null. */ @@ -38,7 +38,7 @@ public interface Claim { /** * Get this Claim as an Integer. - * If the value isn't of type Integer or it can't be converted to an Integer, null will be returned. + * If the value isn't of type Integer or it can't be converted to an Integer, {@code null} will be returned. * * @return the value as an Integer or null. */ @@ -46,7 +46,7 @@ public interface Claim { /** * Get this Claim as an Long. - * If the value isn't of type Long or it can't be converted to an Long, null will be returned. + * If the value isn't of type Long or it can't be converted to a Long, {@code null} will be returned. * * @return the value as an Long or null. */ @@ -54,7 +54,7 @@ public interface Claim { /** * Get this Claim as a Double. - * If the value isn't of type Double or it can't be converted to a Double, null will be returned. + * If the value isn't of type Double or it can't be converted to a Double, {@code null} will be returned. * * @return the value as a Double or null. */ @@ -62,7 +62,7 @@ public interface Claim { /** * Get this Claim as a String. - * If the value isn't of type String or it can't be converted to a String, null will be returned. + * If the value isn't of type String or it can't be converted to a String, {@code null} will be returned. * * @return the value as a String or null. */ @@ -70,7 +70,7 @@ public interface Claim { /** * Get this Claim as a Date. - * If the value can't be converted to a Date, null will be returned. + * If the value can't be converted to a Date, {@code null} will be returned. * * @return the value as a Date or null. */ @@ -78,7 +78,7 @@ public interface Claim { /** * Get this Claim as an Instant. - * If the value can't be converted to an Instant, null will be returned. + * If the value can't be converted to an Instant, {@code null} will be returned. * * @return the value as a Date or null. */ @@ -89,7 +89,7 @@ default Instant asInstant() { /** * Get this Claim as an Array of type T. - * If the value isn't an Array, null will be returned. + * If the value isn't an Array, {@code null} will be returned. * * @param type * @param clazz the type class @@ -100,7 +100,7 @@ default Instant asInstant() { /** * Get this Claim as a List of type T. - * If the value isn't an Array, null will be returned. + * If the value isn't an Array, {@code null} will be returned. * * @param type * @param clazz the type class diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Header.java b/lib/src/main/java/com/auth0/jwt/interfaces/Header.java index 030643d0..52b3ba56 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Header.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Header.java @@ -1,7 +1,7 @@ package com.auth0.jwt.interfaces; /** - * The Header class represents the 1st part of the JWT, where the Header value is hold. + * The Header class represents the 1st part of the JWT, where the Header value is held. */ public interface Header { @@ -35,7 +35,7 @@ public interface Header { /** * Get a Private Claim given it's name. If the Claim wasn't specified in the Header, a 'null claim' will be - * returned. All of the methods of that claim will return {@code null}. + * returned. All the methods of that claim will return {@code null}. * * @param name the name of the Claim to retrieve. * @return a non-null Claim. diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java index e1c6efcc..33cd0d70 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java @@ -4,12 +4,12 @@ /** * The JWTPartsParser class defines which parts of the JWT should be converted - * to it's specific Object representation instance. + * to its specific Object representation instance. */ public interface JWTPartsParser { /** - * Parses the given JSON into a Payload instance. + * Parses the given JSON into a {@link Payload} instance. * * @param json the content of the Payload in a JSON representation. * @return the Payload. @@ -18,7 +18,7 @@ public interface JWTPartsParser { Payload parsePayload(String json) throws JWTDecodeException; /** - * Parses the given JSON into a Header instance. + * Parses the given JSON into a {@link Header} instance. * * @param json the content of the Header in a JSON representation. * @return the Header. diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java index 3555878e..b7030a97 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java @@ -4,7 +4,7 @@ /** - * Used to verify the JWT for it's signature and claims. + * Used to verify the JWT for its signature and claims. */ public interface JWTVerifier { @@ -18,7 +18,7 @@ public interface JWTVerifier { DecodedJWT verify(String token) throws JWTVerificationException; /** - * Performs the verification against the given decoded JWT. + * Performs the verification against the given {@link DecodedJWT}. * * @param jwt to verify. * @return a verified and decoded JWT. diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java index b3bf71f5..feb58c64 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java @@ -6,7 +6,7 @@ import java.util.Map; /** - * The Payload class represents the 2nd part of the JWT, where the Payload value is hold. + * The Payload class represents the 2nd part of the JWT, where the Payload value is held. */ public interface Payload { @@ -87,8 +87,8 @@ default Instant getIssuedAtAsInstant() { String getId(); /** - * Get a Claim given it's name. If the Claim wasn't specified in the Payload, a 'null claim' - * will be returned. All of the methods of that claim will return {@code null}. + * Get a Claim given its name. If the Claim wasn't specified in the Payload, a 'null claim' + * will be returned. All the methods of that claim will return {@code null}. * * @param name the name of the Claim to retrieve. * @return a non-null Claim. diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index 8b0416dc..4a8a0f84 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -7,12 +7,13 @@ import java.util.function.BiPredicate; /** - * Holds the Claims and claim-based configurations required for a JWT to be considered valid. + * Constructs and holds the checks required for a JWT to be considered valid. */ public interface Verification { /** - * Require a specific Issuer ("iss") claim. + * Verifies whether the JWT contains an Issuer ("iss") claim that equals to the value provided. + * This check is case-sensitive. * * @param issuer the required Issuer value. * @return this same Verification instance. @@ -22,7 +23,8 @@ default Verification withIssuer(String issuer) { } /** - * Require a specific Issuer ("iss") claim. + * Verifies whether the JWT contains an Issuer ("iss") claim that contains all the values provided. + * This check is case-sensitive. An empty array is considered as a {@code null}. * * @param issuer the required Issuer value. If multiple values are given, the claim must at least match one of them * @return this same Verification instance. @@ -30,7 +32,8 @@ default Verification withIssuer(String issuer) { Verification withIssuer(String... issuer); /** - * Require a specific Subject ("sub") claim. + * Verifies whether the JWT contains a Subject ("sub") claim that equals to the value provided. + * This check is case-sensitive. * * @param subject the required Subject value * @return this same Verification instance. @@ -38,11 +41,8 @@ default Verification withIssuer(String issuer) { Verification withSubject(String subject); /** - * Require a specific Audience ("aud") claim. If multiple audiences are specified, they must all be present - * in the "aud" claim. - * - * If this is used in conjunction with {@link #withAnyOfAudience(String...)}, whichever one is configured last will - * determine the audience validation behavior. + * Verifies whether the JWT contains an Audience ("aud") claim that contains all the values provided. + * This check is case-sensitive. An empty array is considered as a {@code null}. * * @param audience the required Audience value * @return this same Verification instance. @@ -50,24 +50,13 @@ default Verification withIssuer(String issuer) { Verification withAudience(String... audience); /** - * Require that the Audience ("aud") claim contain at least one of the specified audiences. - * - * If this is used in conjunction with {@link #withAudience(String...)}, whichever one is configured last will - * determine the audience validation behavior. - * - * Note: This method was added after the interface was released. - * It is defined as a default method for compatibility reasons. - * From version 4.0 on, the method will be abstract and all implementations of this interface - * will have to provide their own implementation. - * - * The default implementation throws an {@linkplain UnsupportedOperationException}. + * Verifies whether the JWT contains an Audience ("aud") claim contain at least one of the specified audiences. + * This check is case-sensitive. An empty array is considered as a {@code null}. * * @param audience the required Audience value for which the "aud" claim must contain at least one value. * @return this same Verification instance. */ - default Verification withAnyOfAudience(String... audience) { - throw new UnsupportedOperationException("withAnyOfAudience"); - } + Verification withAnyOfAudience(String... audience); /** * Define the default window in seconds in which the Not Before, Issued At and Expires At Claims @@ -116,149 +105,152 @@ default Verification withAnyOfAudience(String... audience) { Verification acceptIssuedAt(long leeway) throws IllegalArgumentException; /** - * Require a specific JWT Id ("jti") claim. + * Verifies whether the JWT contains a JWT ID ("jti") claim that equals to the value provided. + * This check is case-sensitive. * - * @param jwtId the required Id value + * @param jwtId the required ID value * @return this same Verification instance. */ Verification withJWTId(String jwtId); /** - * Require a claim to be present, with any value. + * Verifies whether the claim is present in the JWT, with any value including {@code null}. * * @param name the Claim's name. * @return this same Verification instance - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaimPresence(String name) throws IllegalArgumentException; /** - * Require a specific Claim value to be null. + * Verifies whether the claim is present with a {@code null} value. * * @param name the Claim's name. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withNullClaim(String name) throws IllegalArgumentException; /** - * Require a specific Claim value. + * Verifies whether the claim is equal to the given Boolean value. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, Boolean value) throws IllegalArgumentException; /** - * Require a specific Claim value. + * Verifies whether the claim is equal to the given Integer value. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, Integer value) throws IllegalArgumentException; /** - * Require a specific Claim value. + * Verifies whether the claim is equal to the given Long value. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, Long value) throws IllegalArgumentException; /** - * Require a specific Claim value. + * Verifies whether the claim is equal to the given Integer value. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, Double value) throws IllegalArgumentException; /** - * Require a specific Claim value. + * Verifies whether the claim is equal to the given String value. + * This check is case-sensitive. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, String value) throws IllegalArgumentException; /** - * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; + * Verifies whether the claim is equal to the given Date value. + * Note that date-time claims are serialized as seconds since the epoch; * when verifying date-time claim value, any time units more granular than seconds will not be considered. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, Date value) throws IllegalArgumentException; /** - * Require a specific Claim value. Note that date-time claims are serialized as seconds since the epoch; + * Verifies whether the claim is equal to the given Instant value. + * Note that date-time claims are serialized as seconds since the epoch; * when verifying a date-time claim value, any time units more granular than seconds will not be considered. * * @param name the Claim's name. * @param value the Claim's value. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ default Verification withClaim(String name, Instant value) throws IllegalArgumentException { return withClaim(name, value != null ? Date.from(value) : null); } /** - * Executes the predicate provided during the verification - * and passes the verification if the predicate returns true. + * Executes the predicate provided and the validates the JWT if the predicate returns true. * * @param name the Claim's name * @param predicate the predicate check to be done. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withClaim(String name, BiPredicate predicate) throws IllegalArgumentException; /** - * Require a specific Array Claim to contain at least the given items. + * Verifies whether the claim contain at least the given String items. * * @param name the Claim's name. * @param items the items the Claim must contain. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withArrayClaim(String name, String... items) throws IllegalArgumentException; /** - * Require a specific Array Claim to contain at least the given items. + * Verifies whether the claim contain at least the given Integer items. * * @param name the Claim's name. * @param items the items the Claim must contain. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException; /** - * Require a specific Array Claim to contain at least the given items. + * Verifies whether the claim contain at least the given Long items. * * @param name the Claim's name. * @param items the items the Claim must contain. * @return this same Verification instance. - * @throws IllegalArgumentException if the name is null. + * @throws IllegalArgumentException if the name is {@code null}. */ Verification withArrayClaim(String name, Long ... items) throws IllegalArgumentException; /** - * Skip the Issued At ("iat") date verification. By default, the verification is performed. + * Skip the Issued At ("iat") claim verification. By default, the verification is performed. * * @return this same Verification instance. */ @@ -267,7 +259,7 @@ default Verification withClaim(String name, Instant value) throws IllegalArgumen /** * Creates a new and reusable instance of the JWTVerifier with the configuration already provided. * - * @return a new JWTVerifier instance. + * @return a new {@link com.auth0.jwt.interfaces.JWTVerifier} instance. */ JWTVerifier build(); } diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java index fb0c74a9..bdbd688a 100644 --- a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java +++ b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java @@ -74,6 +74,11 @@ public Verification withAudience(String... audience) { return null; } + @Override + public Verification withAnyOfAudience(String... audience) { + return null; + } + @Override public Verification acceptLeeway(long leeway) throws IllegalArgumentException { return null; From 1979b95f272cc4bffda318a7db097bbed66a5d82 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 20 Apr 2022 19:45:09 +0530 Subject: [PATCH 032/134] Removed test for default audience claim check --- .../java/com/auth0/jwt/interfaces/VerificationTest.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java index bdbd688a..11acb029 100644 --- a/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java +++ b/lib/src/test/java/com/auth0/jwt/interfaces/VerificationTest.java @@ -38,13 +38,6 @@ public void withInstantClaimShouldUseDefaultImplAndHandleNull() { assertThat(((VerificationImplForTest)verification).expectedClaims, hasEntry("name", null)); } - @Test - public void withAnyOfAudienceDeafultImplShouldThrow() { - assertThrows("withAnyOfAudience", UnsupportedOperationException.class, () -> { - new VerificationImplForTest().withAnyOfAudience(""); - }); - } - @Test public void withIssuerStringDefaultImplShouldDelegate() { Verification verification = new VerificationImplForTest() From fef52cc0bd7b1039436ebe09abbe569123812b02 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Wed, 20 Apr 2022 17:27:14 -0500 Subject: [PATCH 033/134] Formatting fixes --- MIGRATION_GUIDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 1f95f323..7105742d 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -50,11 +50,11 @@ This class extends `InvalidClaimException` and represents that when validating a This class extends `InvalidClaimException` and represents that when validating a JWT, an expected claim is missing from the JWT. -### `HeaderParams` added +#### `HeaderParams` added This class contains constants representing common header parameter names. -### `StandardClaims` added +#### `StandardClaims` added This class contains constants representing the standard claim names. From 3f939842f1d0c6c393b9fd6d2365fa2e45d986cc Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Thu, 21 Apr 2022 18:49:01 +0530 Subject: [PATCH 034/134] Added note on Keyprovider --- lib/src/main/java/com/auth0/jwt/JWTCreator.java | 2 -- lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index 25624982..cab474f7 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -19,8 +19,6 @@ * from a given Header and Payload content. *

* This class is thread-safe. - * - * TODO Poovam - Should we claim thread safety since KeyProvider implementation can cause signing differ */ @SuppressWarnings("WeakerAccess") public final class JWTCreator { diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java index fd8baea5..30a144a6 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java @@ -5,6 +5,7 @@ /** * Generic Public/Private Key provider. + * While implementing, ensure the Private Key and Private Key ID doesn't change in between signing a token. * * @param the class that represents the Public Key * @param the class that represents the Private Key From 0d3864da70b1831d4a923450d41cd784ba181c91 Mon Sep 17 00:00:00 2001 From: James Anderson Date: Thu, 21 Apr 2022 10:31:43 -0500 Subject: [PATCH 035/134] updates from PR review --- MIGRATION_GUIDE.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 7105742d..c47b95c2 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -18,7 +18,8 @@ This guide captures the changes you should be aware of when planning and upgradi - Support for the ES256K algorithm has been removed, as it is disabled in Java 15+. The `Algorithm#ECDSA256K(ECDSAKeyProvider keyProvider)` and `Algorithm#ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey)` methods have been removed. - `com.auth0.jwt.interfaces.Clock` has been removed. Instead, an implementation of `java.time.Clock` can be passed to the `BaseVerification` for testing purposes. - `com.auth0.jwt.impl.NullClaim` has been removed. `Claim#isNull` can be used to determine if a claim's value is `null`. -- `com.auth0.jwt.impl.PublicClaims` was removed, and replaced by `com.auth0.jwt.StandardClaims` and `com.auth0.jwt.HeaderParams`. +- `com.auth0.jwt.impl.PublicClaims` was removed, and replaced by `com.auth0.jwt.RegisteredClaims` and `com.auth0.jwt.HeaderParams`. +- `com.auth0.jwt.interfaces.Verification#withAnyOfAudience` no longer provides a default implementation. ### Behavioral potentially breaking changes @@ -54,9 +55,9 @@ This class extends `InvalidClaimException` and represents that when validating a This class contains constants representing common header parameter names. -#### `StandardClaims` added +#### `RegisteredClaims` added -This class contains constants representing the standard claim names. +This class contains constants representing the registered claim names. #### `JWTCreator` new methods From b6a9a034b3ceac2e644308e376c0f48aefdcc6da Mon Sep 17 00:00:00 2001 From: James Anderson Date: Mon, 25 Apr 2022 19:31:01 -0500 Subject: [PATCH 036/134] Documentation updates --- .codecov.yml | 1 + README.md | 39 ++++++++++++++++--- .../main/java/com/auth0/jwt/JWTCreator.java | 2 +- .../java/com/auth0/jwt/JWTCreatorTest.java | 6 +-- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 51f857af..de278af2 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -11,5 +11,6 @@ coverage: project: default: target: auto + threshold: 1% if_no_uploads: error comment: false \ No newline at end of file diff --git a/README.md b/README.md index 065899f1..624a7f68 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,15 @@ A Java implementation of [JSON Web Token (JWT) - RFC 7519](https://tools.ietf.or If you're looking for an **Android** version of the JWT Decoder take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library. -> This library requires Java 8 or higher. The last version that supported Java 7 was 3.11.0. +> You are viewing the documentation for the v4 beta release. For the latest stable release, please see the [version 3.x documentation](https://github.com/auth0/java-jwt). ## Table of Contents +- [**Requirements**](#requirements) - [**Installation**](#installation) - [**Available Algorithms**](#available-algorithms) - [**Quickstart**](#quickstart) + [**Create and Sign a Token**](#create-and-sign-a-token) + [**Verify a Token**](#verify-a-token) - + [**Decode a Token**](#decode-a-token) - [**Usage**](#usage) + [**Pick the algorithm**](#pick-the-algorithm) + [**Time Validation**](#time-validation) @@ -28,6 +28,10 @@ If you're looking for an **Android** version of the JWT Decoder take a look at o + [**Claim Class**](#claim-class) - [**Javadoc**](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html) +## Requirements + +This library is supported for Java 8, 11, and 17. For issues on non-LTS versions above 8, consideration will be given on a case-by-case basis. + ## Installation ### Gradle @@ -138,8 +142,13 @@ You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` If the token has an invalid signature or the Claim requirement is not met, a `JWTVerificationException` will raise. +

+Need to peek into a JWT without verifying it? (Click to expand) + ### Decode a Token +> __Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `JWTVerifier` as documented above instead. + ```java String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { @@ -151,6 +160,8 @@ try { If the token has an invalid syntax or the header or payload are not JSONs, a `JWTDecodeException` will raise. +
+ ## Usage ### Pick the Algorithm @@ -176,7 +187,7 @@ Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); ##### HMAC Key Length and Security -When using a Hash-based Message Authenticaton Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recomendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. +When using a Hash-based Message Authenticaton Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recommendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. #### Using a KeyProvider: By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: @@ -243,13 +254,13 @@ JWTVerifier verifier = JWT.require(algorithm) .build(); ``` -If you need to test this behaviour in your lib/app cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a custom `Clock`. e.g.: +If you need to test this behavior in your lib/app cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a `java.time.Clock`. e.g.: ```java BaseVerification verification = (BaseVerification) JWT.require(algorithm) .acceptLeeway(1) .acceptExpiresAt(5); -Clock clock = new CustomClock(); //Must implement Clock interface +private final Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); JWTVerifier verifier = verification.build(clock); ``` @@ -342,6 +353,12 @@ Returns the Expiration Time value or null if it's not defined in the Payload. Date expiresAt = jwt.getExpiresAt(); ``` +If you prefer to work with `java.time.Instant` instead of `java.util.Date`: + +```java +Instant expiresAt = jwt.getExpiresAtAsInstant(); +``` + #### Not Before ("nbf") Returns the Not Before value or null if it's not defined in the Payload. @@ -350,6 +367,12 @@ Returns the Not Before value or null if it's not defined in the Payload. Date notBefore = jwt.getNotBefore(); ``` +If you prefer to work with `java.time.Instant` instead of `java.util.Date`: + +```java +Instant notBefore = jwt.getNotBeforeAsInstant(); +``` + #### Issued At ("iat") Returns the Issued At value or null if it's not defined in the Payload. @@ -358,6 +381,12 @@ Returns the Issued At value or null if it's not defined in the Payload. Date issuedAt = jwt.getIssuedAt(); ``` +If you prefer to work with `java.time.Instant` instead of `java.util.Date`: + +```java +Instant issuedAt = jwt.getIssuedAtAsInstant(); +``` + #### JWT ID ("jti") Returns the JWT ID value or null if it's not defined in the Payload. diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index cab474f7..a99f0fa0 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -453,7 +453,7 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE if (!validatePayload(payloadClaims)) { throw new IllegalArgumentException("Claim values must only be of types Map, List, Boolean, Integer, " - + "Long, Double, String, Date and Null"); + + "Long, Double, String, Date, Instant, and Null"); } // add claims only after validating all claims so as not to corrupt the claims map of this builder diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index efe6b94b..4d1c7314 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -759,7 +759,7 @@ public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() { @Test public void withPayloadShouldNotAllowCustomType() { exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date and Null"); + exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null"); Map payload = new HashMap<>(); payload.put("entry", "value"); @@ -786,7 +786,7 @@ public void withPayloadShouldAllowNullListItems() { @Test public void withPayloadShouldNotAllowListWithCustomType() { exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date and Null"); + exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null"); Map payload = new HashMap<>(); payload.put("list", Arrays.asList("item1", new UserPojo("name", 42))); @@ -798,7 +798,7 @@ public void withPayloadShouldNotAllowListWithCustomType() { @Test public void withPayloadShouldNotAllowMapWithCustomType() { exception.expect(IllegalArgumentException.class); - exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date and Null"); + exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null"); Map payload = new HashMap<>(); payload.put("entry", "value"); From 05b54499be0cc06478467d66c801d9bc3da3fecc Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 3 May 2022 15:46:47 +0200 Subject: [PATCH 037/134] Added protection against CVE-2022-21449 --- .../auth0/jwt/algorithms/ECDSAAlgorithm.java | 69 ++++++++- .../jwt/algorithms/ECDSAAlgorithmTest.java | 139 +++++++++++++++++- .../ECDSABouncyCastleProviderTests.java | 20 ++- 3 files changed, 221 insertions(+), 7 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index c2d08a15..f96fd576 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -5,6 +5,7 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.ECDSAKeyProvider; +import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; @@ -46,6 +47,7 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { if (publicKey == null) { throw new IllegalStateException("The given Public Key is null."); } + validateSignatureStructure(signatureBytes, publicKey); boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), JOSEToDER(signatureBytes)); if (!valid) { @@ -140,13 +142,42 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { return joseSignature; } - //Visible for testing - byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { + /** + * Added check for extra protection against CVE-2022-21449. + * This method ensures the signature's structure is as expected. + * + * @param joseSignature is the signature from the JWT + * @param publicKey public key used to verify the JWT + * @throws SignatureException if the signature's structure is not as per expectation + */ + // Visible for testing + void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) throws SignatureException { + // check signature length, moved this check from JOSEToDER method if (joseSignature.length != ecNumberSize * 2) { throw new SignatureException("Invalid JOSE signature format."); } - // Retrieve R and S number's length and padding. + if (isAllZeros(joseSignature)) { + throw new SignatureException("Invalid Signature: All Zeros."); + } + + // get R + byte[] rBytes = new byte[ecNumberSize]; + System.arraycopy(joseSignature, 0, rBytes, 0, ecNumberSize); + BigInteger r = new BigInteger(1, rBytes); + if(isAllZeros(rBytes)) { + throw new SignatureException("Invalid Signature: All Zeros for R value."); + } + + // get S + byte[] sBytes = new byte[ecNumberSize]; + System.arraycopy(joseSignature, ecNumberSize, sBytes, 0, ecNumberSize); + BigInteger s = new BigInteger(1, sBytes); + if(isAllZeros(sBytes)) { + throw new SignatureException("Invalid Signature: All Zeros for S value."); + } + + //moved this check from JOSEToDER method int rPadding = countPadding(joseSignature, 0, ecNumberSize); int sPadding = countPadding(joseSignature, ecNumberSize, joseSignature.length); int rLength = ecNumberSize - rPadding; @@ -157,6 +188,29 @@ byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { throw new SignatureException("Invalid JOSE signature format."); } + // check for 0 r or s here since we have the values + if (BigInteger.ZERO.equals(r) || BigInteger.ZERO.equals(s)) { + throw new SignatureException("R or S value cannot be zero."); + } + + BigInteger order = publicKey.getParams().getOrder(); + + // R and S must be less than N + if (order.compareTo(r) < 1 || order.compareTo(s) < 1) { + throw new SignatureException("The difference between R or S value and order should be greater than one."); + } + } + + //Visible for testing + byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { + // Retrieve R and S number's length and padding. + int rPadding = countPadding(joseSignature, 0, ecNumberSize); + int sPadding = countPadding(joseSignature, ecNumberSize, joseSignature.length); + int rLength = ecNumberSize - rPadding; + int sLength = ecNumberSize - sPadding; + + int length = 2 + rLength + 2 + sLength; + final byte[] derSignature; int offset; if (length > 0x7f) { @@ -205,6 +259,15 @@ byte[] JOSEToDER(byte[] joseSignature) throws SignatureException { return derSignature; } + private boolean isAllZeros(byte[] bytes) { + for (byte b : bytes) { + if (b != 0) { + return false; + } + } + return true; + } + private int countPadding(byte[] bytes, int fromIndex, int toIndex) { int padding = 0; while (fromIndex + padding < toIndex && bytes[fromIndex + padding] == 0) { diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index 39c9dabf..aee8238c 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -4,6 +4,7 @@ import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.ECDSAKeyProvider; +import com.auth0.jwt.interfaces.JWTVerifier; import org.hamcrest.Matchers; import org.hamcrest.collection.IsIn; import org.junit.Assert; @@ -12,11 +13,13 @@ import org.junit.rules.ExpectedException; import java.io.ByteArrayOutputStream; +import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.interfaces.ECKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; import java.util.Arrays; import java.util.Base64; @@ -574,6 +577,10 @@ public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exce .thenThrow(NoSuchAlgorithmException.class); ECPublicKey publicKey = mock(ECPublicKey.class); + when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); + byte[] a = new byte[64]; + Arrays.fill(a, Byte.MAX_VALUE); + when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); @@ -592,6 +599,10 @@ public void shouldThrowOnVerifyWhenThePublicKeyIsInvalid() throws Exception { .thenThrow(InvalidKeyException.class); ECPublicKey publicKey = mock(ECPublicKey.class); + when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); + byte[] a = new byte[64]; + Arrays.fill(a, Byte.MAX_VALUE); + when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); @@ -610,6 +621,10 @@ public void shouldThrowOnVerifyWhenTheSignatureIsNotPrepared() throws Exception .thenThrow(SignatureException.class); ECPublicKey publicKey = mock(ECPublicKey.class); + when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); + byte[] a = new byte[64]; + Arrays.fill(a, Byte.MAX_VALUE); + when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); @@ -939,12 +954,13 @@ public void shouldThrowOnDERSignatureConversionIfSNumberDoesNotHaveExpectedLengt @Test public void shouldThrowOnJOSESignatureConversionIfDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); + ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] joseSignature = new byte[32 * 2 - 1]; exception.expect(SignatureException.class); exception.expectMessage("Invalid JOSE signature format."); - algorithm256.JOSEToDER(joseSignature); + algorithm256.validateSignatureStructure(joseSignature, publicKey); } @Test @@ -1309,4 +1325,123 @@ public void shouldFailOnECDSA256SigningWithDeprecatedMethodWhenProvidedPrivateKe algorithm.sign(new byte[0]); } + @Test + public void invalidECDSA256SignatureShouldFailTokenVerification() throws Exception { + exception.expect(SignatureVerificationException.class); + exception.expectCause(isA(SignatureException.class)); + + String jwtWithInvalidSig = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0._____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"; + + ECKey key256 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECKey key384 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); + ECKey key512 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); + ECKey key256k = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); + JWTVerifier verifier256 = JWT.require(Algorithm.ECDSA256(key256)).build(); + JWTVerifier verifier384 = JWT.require(Algorithm.ECDSA256(key384)).build(); + JWTVerifier verifier512 = JWT.require(Algorithm.ECDSA256(key512)).build(); + JWTVerifier verifier256k = JWT.require(Algorithm.ECDSA256(key256k)).build(); + verifier256.verify(jwtWithInvalidSig); + verifier384.verify(jwtWithInvalidSig); + verifier512.verify(jwtWithInvalidSig); + verifier256k.verify(jwtWithInvalidSig); + } + + @Test + public void emptyECDSA256SignatureShouldFailTokenVerification() throws Exception { + exception.expect(SignatureVerificationException.class); + exception.expectCause(isA(SignatureException.class)); + + String jwtWithInvalidSig = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + + ECKey key256 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECKey key384 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); + ECKey key512 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); + ECKey key256k = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); + JWTVerifier verifier256 = JWT.require(Algorithm.ECDSA256(key256)).build(); + JWTVerifier verifier384 = JWT.require(Algorithm.ECDSA256(key384)).build(); + JWTVerifier verifier512 = JWT.require(Algorithm.ECDSA256(key512)).build(); + JWTVerifier verifier256k = JWT.require(Algorithm.ECDSA256(key256k)).build(); + verifier256.verify(jwtWithInvalidSig); + verifier384.verify(jwtWithInvalidSig); + verifier512.verify(jwtWithInvalidSig); + verifier256k.verify(jwtWithInvalidSig); + } + + @Test + public void signatureWithAllZerosShouldFail() throws Exception { + exception.expect(SignatureException.class); + + ECPublicKey pubKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(pubKey, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); + byte[] signatureBytes = new byte[64]; + algorithm256.validateSignatureStructure(signatureBytes, pubKey); + } + + @Test + public void signatureWithRZeroShouldFail() throws Exception { + exception.expect(SignatureException.class); + + ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); + + String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); + + String[] chunks = signedJwt.split("\\."); + byte[] signature = Base64.getUrlDecoder().decode(chunks[2]); + + byte[] sigWithBlankR = new byte[signature.length]; + for (int i = 0; i < signature.length; i++) { + if (i < signature.length / 2) { + sigWithBlankR[i] = 0; + } else { + sigWithBlankR[i] = signature[i]; + } + } + + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); + algorithm256.validateSignatureStructure(sigWithBlankR, publicKey); + } + + @Test + public void signatureWithSZeroShouldFail() throws Exception { + exception.expect(SignatureException.class); + + ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); + + String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); + + String[] chunks = signedJwt.split("\\."); + byte[] signature = Base64.getUrlDecoder().decode(chunks[2]); + + byte[] sigWithBlankS = new byte[signature.length]; + for (int i = 0; i < signature.length; i++) { + if (i < signature.length / 2) { + sigWithBlankS[i] = signature[i]; + } else { + sigWithBlankS[i] = 0; + } + } + + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); + algorithm256.validateSignatureStructure(sigWithBlankS, publicKey); + } + + @Test + public void signatureWithRSValueNotLessThanOrderShouldFail() throws Exception { + exception.expect(SignatureException.class); + + ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); + + String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); + String jwtWithInvalidSig = signedJwt.substring(0, signedJwt.lastIndexOf('.') + 1) + "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"; + + String[] chunks = jwtWithInvalidSig.split("\\."); + byte[] invalidSignature = Base64.getUrlDecoder().decode(chunks[2]); + + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); + algorithm256.validateSignatureStructure(invalidSignature, publicKey); + } } \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java index 68fe6e50..78e0063d 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java @@ -11,11 +11,14 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.interfaces.ECKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +import java.util.Arrays; import java.util.Base64; import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; @@ -591,6 +594,10 @@ public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exce .thenThrow(NoSuchAlgorithmException.class); ECPublicKey publicKey = mock(ECPublicKey.class); + when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); + byte[] a = new byte[64]; + Arrays.fill(a, Byte.MAX_VALUE); + when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); @@ -609,6 +616,10 @@ public void shouldThrowOnVerifyWhenThePublicKeyIsInvalid() throws Exception { .thenThrow(InvalidKeyException.class); ECPublicKey publicKey = mock(ECPublicKey.class); + when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); + byte[] a = new byte[64]; + Arrays.fill(a, Byte.MAX_VALUE); + when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); @@ -627,6 +638,10 @@ public void shouldThrowOnVerifyWhenTheSignatureIsNotPrepared() throws Exception .thenThrow(SignatureException.class); ECPublicKey publicKey = mock(ECPublicKey.class); + when(publicKey.getParams()).thenReturn(mock(ECParameterSpec.class)); + byte[] a = new byte[64]; + Arrays.fill(a, Byte.MAX_VALUE); + when(publicKey.getParams().getOrder()).thenReturn(new BigInteger(a)); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); @@ -935,12 +950,13 @@ public void shouldThrowOnDERSignatureConversionIfSNumberDoesNotHaveExpectedLengt @Test public void shouldThrowOnJOSESignatureConversionIfDoesNotHaveExpectedLength() throws Exception { - ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); + ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] joseSignature = new byte[32 * 2 - 1]; exception.expect(SignatureException.class); exception.expectMessage("Invalid JOSE signature format."); - algorithm256.JOSEToDER(joseSignature); + algorithm256.validateSignatureStructure(joseSignature, publicKey); } @Test From 69dae3eba9235a45e01ab588d5027b73aef918cc Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 3 May 2022 16:16:36 +0200 Subject: [PATCH 038/134] Added banner to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 260f6d6e..0e6a7d48 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ A Java implementation of [JSON Web Token (JWT) - RFC 7519](https://tools.ietf.org/html/rfc7519). +> :warning: **Important security note:** JVM has a critical vulnerability for ECDSA Algorithms - [CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449). Please review the details of the vulnerability and update your environment. + If you're looking for an **Android** version of the JWT Decoder take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library. > This library requires Java 8 or higher. The last version that supported Java 7 was 3.11.0. From 3135ba7893ea60882500fa509c6d98fe48a4f0f8 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 3 May 2022 16:18:01 +0200 Subject: [PATCH 039/134] Removed zero check since it is already verified --- .../main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index f96fd576..1d2544f6 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -188,11 +188,6 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr throw new SignatureException("Invalid JOSE signature format."); } - // check for 0 r or s here since we have the values - if (BigInteger.ZERO.equals(r) || BigInteger.ZERO.equals(s)) { - throw new SignatureException("R or S value cannot be zero."); - } - BigInteger order = publicKey.getParams().getOrder(); // R and S must be less than N From 208d7b66c281fcd91dbc5d83fe51d676ee5e0d51 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 3 May 2022 18:37:52 +0200 Subject: [PATCH 040/134] Improved order comparison --- .../auth0/jwt/algorithms/ECDSAAlgorithm.java | 8 ++++++-- .../jwt/algorithms/ECDSAAlgorithmTest.java | 20 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index 1d2544f6..00b68cad 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -191,8 +191,12 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr BigInteger order = publicKey.getParams().getOrder(); // R and S must be less than N - if (order.compareTo(r) < 1 || order.compareTo(s) < 1) { - throw new SignatureException("The difference between R or S value and order should be greater than one."); + if (order.compareTo(r) < 1) { + throw new SignatureException("The difference between R value and order should be greater than one."); + } + + if (order.compareTo(s) < 1){ + throw new SignatureException("The difference between S value and order should be greater than one."); } } diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index aee8238c..a02c639b 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -1429,7 +1429,7 @@ public void signatureWithSZeroShouldFail() throws Exception { } @Test - public void signatureWithRSValueNotLessThanOrderShouldFail() throws Exception { + public void signatureWithRValueNotLessThanOrderShouldFail() throws Exception { exception.expect(SignatureException.class); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); @@ -1444,4 +1444,22 @@ public void signatureWithRSValueNotLessThanOrderShouldFail() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); algorithm256.validateSignatureStructure(invalidSignature, publicKey); } + + @Test + public void signatureWithSValueNotLessThanOrderShouldFail() throws Exception { + exception.expect(SignatureException.class); + + ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); + ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); + + String signedJwt = JWT.create().sign(Algorithm.ECDSA256(publicKey, privateKey)); + String jwtWithInvalidSig = signedJwt.substring(0, signedJwt.lastIndexOf('.') + 1) + "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"; + + String[] chunks = jwtWithInvalidSig.split("\\."); + byte[] invalidSignature = Base64.getUrlDecoder().decode(chunks[2]); + invalidSignature[0] = Byte.MAX_VALUE; + + ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256(publicKey, privateKey); + algorithm256.validateSignatureStructure(invalidSignature, publicKey); + } } \ No newline at end of file From df004b1bc55ed42f9ccb1d2b820bad08879ad273 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 4 May 2022 11:38:43 +0200 Subject: [PATCH 041/134] Updated documentation regarding HMAC Key length --- README.md | 8 ++++---- .../com/auth0/jwt/algorithms/Algorithm.java | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 624a7f68..3e270500 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` ```java String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { - Algorithm algorithm = Algorithm.HMAC256("secret"); + Algorithm algorithm = Algorithm.HMAC256("secret"); //use more secure key JWTVerifier verifier = JWT.require(algorithm) .withIssuer("auth0") .build(); //Reusable verifier instance @@ -175,7 +175,7 @@ When using RSA or ECDSA algorithms and you just need to **sign** JWTs you can av ```java //HMAC -Algorithm algorithmHS = Algorithm.HMAC256("secret"); +Algorithm algorithmHS = Algorithm.HMAC256("secret"); //use more secure key //RSA RSAPublicKey publicKey = //Get the key instance @@ -185,9 +185,9 @@ Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); > Note: How you obtain or read keys is not in the scope of this library. For an example of how you might implement this, see [this gist](https://gist.github.com/lbalmaceda/9a0c7890c2965826c04119dcfb1a5469). -##### HMAC Key Length and Security +##### :key: HMAC Key Length and Security -When using a Hash-based Message Authenticaton Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recommendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. +When using a Hash-based Message Authentication Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recommendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. #### Using a KeyProvider: By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index a5247005..27d79909 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -130,7 +130,9 @@ public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException { /** * Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256". * - * @param secret the secret to use in the verify or signing instance. + * @param secret the secret bytes to use in the verify or signing instance. + * Ensure the length of the secret is at least 256 bit long + * See HMAC Key Length and Security in README * @return a valid HMAC256 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -142,6 +144,8 @@ public static Algorithm HMAC256(String secret) throws IllegalArgumentException { * Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256". * * @param secret the secret bytes to use in the verify or signing instance. + * Ensure the length of the secret is at least 256 bit long + * See HMAC Key Length and Security in README * @return a valid HMAC256 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -152,7 +156,9 @@ public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { /** * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". * - * @param secret the secret to use in the verify or signing instance. + * @param secret the secret bytes to use in the verify or signing instance. + * Ensure the length of the secret is at least 384 bit long + * See HMAC Key Length and Security in README * @return a valid HMAC384 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -164,6 +170,8 @@ public static Algorithm HMAC384(String secret) throws IllegalArgumentException { * Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384". * * @param secret the secret bytes to use in the verify or signing instance. + * Ensure the length of the secret is at least 384 bit long + * See HMAC Key Length and Security in README * @return a valid HMAC384 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -174,7 +182,9 @@ public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException { /** * Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512". * - * @param secret the secret to use in the verify or signing instance. + * @param secret the secret bytes to use in the verify or signing instance. + * Ensure the length of the secret is at least 512 bit long + * See HMAC Key Length and Security in README * @return a valid HMAC512 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -186,6 +196,8 @@ public static Algorithm HMAC512(String secret) throws IllegalArgumentException { * Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512". * * @param secret the secret bytes to use in the verify or signing instance. + * Ensure the length of the secret is at least 512 bit long + * See HMAC Key Length and Security in README * @return a valid HMAC512 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ From 645b40a4c9ee9ed62e49d5bebda2c8a6c9d3221a Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Thu, 5 May 2022 11:54:49 +0200 Subject: [PATCH 042/134] Added test cases to differentiate thrown exception --- .../java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index a02c639b..44d9e6db 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -1370,6 +1370,7 @@ public void emptyECDSA256SignatureShouldFailTokenVerification() throws Exception @Test public void signatureWithAllZerosShouldFail() throws Exception { exception.expect(SignatureException.class); + exception.expectMessage("Invalid Signature: All Zeros."); ECPublicKey pubKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); @@ -1381,6 +1382,7 @@ public void signatureWithAllZerosShouldFail() throws Exception { @Test public void signatureWithRZeroShouldFail() throws Exception { exception.expect(SignatureException.class); + exception.expectMessage("Invalid Signature: All Zeros for R value."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); @@ -1406,6 +1408,7 @@ public void signatureWithRZeroShouldFail() throws Exception { @Test public void signatureWithSZeroShouldFail() throws Exception { exception.expect(SignatureException.class); + exception.expectMessage("Invalid Signature: All Zeros for S value."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); @@ -1431,6 +1434,7 @@ public void signatureWithSZeroShouldFail() throws Exception { @Test public void signatureWithRValueNotLessThanOrderShouldFail() throws Exception { exception.expect(SignatureException.class); + exception.expectMessage("The difference between R value and order should be greater than one."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); @@ -1448,6 +1452,7 @@ public void signatureWithRValueNotLessThanOrderShouldFail() throws Exception { @Test public void signatureWithSValueNotLessThanOrderShouldFail() throws Exception { exception.expect(SignatureException.class); + exception.expectMessage("The difference between S value and order should be greater than one."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); From 9d471d2152354866bfa65a861dac5590601efe79 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Thu, 5 May 2022 14:10:52 +0200 Subject: [PATCH 043/134] Abstracted the error message thrown --- .../java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java | 10 +++++----- .../com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index 00b68cad..ac34c44e 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -158,7 +158,7 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr } if (isAllZeros(joseSignature)) { - throw new SignatureException("Invalid Signature: All Zeros."); + throw new SignatureException("Invalid signature format."); } // get R @@ -166,7 +166,7 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr System.arraycopy(joseSignature, 0, rBytes, 0, ecNumberSize); BigInteger r = new BigInteger(1, rBytes); if(isAllZeros(rBytes)) { - throw new SignatureException("Invalid Signature: All Zeros for R value."); + throw new SignatureException("Invalid signature format."); } // get S @@ -174,7 +174,7 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr System.arraycopy(joseSignature, ecNumberSize, sBytes, 0, ecNumberSize); BigInteger s = new BigInteger(1, sBytes); if(isAllZeros(sBytes)) { - throw new SignatureException("Invalid Signature: All Zeros for S value."); + throw new SignatureException("Invalid signature format."); } //moved this check from JOSEToDER method @@ -192,11 +192,11 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr // R and S must be less than N if (order.compareTo(r) < 1) { - throw new SignatureException("The difference between R value and order should be greater than one."); + throw new SignatureException("Invalid signature format."); } if (order.compareTo(s) < 1){ - throw new SignatureException("The difference between S value and order should be greater than one."); + throw new SignatureException("Invalid signature format."); } } diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index 44d9e6db..818924fe 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -1370,7 +1370,7 @@ public void emptyECDSA256SignatureShouldFailTokenVerification() throws Exception @Test public void signatureWithAllZerosShouldFail() throws Exception { exception.expect(SignatureException.class); - exception.expectMessage("Invalid Signature: All Zeros."); + exception.expectMessage("Invalid signature format."); ECPublicKey pubKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); @@ -1382,7 +1382,7 @@ public void signatureWithAllZerosShouldFail() throws Exception { @Test public void signatureWithRZeroShouldFail() throws Exception { exception.expect(SignatureException.class); - exception.expectMessage("Invalid Signature: All Zeros for R value."); + exception.expectMessage("Invalid signature format."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); @@ -1408,7 +1408,7 @@ public void signatureWithRZeroShouldFail() throws Exception { @Test public void signatureWithSZeroShouldFail() throws Exception { exception.expect(SignatureException.class); - exception.expectMessage("Invalid Signature: All Zeros for S value."); + exception.expectMessage("Invalid signature format."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); @@ -1434,7 +1434,7 @@ public void signatureWithSZeroShouldFail() throws Exception { @Test public void signatureWithRValueNotLessThanOrderShouldFail() throws Exception { exception.expect(SignatureException.class); - exception.expectMessage("The difference between R value and order should be greater than one."); + exception.expectMessage("Invalid signature format."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); @@ -1452,7 +1452,7 @@ public void signatureWithRValueNotLessThanOrderShouldFail() throws Exception { @Test public void signatureWithSValueNotLessThanOrderShouldFail() throws Exception { exception.expect(SignatureException.class); - exception.expectMessage("The difference between S value and order should be greater than one."); + exception.expectMessage("Invalid signature format."); ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); From fd3eac3b721c7481a69d9109cc0666b65544ac5b Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Thu, 5 May 2022 17:17:28 +0200 Subject: [PATCH 044/134] Release 3.19.2 --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a022328d..d81f9a18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [3.19.2](https://github.com/auth0/java-jwt/tree/3.19.2) (2022-05-05) +[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.1...3.19.2) + +**Security** +- [SDK-3311] Added protection against CVE-2022-21449 [\#579](https://github.com/auth0/java-jwt/pull/579) ([poovamraj](https://github.com/poovamraj)) + ## [3.19.1](https://github.com/auth0/java-jwt/tree/3.19.1) (2022-03-30) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.0...3.19.1) diff --git a/README.md b/README.md index 0e6a7d48..c55fa70c 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ The library is available on both Maven Central and Bintray, and the Javadoc is p com.auth0 java-jwt - 3.19.1 + 3.19.2 ``` ### Gradle ```gradle -implementation 'com.auth0:java-jwt:3.19.1' +implementation 'com.auth0:java-jwt:3.19.2' ``` ## Available Algorithms From 4573ba0537c5a34b768be4149ab817075cdbd111 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 6 May 2022 13:02:42 +0200 Subject: [PATCH 045/134] Code formatting for CheckStyle --- config/checkstyle/checkstyle.xml | 2 +- .../com/auth0/jwt/algorithms/ECDSAAlgorithm.java | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index d2615981..b97ccc37 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -206,7 +206,7 @@ value="Catch parameter name ''{0}'' must match pattern ''{1}''."/> - + diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index 185d95cf..b3046097 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -50,7 +50,8 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { throw new IllegalStateException("The given Public Key is null."); } validateSignatureStructure(signatureBytes, publicKey); - boolean valid = crypto.verifySignatureFor(getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), JOSEToDER(signatureBytes)); + boolean valid = crypto.verifySignatureFor( + getDescription(), publicKey, jwt.getHeader(), jwt.getPayload(), JOSEToDER(signatureBytes)); if (!valid) { throw new SignatureVerificationException(this); @@ -151,7 +152,7 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { * This method ensures the signature's structure is as expected. * * @param joseSignature is the signature from the JWT - * @param publicKey public key used to verify the JWT + * @param publicKey public key used to verify the JWT * @throws SignatureException if the signature's structure is not as per expectation */ // Visible for testing @@ -168,16 +169,14 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr // get R byte[] rBytes = new byte[ecNumberSize]; System.arraycopy(joseSignature, 0, rBytes, 0, ecNumberSize); - BigInteger r = new BigInteger(1, rBytes); - if(isAllZeros(rBytes)) { + if (isAllZeros(rBytes)) { throw new SignatureException("Invalid signature format."); } // get S byte[] sBytes = new byte[ecNumberSize]; System.arraycopy(joseSignature, ecNumberSize, sBytes, 0, ecNumberSize); - BigInteger s = new BigInteger(1, sBytes); - if(isAllZeros(sBytes)) { + if (isAllZeros(sBytes)) { throw new SignatureException("Invalid signature format."); } @@ -193,13 +192,15 @@ void validateSignatureStructure(byte[] joseSignature, ECPublicKey publicKey) thr } BigInteger order = publicKey.getParams().getOrder(); + BigInteger r = new BigInteger(1, rBytes); + BigInteger s = new BigInteger(1, sBytes); // R and S must be less than N if (order.compareTo(r) < 1) { throw new SignatureException("Invalid signature format."); } - if (order.compareTo(s) < 1){ + if (order.compareTo(s) < 1) { throw new SignatureException("Invalid signature format."); } } From 6f94d823682cf4ddb717d9e336c6f49004078b4b Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 6 May 2022 13:15:37 +0200 Subject: [PATCH 046/134] Removed ES256K tests since it is removed in v4 --- .../java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index d05fb53d..2e636c71 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -1223,15 +1223,12 @@ public void invalidECDSA256SignatureShouldFailTokenVerification() throws Excepti ECKey key256 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECKey key384 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); ECKey key512 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - ECKey key256k = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); JWTVerifier verifier256 = JWT.require(Algorithm.ECDSA256(key256)).build(); JWTVerifier verifier384 = JWT.require(Algorithm.ECDSA256(key384)).build(); JWTVerifier verifier512 = JWT.require(Algorithm.ECDSA256(key512)).build(); - JWTVerifier verifier256k = JWT.require(Algorithm.ECDSA256(key256k)).build(); verifier256.verify(jwtWithInvalidSig); verifier384.verify(jwtWithInvalidSig); verifier512.verify(jwtWithInvalidSig); - verifier256k.verify(jwtWithInvalidSig); } @Test @@ -1244,15 +1241,12 @@ public void emptyECDSA256SignatureShouldFailTokenVerification() throws Exception ECKey key256 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECKey key384 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); ECKey key512 = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); - ECKey key256k = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256K, "EC"); JWTVerifier verifier256 = JWT.require(Algorithm.ECDSA256(key256)).build(); JWTVerifier verifier384 = JWT.require(Algorithm.ECDSA256(key384)).build(); JWTVerifier verifier512 = JWT.require(Algorithm.ECDSA256(key512)).build(); - JWTVerifier verifier256k = JWT.require(Algorithm.ECDSA256(key256k)).build(); verifier256.verify(jwtWithInvalidSig); verifier384.verify(jwtWithInvalidSig); verifier512.verify(jwtWithInvalidSig); - verifier256k.verify(jwtWithInvalidSig); } @Test From c2e3558feb5cf6bd12f977b692236005053962fd Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 6 May 2022 14:46:45 +0200 Subject: [PATCH 047/134] Added tests to verify null creation in list and map --- .../java/com/auth0/jwt/JWTCreatorTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 4d1c7314..020e5e37 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -16,6 +16,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -919,4 +922,22 @@ public void withPayloadShouldSupportNullValuesEverywhere() { assertThat(headerJson, JsonMatcher.hasEntry("listNestedClaim", listNestedClaim)); assertThat(headerJson, JsonMatcher.hasEntry("objClaim", objClaim)); } + + @Test + public void shouldCreatePayloadWithNullForMap() { + String jwt = JWTCreator.init() + .withClaim("name", (Map) null) + .sign(Algorithm.HMAC256("secret")); + assertThat(jwt, is(notNullValue())); + assertTrue(JWT.decode(jwt).getClaim("name").isNull()); + } + + @Test + public void shouldCreatePayloadWithNullForList() { + String jwt = JWTCreator.init() + .withClaim("name", (List) null) + .sign(Algorithm.HMAC256("secret")); + assertThat(jwt, is(notNullValue())); + assertTrue(JWT.decode(jwt).getClaim("name").isNull()); + } } From 08f2e1de7ad86ad85a182c2d8a01ec04358be5ed Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 6 May 2022 16:01:51 +0200 Subject: [PATCH 048/134] Release 4.0.0-beta.0 --- CHANGELOG.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d81f9a18..c920528c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,52 @@ # Change Log +## [4.0.0-beta.0](https://github.com/auth0/java-jwt/tree/4.0.0-beta.0) (2022-05-06) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0...4.0.0-beta.0) + +**Added** +- [SDK-3159] JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3244] Add Migration Guide [\#576](https://github.com/auth0/java-jwt/pull/576) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3226] Expose claim name and header constants [\#574](https://github.com/auth0/java-jwt/pull/574) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3231] Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) +- Improved README structure [\#571](https://github.com/auth0/java-jwt/pull/571) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3154] Improved Exception Handling [\#568](https://github.com/auth0/java-jwt/pull/568) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3155] Predicate based Claim verification [\#562](https://github.com/auth0/java-jwt/pull/562) ([poovamraj](https://github.com/poovamraj)) +- Add lint checks [\#561](https://github.com/auth0/java-jwt/pull/561) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3186] Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3149] Add Instant support [\#537](https://github.com/auth0/java-jwt/pull/537) ([jimmyjames](https://github.com/jimmyjames)) +- Testing Java LTS versions [\#536](https://github.com/auth0/java-jwt/pull/536) ([poovamraj](https://github.com/poovamraj)) + +**Changed** +- [SDK-3158] Null claim handling [\#564](https://github.com/auth0/java-jwt/pull/564) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3151] Undeprecate Single Key Constructor for Algorithms [\#551](https://github.com/auth0/java-jwt/pull/551) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3151] Update documentation and undeprecate single content sign methods [\#550](https://github.com/auth0/java-jwt/pull/550) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3197] Update test deps [\#539](https://github.com/auth0/java-jwt/pull/539) ([jimmyjames](https://github.com/jimmyjames)) + +**Deprecated** +- [SDK-3192] Deprecate secp256k1 curve for EC Algorithms [\#540](https://github.com/auth0/java-jwt/pull/540) ([poovamraj](https://github.com/poovamraj)) + +**Removed** +- Remove ES256K support [\#556](https://github.com/auth0/java-jwt/pull/556) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3212] Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3160] Remove internal Clock [\#533](https://github.com/auth0/java-jwt/pull/533) ([jimmyjames](https://github.com/jimmyjames)) + +**Fixed** +- Improve keyprovider reliability [\#570](https://github.com/auth0/java-jwt/pull/570) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3186] Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) +- Test only change - remove unnecessary throws clause from tests [\#535](https://github.com/auth0/java-jwt/pull/535) ([jimmyjames](https://github.com/jimmyjames)) + +**Security** +- [SDK-3125] Updated documentation regarding HMAC Key length [\#580](https://github.com/auth0/java-jwt/pull/580) ([poovamraj](https://github.com/poovamraj)) + +**Breaking changes** +- [SDK-3231] Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) +- Improve keyprovider reliability [\#570](https://github.com/auth0/java-jwt/pull/570) ([poovamraj](https://github.com/poovamraj)) +- Remove ES256K support [\#556](https://github.com/auth0/java-jwt/pull/556) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3212] Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) +- [SDK-3171] Fix header claims serialization [\#549](https://github.com/auth0/java-jwt/pull/549) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3150] Serialize dates in collections as seconds since epoch [\#534](https://github.com/auth0/java-jwt/pull/534) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3160] Replace com.auth0.jwt.interfaces.Clock with java.time.Clock [\#532](https://github.com/auth0/java-jwt/pull/532) ([jimmyjames](https://github.com/jimmyjames)) + ## [3.19.2](https://github.com/auth0/java-jwt/tree/3.19.2) (2022-05-05) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.1...3.19.2) From a14643d4a9cca096d3dc2049db6a4e0522d454d9 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 6 May 2022 16:10:37 +0200 Subject: [PATCH 049/134] Updated Changelog for beta --- CHANGELOG.md | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c920528c..123788f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,51 +1,53 @@ # Change Log ## [4.0.0-beta.0](https://github.com/auth0/java-jwt/tree/4.0.0-beta.0) (2022-05-06) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0...4.0.0-beta.0) +[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0-beta.0) + +💡 Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. **Added** -- [SDK-3159] JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3244] Add Migration Guide [\#576](https://github.com/auth0/java-jwt/pull/576) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3226] Expose claim name and header constants [\#574](https://github.com/auth0/java-jwt/pull/574) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3231] Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) +- JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) +- Add Migration Guide [\#576](https://github.com/auth0/java-jwt/pull/576) ([jimmyjames](https://github.com/jimmyjames)) +- Expose claim name and header constants [\#574](https://github.com/auth0/java-jwt/pull/574) ([jimmyjames](https://github.com/jimmyjames)) +- Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) - Improved README structure [\#571](https://github.com/auth0/java-jwt/pull/571) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3154] Improved Exception Handling [\#568](https://github.com/auth0/java-jwt/pull/568) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3155] Predicate based Claim verification [\#562](https://github.com/auth0/java-jwt/pull/562) ([poovamraj](https://github.com/poovamraj)) +- Improved Exception Handling [\#568](https://github.com/auth0/java-jwt/pull/568) ([poovamraj](https://github.com/poovamraj)) +- Predicate based Claim verification [\#562](https://github.com/auth0/java-jwt/pull/562) ([poovamraj](https://github.com/poovamraj)) - Add lint checks [\#561](https://github.com/auth0/java-jwt/pull/561) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3186] Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3149] Add Instant support [\#537](https://github.com/auth0/java-jwt/pull/537) ([jimmyjames](https://github.com/jimmyjames)) +- Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) +- Add Instant support [\#537](https://github.com/auth0/java-jwt/pull/537) ([jimmyjames](https://github.com/jimmyjames)) - Testing Java LTS versions [\#536](https://github.com/auth0/java-jwt/pull/536) ([poovamraj](https://github.com/poovamraj)) **Changed** -- [SDK-3158] Null claim handling [\#564](https://github.com/auth0/java-jwt/pull/564) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3151] Undeprecate Single Key Constructor for Algorithms [\#551](https://github.com/auth0/java-jwt/pull/551) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3151] Update documentation and undeprecate single content sign methods [\#550](https://github.com/auth0/java-jwt/pull/550) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3197] Update test deps [\#539](https://github.com/auth0/java-jwt/pull/539) ([jimmyjames](https://github.com/jimmyjames)) +- Null claim handling [\#564](https://github.com/auth0/java-jwt/pull/564) ([poovamraj](https://github.com/poovamraj)) +- Undeprecate Single Key Constructor for Algorithms [\#551](https://github.com/auth0/java-jwt/pull/551) ([poovamraj](https://github.com/poovamraj)) +- Update documentation and undeprecate single content sign methods [\#550](https://github.com/auth0/java-jwt/pull/550) ([poovamraj](https://github.com/poovamraj)) +- Update test deps [\#539](https://github.com/auth0/java-jwt/pull/539) ([jimmyjames](https://github.com/jimmyjames)) **Deprecated** -- [SDK-3192] Deprecate secp256k1 curve for EC Algorithms [\#540](https://github.com/auth0/java-jwt/pull/540) ([poovamraj](https://github.com/poovamraj)) +- Deprecate secp256k1 curve for EC Algorithms [\#540](https://github.com/auth0/java-jwt/pull/540) ([poovamraj](https://github.com/poovamraj)) **Removed** - Remove ES256K support [\#556](https://github.com/auth0/java-jwt/pull/556) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3212] Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3160] Remove internal Clock [\#533](https://github.com/auth0/java-jwt/pull/533) ([jimmyjames](https://github.com/jimmyjames)) +- Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) +- Remove internal Clock [\#533](https://github.com/auth0/java-jwt/pull/533) ([jimmyjames](https://github.com/jimmyjames)) **Fixed** - Improve keyprovider reliability [\#570](https://github.com/auth0/java-jwt/pull/570) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3186] Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) +- Support date/time custom claim validation [\#538](https://github.com/auth0/java-jwt/pull/538) ([jimmyjames](https://github.com/jimmyjames)) - Test only change - remove unnecessary throws clause from tests [\#535](https://github.com/auth0/java-jwt/pull/535) ([jimmyjames](https://github.com/jimmyjames)) **Security** -- [SDK-3125] Updated documentation regarding HMAC Key length [\#580](https://github.com/auth0/java-jwt/pull/580) ([poovamraj](https://github.com/poovamraj)) +- Updated documentation regarding HMAC Key length [\#580](https://github.com/auth0/java-jwt/pull/580) ([poovamraj](https://github.com/poovamraj)) **Breaking changes** -- [SDK-3231] Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) +- Added support for multiple checks on a single claim [\#573](https://github.com/auth0/java-jwt/pull/573) ([poovamraj](https://github.com/poovamraj)) - Improve keyprovider reliability [\#570](https://github.com/auth0/java-jwt/pull/570) ([poovamraj](https://github.com/poovamraj)) - Remove ES256K support [\#556](https://github.com/auth0/java-jwt/pull/556) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3212] Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) -- [SDK-3171] Fix header claims serialization [\#549](https://github.com/auth0/java-jwt/pull/549) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3150] Serialize dates in collections as seconds since epoch [\#534](https://github.com/auth0/java-jwt/pull/534) ([jimmyjames](https://github.com/jimmyjames)) -- [SDK-3160] Replace com.auth0.jwt.interfaces.Clock with java.time.Clock [\#532](https://github.com/auth0/java-jwt/pull/532) ([jimmyjames](https://github.com/jimmyjames)) +- Remove impl package export in module-info [\#553](https://github.com/auth0/java-jwt/pull/553) ([poovamraj](https://github.com/poovamraj)) +- Fix header claims serialization [\#549](https://github.com/auth0/java-jwt/pull/549) ([jimmyjames](https://github.com/jimmyjames)) +- Serialize dates in collections as seconds since epoch [\#534](https://github.com/auth0/java-jwt/pull/534) ([jimmyjames](https://github.com/jimmyjames)) +- Replace com.auth0.jwt.interfaces.Clock with java.time.Clock [\#532](https://github.com/auth0/java-jwt/pull/532) ([jimmyjames](https://github.com/jimmyjames)) ## [3.19.2](https://github.com/auth0/java-jwt/tree/3.19.2) (2022-05-05) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.1...3.19.2) From 90a68cbeba433c1634450f7d4d32e882aec5bd79 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 24 Jun 2022 11:59:21 +0200 Subject: [PATCH 050/134] Release 4.0.0 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 123788f0..6f330308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Change Log +## [4.0.0](https://github.com/auth0/java-jwt/tree/4.0.0) (2022-06-24) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0-beta.0...4.0.0) + ## [4.0.0-beta.0](https://github.com/auth0/java-jwt/tree/4.0.0-beta.0) (2022-05-06) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0-beta.0) -💡 Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. +? Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. **Added** - JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) From b786c9dd42c2332c3caaca3b37198e8025c4b912 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 24 Jun 2022 12:16:27 +0200 Subject: [PATCH 051/134] Update release note in CHANGELOG --- CHANGELOG.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f330308..57edfa51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,24 @@ # Change Log ## [4.0.0](https://github.com/auth0/java-jwt/tree/4.0.0) (2022-06-24) -[Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0-beta.0...4.0.0) +[Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0) + +**This is a major release and contains breaking changes!** + +- Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. + +### Main features +- Predicates based claim verification +- Support for Instant API and Lambda functions +- Improved Exceptions API +- Consistent null handling + +See the changelog entries for additional details. ## [4.0.0-beta.0](https://github.com/auth0/java-jwt/tree/4.0.0-beta.0) (2022-05-06) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0-beta.0) -? Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. +- Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. **Added** - JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) From 84dc66063790905561e3bb2addffcd5bc7125697 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 24 Jun 2022 12:19:12 +0200 Subject: [PATCH 052/134] Fix emoji used in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57edfa51..6023d836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ See the changelog entries for additional details. ## [4.0.0-beta.0](https://github.com/auth0/java-jwt/tree/4.0.0-beta.0) (2022-05-06) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0-beta.0) -- Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. +💡 Check the [Migration Guide](https://github.com/auth0/java-jwt/blob/master/MIGRATION_GUIDE.md) to understand the changes required to migrate your application to v4. **Added** - JavaDoc updated [\#577](https://github.com/auth0/java-jwt/pull/577) ([poovamraj](https://github.com/poovamraj)) From 929b99ed71c086b044e9f38fb6996298b604d58a Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 24 Jun 2022 13:22:48 +0200 Subject: [PATCH 053/134] Update README.md --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f649a742..77fb30fc 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This library is supported for Java 8, 11, and 17. For issues on non-LTS versions ### Gradle ```gradle -implementation 'com.auth0:java-jwt:3.19.0' +implementation 'com.auth0:java-jwt:4.0.0' ``` ### Maven @@ -48,16 +48,10 @@ implementation 'com.auth0:java-jwt:3.19.0' com.auth0 java-jwt - 3.19.2 + 4.0.0 ``` -### Gradle - -```gradle -implementation 'com.auth0:java-jwt:3.19.2' -``` - ## Available Algorithms The library implements JWT Verification and Signing using the following algorithms: From 3e6f4b80a125df67a97df6d8eadf675d79907624 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Tue, 5 Jul 2022 17:12:01 -0400 Subject: [PATCH 054/134] Create semgrep.yml --- .github/workflows/semgrep.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/semgrep.yml diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 00000000..e0227e37 --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,24 @@ +name: Semgrep + +on: + pull_request: {} + + push: + branches: ["master", "main"] + + schedule: + - cron: '30 0 1,15 * *' + +jobs: + semgrep: + name: Scan + runs-on: ubuntu-latest + container: + image: returntocorp/semgrep + if: (github.actor != 'dependabot[bot]') + steps: + - uses: actions/checkout@v3 + + - run: semgrep ci + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} From 190132ca282c2b6ff2d12b04c1ea07224ad9f271 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 8 Jul 2022 00:24:46 -0500 Subject: [PATCH 055/134] Update config.yml --- .circleci/config.yml | 48 +++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f47d6efa..c6425bb8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,6 @@ version: 2.1 +orbs: + codecov: codecov/codecov@3 commands: checkout-and-build: @@ -8,9 +10,9 @@ commands: # Download and cache dependencies - restore_cache: keys: - - v1-dependencies-{{ checksum "build.gradle" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- + - v1-dependencies-{{ checksum "build.gradle" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- - run: ./gradlew clean build - save_cache: paths: @@ -19,10 +21,7 @@ commands: run-tests: steps: - run: ./gradlew check jacocoTestReport --continue --console=plain - - run: - name: Upload Coverage - when: on_success - command: bash <(curl -s https://codecov.io/bash) -Z -C $CIRCLE_SHA1 + - codecov/upload # TODO re-enable once 4.0.0 is released # run-api-diff: # steps: @@ -43,36 +42,21 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms512m -Xmx1024m" TERM: dumb -# api-diff: -# docker: -# - image: openjdk:11.0-jdk -# steps: -# - checkout-and-build -# - run-api-diff -# environment: -# GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' -# _JAVA_OPTIONS: "-Xms512m -Xmx1024m" -# TERM: dumb - semgrep: - docker: - - image: returntocorp/semgrep-agent:v1 - environment: - SEMGREP_REPO_NAME: "auth0/java-jwt" - SEMGREP_REPO_URL: "https://github.com/auth0/java-jwt" - steps: - - checkout - - run: - name: Run vulnerabilities tests (Semgrep) - command: | - semgrep-agent --baseline-ref master --publish-token $SEMGREP_TOKEN + # api-diff: + # docker: + # - image: openjdk:11.0-jdk + # steps: + # - checkout-and-build + # - run-api-diff + # environment: + # GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' + # _JAVA_OPTIONS: "-Xms512m -Xmx1024m" + # TERM: dumb workflows: build-and-test: jobs: - build - - semgrep: - context: - - semgrep-env # api-diff: # jobs: # - api-diff From 8dc5fbb6cde11084c9c74096d39f869910733bb8 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Mon, 11 Jul 2022 15:29:08 +0200 Subject: [PATCH 056/134] reenable api-diff check for 4.0.0 --- .circleci/config.yml | 43 +++++++++++++++++++++---------------------- lib/build.gradle | 2 +- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c6425bb8..8532ec75 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,15 +22,14 @@ commands: steps: - run: ./gradlew check jacocoTestReport --continue --console=plain - codecov/upload -# TODO re-enable once 4.0.0 is released -# run-api-diff: -# steps: -# # run apiDiff task -# - run: ./gradlew apiDiff -# - store_artifacts: -# path: lib/build/reports/apiDiff/apiDiff.txt -# - store_artifacts: -# path: lib/build/reports/apiDiff/apiDiff.html + run-api-diff: + steps: + # run apiDiff task + - run: ./gradlew apiDiff + - store_artifacts: + path: lib/build/reports/apiDiff/apiDiff.txt + - store_artifacts: + path: lib/build/reports/apiDiff/apiDiff.html jobs: build: docker: @@ -42,21 +41,21 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms512m -Xmx1024m" TERM: dumb - # api-diff: - # docker: - # - image: openjdk:11.0-jdk - # steps: - # - checkout-and-build - # - run-api-diff - # environment: - # GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - # _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - # TERM: dumb + api-diff: + docker: + - image: openjdk:11.0-jdk + steps: + - checkout-and-build + - run-api-diff + environment: + GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' + _JAVA_OPTIONS: "-Xms512m -Xmx1024m" + TERM: dumb workflows: build-and-test: jobs: - build -# api-diff: -# jobs: -# - api-diff + api-diff: + jobs: + - api-diff diff --git a/lib/build.gradle b/lib/build.gradle index b1b24889..01a5adbe 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -17,7 +17,7 @@ oss { repository "java-jwt" organization "auth0" description "Java implementation of JSON Web Token (JWT)" - baselineCompareVersion "3.18.2" + baselineCompareVersion "4.0.0" developers { auth0 { From f30a47b917478010aa91a2093f9db786ef9a7e32 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Mon, 11 Jul 2022 15:44:38 +0200 Subject: [PATCH 057/134] Update config.yml --- .circleci/config.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8532ec75..1675c39f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,16 +41,16 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms512m -Xmx1024m" TERM: dumb - api-diff: - docker: - - image: openjdk:11.0-jdk - steps: - - checkout-and-build - - run-api-diff - environment: - GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - TERM: dumb + api-diff: + docker: + - image: openjdk:11.0-jdk + steps: + - checkout-and-build + - run-api-diff + environment: + GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' + _JAVA_OPTIONS: "-Xms512m -Xmx1024m" + TERM: dumb workflows: build-and-test: From 0bf73a60152ff86014d6687c336851fe78190aba Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Fri, 22 Jul 2022 10:59:13 +0200 Subject: [PATCH 058/134] Provide straightforward example for JWKS --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 77fb30fc..822e9db7 100644 --- a/README.md +++ b/README.md @@ -199,10 +199,10 @@ By using a `KeyProvider` you can change in runtime the key used either to verify - `getPrivateKeyId()`: Its called during token signing and it should return the id of the key that identifies the one returned by `getPrivateKey()`. This value is preferred over the one set in the `JWTCreator.Builder#withKeyId(String)` method. If you don't need to set a `kid` value avoid instantiating an Algorithm using a `KeyProvider`. -The following example shows how this would work with `JwkStore`, an imaginary [JWK Set](https://auth0.com/docs/jwks) implementation. For simple key rotation using JWKS, try the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. +The following example shows how this would work with `JwkProvider` from the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. ```java -final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}"); +final JwkProvider jwkStore = new UrlJwkProvider("https://samples.auth0.com/"); final RSAPrivateKey privateKey = //Get the key instance final String privateKeyId = //Create an Id for the above key @@ -210,7 +210,7 @@ RSAKeyProvider keyProvider = new RSAKeyProvider() { @Override public RSAPublicKey getPublicKeyById(String kid) { //Received 'kid' value might be null if it wasn't defined in the Token's header - RSAPublicKey publicKey = jwkStore.get(kid); + PublicKey publicKey = jwkStore.get(kid).getPublicKey(); return (RSAPublicKey) publicKey; } From 81c8b46b8974bd2160218c2b5116e6d4dfae4a61 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Mon, 25 Jul 2022 11:02:43 +0200 Subject: [PATCH 059/134] Updated variable name for README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 822e9db7..bbc166c1 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ By using a `KeyProvider` you can change in runtime the key used either to verify The following example shows how this would work with `JwkProvider` from the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. ```java -final JwkProvider jwkStore = new UrlJwkProvider("https://samples.auth0.com/"); +final JwkProvider jwkProvider = new UrlJwkProvider("https://samples.auth0.com/"); final RSAPrivateKey privateKey = //Get the key instance final String privateKeyId = //Create an Id for the above key @@ -210,7 +210,7 @@ RSAKeyProvider keyProvider = new RSAKeyProvider() { @Override public RSAPublicKey getPublicKeyById(String kid) { //Received 'kid' value might be null if it wasn't defined in the Token's header - PublicKey publicKey = jwkStore.get(kid).getPublicKey(); + PublicKey publicKey = jwkProvider.get(kid).getPublicKey(); return (RSAPublicKey) publicKey; } From c36ec6ff80c0d62668a5ae726f9198d3ca587a17 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Mon, 22 Aug 2022 10:51:52 +0200 Subject: [PATCH 060/134] Make JWT constants final values --- lib/src/main/java/com/auth0/jwt/HeaderParams.java | 8 ++++---- .../main/java/com/auth0/jwt/RegisteredClaims.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/HeaderParams.java b/lib/src/main/java/com/auth0/jwt/HeaderParams.java index 7af3c442..1107f313 100644 --- a/lib/src/main/java/com/auth0/jwt/HeaderParams.java +++ b/lib/src/main/java/com/auth0/jwt/HeaderParams.java @@ -10,20 +10,20 @@ private HeaderParams() {} /** * The algorithm used to sign a JWT. */ - public static String ALGORITHM = "alg"; + public static final String ALGORITHM = "alg"; /** * The content type of the JWT. */ - public static String CONTENT_TYPE = "cty"; + public static final String CONTENT_TYPE = "cty"; /** * The media type of the JWT. */ - public static String TYPE = "typ"; + public static final String TYPE = "typ"; /** * The key ID of a JWT used to specify the key for signature validation. */ - public static String KEY_ID = "kid"; + public static final String KEY_ID = "kid"; } diff --git a/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java index 8c47eb51..c5509716 100644 --- a/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java +++ b/lib/src/main/java/com/auth0/jwt/RegisteredClaims.java @@ -13,43 +13,43 @@ private RegisteredClaims() { * The "iss" (issuer) claim identifies the principal that issued the JWT. * Refer RFC 7529 Section 4.1.1 */ - public static String ISSUER = "iss"; + public static final String ISSUER = "iss"; /** * The "sub" (subject) claim identifies the principal that is the subject of the JWT. * Refer RFC 7529 Section 4.1.2 */ - public static String SUBJECT = "sub"; + public static final String SUBJECT = "sub"; /** * The "aud" (audience) claim identifies the recipients that the JWT is intended for. * Refer RFC 7529 Section 4.1.3 */ - public static String AUDIENCE = "aud"; + public static final String AUDIENCE = "aud"; /** * The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be * accepted for processing. * Refer RFC 7529 Section 4.1.4 */ - public static String EXPIRES_AT = "exp"; + public static final String EXPIRES_AT = "exp"; /** * The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. * Refer RFC 7529 Section 4.1.5 */ - public static String NOT_BEFORE = "nbf"; + public static final String NOT_BEFORE = "nbf"; /** * The "iat" (issued at) claim identifies the time at which the JWT was issued. * Refer RFC 7529 Section 4.1.6 */ - public static String ISSUED_AT = "iat"; + public static final String ISSUED_AT = "iat"; /** * The "jti" (JWT ID) claim provides a unique identifier for the JWT. * Refer RFC 7529 Section 4.1.7 */ - public static String JWT_ID = "jti"; + public static final String JWT_ID = "jti"; } From 15202989d733ce695c302d2f2029bd67c919fd99 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Mon, 29 Aug 2022 19:32:23 -0500 Subject: [PATCH 061/134] [SDK-3816] Update docs for verification thread-safety --- lib/src/main/java/com/auth0/jwt/JWTVerifier.java | 6 +++++- .../java/com/auth0/jwt/interfaces/JWTVerifier.java | 14 +++++++++++++- .../com/auth0/jwt/interfaces/Verification.java | 4 +++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 0bc17fb1..07c86a4c 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -46,7 +46,11 @@ static Verification init(Algorithm algorithm) throws IllegalArgumentException { } /** - * {@link Verification} implementation that accepts all the expected Claim values for verification. + * {@link Verification} implementation that accepts all the expected Claim values for verification, and + * builds a {@link com.auth0.jwt.interfaces.JWTVerifier} used to verify a JWT's signature and expected claims. + * + * Note that this class is not thread-safe. Calling {@link #build()} returns an instance of + * {@link com.auth0.jwt.interfaces.JWTVerifier} which can be reused. */ public static class BaseVerification implements Verification { private final Algorithm algorithm; diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java index b7030a97..2756ddd8 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/JWTVerifier.java @@ -4,7 +4,19 @@ /** - * Used to verify the JWT for its signature and claims. + * Used to verify the JWT for its signature and claims. Implementations must be thread-safe. Instances are created + * using {@link Verification}. + * + *
+ * try {
+ *      JWTVerifier verifier = JWTVerifier.init(Algorithm.RSA256(publicKey, privateKey)
+ *          .withIssuer("auth0")
+ *          .build();
+ *      DecodedJWT jwt = verifier.verify("token");
+ * } catch (JWTVerificationException e) {
+ *      // invalid signature or claims
+ * }
+ * 
*/ public interface JWTVerifier { diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index 4a8a0f84..b4adcf5c 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -7,7 +7,9 @@ import java.util.function.BiPredicate; /** - * Constructs and holds the checks required for a JWT to be considered valid. + * Constructs and holds the checks required for a JWT to be considered valid. Note that implementations are + * not thread-safe. Once built by calling {@link #build()}, the resulting + * {@link com.auth0.jwt.interfaces.JWTVerifier} is thread-safe. */ public interface Verification { From f530b268354926792461926a0eb8d810be01583b Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Mon, 29 Aug 2022 20:11:33 -0500 Subject: [PATCH 062/134] Check for null token before splitting --- lib/src/main/java/com/auth0/jwt/TokenUtils.java | 3 +++ lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/lib/src/main/java/com/auth0/jwt/TokenUtils.java b/lib/src/main/java/com/auth0/jwt/TokenUtils.java index 0a76028b..6fa731c5 100644 --- a/lib/src/main/java/com/auth0/jwt/TokenUtils.java +++ b/lib/src/main/java/com/auth0/jwt/TokenUtils.java @@ -12,6 +12,9 @@ abstract class TokenUtils { * @throws JWTDecodeException if the Token doesn't have 3 parts. */ static String[] splitToken(String token) throws JWTDecodeException { + if (token == null) { + throw new JWTDecodeException("The token is null."); + } String[] parts = token.split("\\."); if (parts.length == 2 && token.endsWith(".")) { //Tokens with alg='none' have empty String as Signature. diff --git a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java index d32ee859..8649ec90 100644 --- a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java +++ b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java @@ -52,4 +52,11 @@ public void shouldThrowOnSplitTokenWithLessThan3Parts() { String token = "two.parts"; TokenUtils.splitToken(token); } + + @Test + public void shouldThrowOnSplitTokenWithNullValue() { + exception.expect(JWTDecodeException.class); + exception.expectMessage("The token is null."); + TokenUtils.splitToken(null); + } } \ No newline at end of file From 39eec490bd9ad07f7260e9fa1fd0cf60369c6036 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 31 Aug 2022 15:34:11 +0200 Subject: [PATCH 063/134] Trigger Build From 122a8af5c09b72a6fd22185970031c1a5b3e6961 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 31 Aug 2022 15:52:11 +0200 Subject: [PATCH 064/134] Disable API diff task temporarily --- .circleci/config.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1675c39f..fb185917 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,14 +22,14 @@ commands: steps: - run: ./gradlew check jacocoTestReport --continue --console=plain - codecov/upload - run-api-diff: - steps: - # run apiDiff task - - run: ./gradlew apiDiff - - store_artifacts: - path: lib/build/reports/apiDiff/apiDiff.txt - - store_artifacts: - path: lib/build/reports/apiDiff/apiDiff.html + # run-api-diff: + # steps: + # # run apiDiff task + # - run: ./gradlew apiDiff + # - store_artifacts: + # path: lib/build/reports/apiDiff/apiDiff.txt + # - store_artifacts: + # path: lib/build/reports/apiDiff/apiDiff.html jobs: build: docker: From 89fbc61318641b88e3b8b400ff4e8a67d04632fa Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 31 Aug 2022 15:56:09 +0200 Subject: [PATCH 065/134] Disable API diff --- .circleci/config.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fb185917..73f58ddb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,21 +41,21 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms512m -Xmx1024m" TERM: dumb - api-diff: - docker: - - image: openjdk:11.0-jdk - steps: - - checkout-and-build - - run-api-diff - environment: - GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - TERM: dumb + # api-diff: + # docker: + # - image: openjdk:11.0-jdk + # steps: + # - checkout-and-build + # - run-api-diff + # environment: + # GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' + # _JAVA_OPTIONS: "-Xms512m -Xmx1024m" + # TERM: dumb workflows: build-and-test: jobs: - build - api-diff: - jobs: - - api-diff + # api-diff: + # jobs: + # - api-diff From 884ac926d7f7afb7e42036a65dc739e9bed79e25 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 7 Sep 2022 10:22:13 -0500 Subject: [PATCH 066/134] Update OSS plugin to latest --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index b614415b..a4cda2d7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ pluginManagement { gradlePluginPortal() } plugins { - id 'com.auth0.gradle.oss-library.java' version '0.16.0' + id 'com.auth0.gradle.oss-library.java' version '0.17.2' } } From f29d70c56768bd7ed8356a44040082087e076cd8 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 8 Sep 2022 21:41:03 -0500 Subject: [PATCH 067/134] Update to gradle 6.9.2 --- gradle/wrapper/gradle-wrapper.properties | 2 +- lib/build.gradle | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4d9ca164..ec991f9a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/lib/build.gradle b/lib/build.gradle index 01a5adbe..eab6a0a5 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -44,7 +44,7 @@ java { compileJava { exclude 'module-info.java' // Required to be compatible with JDK 8+ - options.compilerArgs = ['--release', "8"] + options.release = 8 } javadoc { @@ -99,7 +99,8 @@ task compileModuleInfoJava(type: JavaCompile) { } compileTestJava { - options.compilerArgs = ['--release', "8", "-Xlint:deprecation"] + options.release = 8 + options.compilerArgs = ["-Xlint:deprecation"] } def testJava8 = tasks.register('testJava8', Test) { From adbabeb7c45fc3862a5d5b2c64321d06a33c725d Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Mon, 19 Sep 2022 08:17:15 -0500 Subject: [PATCH 068/134] Add Ship CLI support --- .shiprc | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .shiprc diff --git a/.shiprc b/.shiprc new file mode 100644 index 00000000..7509d078 --- /dev/null +++ b/.shiprc @@ -0,0 +1,6 @@ +{ + "files": { + "README.md": [] + }, + "prefixVersion": false +} \ No newline at end of file From 75a0bc0f9f0411891bb0e791e13dfa91a01e38ac Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Wed, 5 Oct 2022 14:52:37 +0200 Subject: [PATCH 069/134] Add integration with our Shipping orb --- .circleci/config.yml | 12 ++++++++++++ .shiprc | 3 ++- lib/build.gradle | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 73f58ddb..4741868d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,5 +1,6 @@ version: 2.1 orbs: + ship: auth0/ship@0.7.1 codecov: codecov/codecov@3 commands: @@ -56,6 +57,17 @@ workflows: build-and-test: jobs: - build + - ship/java-publish: + prefix-tag: false + context: + - publish-gh + - publish-sonatype + filters: + branches: + only: + - master + requires: + - build # api-diff: # jobs: # - api-diff diff --git a/.shiprc b/.shiprc index 7509d078..a00fb91e 100644 --- a/.shiprc +++ b/.shiprc @@ -1,6 +1,7 @@ { "files": { - "README.md": [] + "README.md": [], + "lib/build.gradle": [] }, "prefixVersion": false } \ No newline at end of file diff --git a/lib/build.gradle b/lib/build.gradle index eab6a0a5..74cdb5c1 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,3 +1,7 @@ +buildscript { + version = "4.0.0" +} + plugins { id 'java' id 'jacoco' @@ -5,6 +9,13 @@ plugins { id 'checkstyle' } +def signingKey = findProperty('SIGNING_KEY') +def signingKeyPwd = findProperty('SIGNING_PASSWORD') + +signing { + useInMemoryPgpKeys(signingKey, signingKeyPwd) +} + checkstyle { toolVersion '10.0' checkstyleTest.enabled = false //We are disabling lint checks for tests @@ -134,3 +145,11 @@ jar { compileModuleInfoJava.dependsOn compileJava classes.dependsOn compileModuleInfoJava + +// Creates a version.txt file containing the current version of the SDK. +// This file is picked up and parsed by our Ship Orb to determine the version. +task exportVersion() { + doLast { + new File(rootDir, "version.txt").text = "$version" + } +} From d2bf8d35e96ea8233f2a80ca6d7371ad54e5ba18 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 6 Oct 2022 13:47:56 -0500 Subject: [PATCH 070/134] Release 4.1.0 --- CHANGELOG.md | 21 +++++++++++++++++++++ README.md | 4 ++-- lib/build.gradle | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6023d836..04796fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## [4.1.0](https://github.com/auth0/java-jwt/tree/4.1.0) (2022-10-06) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0...4.1.0) + +**⚠️ BREAKING CHANGES** +- Make JWT constants final values [\#604](https://github.com/auth0/java-jwt/pull/604) ([poovamraj](https://github.com/poovamraj)) + +**Added** +- Add integration with our Shipping orb [\#612](https://github.com/auth0/java-jwt/pull/612) ([frederikprijck](https://github.com/frederikprijck)) +- Add Ship CLI support [\#609](https://github.com/auth0/java-jwt/pull/609) ([jimmyjames](https://github.com/jimmyjames)) +- Provide straightforward example for JWKS [\#600](https://github.com/auth0/java-jwt/pull/600) ([poovamraj](https://github.com/poovamraj)) + +**Changed** +- Update to gradle 6.9.2 [\#608](https://github.com/auth0/java-jwt/pull/608) ([jimmyjames](https://github.com/jimmyjames)) +- Update OSS plugin to latest [\#607](https://github.com/auth0/java-jwt/pull/607) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3466] Upgrade Codecov [\#595](https://github.com/auth0/java-jwt/pull/595) ([evansims](https://github.com/evansims)) +- Update README.md [\#590](https://github.com/auth0/java-jwt/pull/590) ([poovamraj](https://github.com/poovamraj)) + +**Fixed** +- Check for null token before splitting [\#606](https://github.com/auth0/java-jwt/pull/606) ([jimmyjames](https://github.com/jimmyjames)) +- [SDK-3816] Update docs for verification thread-safety [\#605](https://github.com/auth0/java-jwt/pull/605) ([jimmyjames](https://github.com/jimmyjames)) + ## [4.0.0](https://github.com/auth0/java-jwt/tree/4.0.0) (2022-06-24) [Full Changelog](https://github.com/auth0/java-jwt/compare/3.19.2...4.0.0) diff --git a/README.md b/README.md index bbc166c1..a4fa509e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This library is supported for Java 8, 11, and 17. For issues on non-LTS versions ### Gradle ```gradle -implementation 'com.auth0:java-jwt:4.0.0' +implementation 'com.auth0:java-jwt:4.1.0' ``` ### Maven @@ -48,7 +48,7 @@ implementation 'com.auth0:java-jwt:4.0.0' com.auth0 java-jwt - 4.0.0 + 4.1.0 ``` diff --git a/lib/build.gradle b/lib/build.gradle index 74cdb5c1..8ec1b630 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,5 +1,5 @@ buildscript { - version = "4.0.0" + version = "4.1.0" } plugins { From 9c708c2ca0a9c7a6ab7b900fcf4292d0654a78ea Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Mon, 10 Oct 2022 21:08:49 +0200 Subject: [PATCH 071/134] Update config.yml --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4741868d..505c6f70 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - ship: auth0/ship@0.7.1 + ship: auth0/ship@dev:a88c4d7 codecov: codecov/codecov@3 commands: @@ -66,6 +66,7 @@ workflows: branches: only: - master + - automated-release requires: - build # api-diff: From 7cac89a50bafa65cafebbc919d8b18616b173853 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Mon, 10 Oct 2022 21:19:03 +0200 Subject: [PATCH 072/134] Update config.yml --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 505c6f70..b431f8d7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -59,6 +59,7 @@ workflows: - build - ship/java-publish: prefix-tag: false + package-name: java-jwt context: - publish-gh - publish-sonatype From 245c019bd20bb479b68f220d576e5ad78cae9779 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Mon, 10 Oct 2022 21:23:39 +0200 Subject: [PATCH 073/134] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b431f8d7..10a12231 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - ship: auth0/ship@dev:a88c4d7 + ship: auth0/ship@dev:9412fdc codecov: codecov/codecov@3 commands: From bd9c8133025c9da93ce7d5f8885fea43b75c2421 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Mon, 10 Oct 2022 21:35:27 +0200 Subject: [PATCH 074/134] Update config.yml --- .circleci/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 10a12231..6a313263 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - ship: auth0/ship@dev:9412fdc + ship: auth0/ship@dev:d4bf2df codecov: codecov/codecov@3 commands: @@ -59,7 +59,6 @@ workflows: - build - ship/java-publish: prefix-tag: false - package-name: java-jwt context: - publish-gh - publish-sonatype From 6a666b0c822d8a453405e67f702c0b326d2d8a5c Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Tue, 11 Oct 2022 12:05:04 +0200 Subject: [PATCH 075/134] update build.gradle file --- lib/build.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/build.gradle b/lib/build.gradle index 8ec1b630..d7951ff3 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -9,8 +9,8 @@ plugins { id 'checkstyle' } -def signingKey = findProperty('SIGNING_KEY') -def signingKeyPwd = findProperty('SIGNING_PASSWORD') +def signingKey = findProperty('signingKey') +def signingKeyPwd = findProperty('signingPassword') signing { useInMemoryPgpKeys(signingKey, signingKeyPwd) @@ -29,6 +29,7 @@ oss { organization "auth0" description "Java implementation of JSON Web Token (JWT)" baselineCompareVersion "4.0.0" + skipAssertSigningConfiguration true developers { auth0 { @@ -66,6 +67,7 @@ javadoc { dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2' + testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' testImplementation 'net.jodah:concurrentunit:0.4.6' From 4fbe13f8da785c4826cf5b8fd4c3fec708cdda89 Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Tue, 11 Oct 2022 12:18:20 +0200 Subject: [PATCH 076/134] revert changes --- .circleci/config.yml | 1 - lib/build.gradle | 1 - 2 files changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6a313263..23f09bb2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,7 +66,6 @@ workflows: branches: only: - master - - automated-release requires: - build # api-diff: diff --git a/lib/build.gradle b/lib/build.gradle index d7951ff3..3649399c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -67,7 +67,6 @@ javadoc { dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2' - testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' testImplementation 'net.jodah:concurrentunit:0.4.6' From a2ecb759b2b0200f5a61fe9227b5a2ddf804eee7 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Tue, 11 Oct 2022 15:16:41 +0200 Subject: [PATCH 077/134] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 23f09bb2..e6b1dcd9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - ship: auth0/ship@dev:d4bf2df + ship: auth0/ship@0.7.2 codecov: codecov/codecov@3 commands: From 1e9072d5b0f762f8fe83c6674cd9a3a77bc83255 Mon Sep 17 00:00:00 2001 From: noetro Date: Sat, 15 Oct 2022 03:34:26 +0200 Subject: [PATCH 078/134] Optimise TokenUtils parsing (#611) * Optimise parsing of token for well-defined JWT format * Update error message in test to match new code * Fixing checkstyle issues * Added missing test case for no parts * Return new JWTDecodeException Return a new JWTDecodeException from private utility method `wrongNumberOfParts`, instead of throwing, since we throw from `splitToken()`. Co-authored-by: Jim Anderson Co-authored-by: Jim Anderson --- .../main/java/com/auth0/jwt/TokenUtils.java | 32 ++++++++++++---- .../java/com/auth0/jwt/JWTDecoderTest.java | 2 +- .../java/com/auth0/jwt/TokenUtilsTest.java | 38 +++++++++++++++++-- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/TokenUtils.java b/lib/src/main/java/com/auth0/jwt/TokenUtils.java index 6fa731c5..e62b9832 100644 --- a/lib/src/main/java/com/auth0/jwt/TokenUtils.java +++ b/lib/src/main/java/com/auth0/jwt/TokenUtils.java @@ -15,15 +15,33 @@ static String[] splitToken(String token) throws JWTDecodeException { if (token == null) { throw new JWTDecodeException("The token is null."); } - String[] parts = token.split("\\."); - if (parts.length == 2 && token.endsWith(".")) { - //Tokens with alg='none' have empty String as Signature. - parts = new String[]{parts[0], parts[1], ""}; + + char delimiter = '.'; + + int firstPeriodIndex = token.indexOf(delimiter); + if (firstPeriodIndex == -1) { + throw wrongNumberOfParts(0); } - if (parts.length != 3) { - throw new JWTDecodeException( - String.format("The token was expected to have 3 parts, but got %s.", parts.length)); + + int secondPeriodIndex = token.indexOf(delimiter, firstPeriodIndex + 1); + if (secondPeriodIndex == -1) { + throw wrongNumberOfParts(2); + } + + // too many ? + if (token.indexOf(delimiter, secondPeriodIndex + 1) != -1) { + throw wrongNumberOfParts("> 3"); } + + String[] parts = new String[3]; + parts[0] = token.substring(0, firstPeriodIndex); + parts[1] = token.substring(firstPeriodIndex + 1, secondPeriodIndex); + parts[2] = token.substring(secondPeriodIndex + 1); + return parts; } + + private static JWTDecodeException wrongNumberOfParts(Object partCount) { + return new JWTDecodeException(String.format("The token was expected to have 3 parts, but got %s.", partCount)); + } } diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index 82dc895c..cc427d60 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -50,7 +50,7 @@ public void shouldThrowIfLessThan3Parts() { @Test public void shouldThrowIfMoreThan3Parts() { exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got 4."); + exception.expectMessage("The token was expected to have 3 parts, but got > 3."); JWT.decode("this.has.four.parts"); } diff --git a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java index 8649ec90..01806ddc 100644 --- a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java +++ b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java @@ -13,6 +13,30 @@ public class TokenUtilsTest { @Rule public ExpectedException exception = ExpectedException.none(); + @Test + public void toleratesEmptyFirstPart() { + String token = ".eyJpc3MiOiJhdXRoMCJ9.W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; + String[] parts = TokenUtils.splitToken(token); + + assertThat(parts, is(notNullValue())); + assertThat(parts, is(arrayWithSize(3))); + assertThat(parts[0], is("")); + assertThat(parts[1], is("eyJpc3MiOiJhdXRoMCJ9")); + assertThat(parts[2], is("W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc")); + } + + @Test + public void toleratesEmptySecondPart() { + String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0..W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; + String[] parts = TokenUtils.splitToken(token); + + assertThat(parts, is(notNullValue())); + assertThat(parts, is(arrayWithSize(3))); + assertThat(parts[0], is("eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0")); + assertThat(parts[1], is("")); + assertThat(parts[2], is("W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc")); + } + @Test public void shouldSplitToken() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; @@ -34,19 +58,27 @@ public void shouldSplitTokenWithEmptySignature() { assertThat(parts, is(arrayWithSize(3))); assertThat(parts[0], is("eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0")); assertThat(parts[1], is("eyJpc3MiOiJhdXRoMCJ9")); - assertThat(parts[2], is(isEmptyString())); + assertThat(parts[2], is(emptyString())); } @Test public void shouldThrowOnSplitTokenWithMoreThan3Parts() { exception.expect(JWTDecodeException.class); - exception.expectMessage("The token was expected to have 3 parts, but got 4."); + exception.expectMessage("The token was expected to have 3 parts, but got > 3."); String token = "this.has.four.parts"; TokenUtils.splitToken(token); } @Test - public void shouldThrowOnSplitTokenWithLessThan3Parts() { + public void shouldThrowOnSplitTokenWithNoParts() { + exception.expect(JWTDecodeException.class); + exception.expectMessage("The token was expected to have 3 parts, but got 0."); + String token = "notajwt"; + TokenUtils.splitToken(token); + } + + @Test + public void shouldThrowOnSplitTokenWith2Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 2."); String token = "two.parts"; From 9840e74b7ef87ce9678d2ee71308499fb1b6f757 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Fri, 14 Oct 2022 20:37:24 -0500 Subject: [PATCH 079/134] Update Claim#asString documentation (#615) --- lib/src/main/java/com/auth0/jwt/interfaces/Claim.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java index 7c4da4f7..ca5244d6 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java @@ -62,9 +62,10 @@ public interface Claim { /** * Get this Claim as a String. - * If the value isn't of type String or it can't be converted to a String, {@code null} will be returned. + * If the value isn't of type String, {@code null} will be returned. For a String representation of non-textual + * claim types, clients can call {@code toString()}. * - * @return the value as a String or null. + * @return the value as a String or null if the underlying value is not a string. */ String asString(); From 1875ed74b136422952080b5f2ac7656e67e51f27 Mon Sep 17 00:00:00 2001 From: "sre-57-opslevel[bot]" <113727212+sre-57-opslevel[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:07:35 +0000 Subject: [PATCH 080/134] Upload OpsLevel YAML --- opslevel.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 opslevel.yml diff --git a/opslevel.yml b/opslevel.yml new file mode 100644 index 00000000..009a5ec0 --- /dev/null +++ b/opslevel.yml @@ -0,0 +1,6 @@ +--- +version: 1 +repository: + owner: dx_sdks + tier: + tags: From e8808abb910bb2d3ea8da816e626a7df9fc543e9 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 19 Oct 2022 10:25:34 -0500 Subject: [PATCH 081/134] Update .shiprc to only update lib version in build.gradle (#625) --- .shiprc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.shiprc b/.shiprc index a00fb91e..2bd0fdb3 100644 --- a/.shiprc +++ b/.shiprc @@ -1,7 +1,7 @@ { "files": { "README.md": [], - "lib/build.gradle": [] + "lib/build.gradle": ["version[[:blank:]]*=[[:blank:]]*{MAJOR}.{MINOR}.{PATCH}"] }, "prefixVersion": false } \ No newline at end of file From 49c5def67ab2d37aa98f210bec2ca5ea39889d8c Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 19 Oct 2022 10:46:57 -0500 Subject: [PATCH 082/134] Re-enable japicmp API diff checking (#619) --- .circleci/config.yml | 42 +++++++++++++++++++++--------------------- lib/build.gradle | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e6b1dcd9..32e9d4de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,14 +23,14 @@ commands: steps: - run: ./gradlew check jacocoTestReport --continue --console=plain - codecov/upload - # run-api-diff: - # steps: - # # run apiDiff task - # - run: ./gradlew apiDiff - # - store_artifacts: - # path: lib/build/reports/apiDiff/apiDiff.txt - # - store_artifacts: - # path: lib/build/reports/apiDiff/apiDiff.html + run-api-diff: + steps: + # run apiDiff task + - run: ./gradlew apiDiff + - store_artifacts: + path: lib/build/reports/apiDiff/apiDiff.txt + - store_artifacts: + path: lib/build/reports/apiDiff/apiDiff.html jobs: build: docker: @@ -42,16 +42,16 @@ jobs: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms512m -Xmx1024m" TERM: dumb - # api-diff: - # docker: - # - image: openjdk:11.0-jdk - # steps: - # - checkout-and-build - # - run-api-diff - # environment: - # GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - # _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - # TERM: dumb + api-diff: + docker: + - image: openjdk:11.0-jdk + steps: + - checkout-and-build + - run-api-diff + environment: + GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' + _JAVA_OPTIONS: "-Xms512m -Xmx1024m" + TERM: dumb workflows: build-and-test: @@ -68,6 +68,6 @@ workflows: - master requires: - build - # api-diff: - # jobs: - # - api-diff + api-diff: + jobs: + - api-diff diff --git a/lib/build.gradle b/lib/build.gradle index 3649399c..a0d7a7da 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -28,7 +28,7 @@ oss { repository "java-jwt" organization "auth0" description "Java implementation of JSON Web Token (JWT)" - baselineCompareVersion "4.0.0" + baselineCompareVersion "4.1.0" skipAssertSigningConfiguration true developers { From 3526fcc80ec15038de1a13a2c84d55d2453c835a Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 19 Oct 2022 21:53:07 -0500 Subject: [PATCH 083/134] Release 4.2.0 (#626) --- CHANGELOG.md | 12 ++++++++++++ README.md | 4 ++-- lib/build.gradle | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04796fd7..c6c2d511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## [4.2.0](https://github.com/auth0/java-jwt/tree/4.2.0) (2022-10-19) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.1.0...4.2.0) + +**Changed** +- Re-enable japicmp API diff checking [\#619](https://github.com/auth0/java-jwt/pull/619) ([jimmyjames](https://github.com/jimmyjames)) +- Update .shiprc to only update lib version in build.gradle [\#625](https://github.com/auth0/java-jwt/pull/625) ([jimmyjames](https://github.com/jimmyjames)) +- Optimise TokenUtils parsing [\#611](https://github.com/auth0/java-jwt/pull/611) ([noetro](https://github.com/noetro)) +- Update Circle Ship Orb configuration [\#616](https://github.com/auth0/java-jwt/pull/616) ([frederikprijck](https://github.com/frederikprijck)) + +**Fixed** +- Update Claim#asString documentation [\#615](https://github.com/auth0/java-jwt/pull/615) ([jimmyjames](https://github.com/jimmyjames)) + ## [4.1.0](https://github.com/auth0/java-jwt/tree/4.1.0) (2022-10-06) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.0.0...4.1.0) diff --git a/README.md b/README.md index a4fa509e..89b67ad8 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This library is supported for Java 8, 11, and 17. For issues on non-LTS versions ### Gradle ```gradle -implementation 'com.auth0:java-jwt:4.1.0' +implementation 'com.auth0:java-jwt:4.2.0' ``` ### Maven @@ -48,7 +48,7 @@ implementation 'com.auth0:java-jwt:4.1.0' com.auth0 java-jwt - 4.1.0 + 4.2.0 ``` diff --git a/lib/build.gradle b/lib/build.gradle index a0d7a7da..05807472 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,5 +1,5 @@ buildscript { - version = "4.1.0" + version = "4.2.0" } plugins { From 32935767d3414d1e91feec41ee69159b3d2524eb Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 20 Oct 2022 17:08:35 -0500 Subject: [PATCH 084/134] Fix .shiprc build.gradle version substitution pattern (#627) --- .shiprc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.shiprc b/.shiprc index 2bd0fdb3..fe59345e 100644 --- a/.shiprc +++ b/.shiprc @@ -1,7 +1,7 @@ { "files": { "README.md": [], - "lib/build.gradle": ["version[[:blank:]]*=[[:blank:]]*{MAJOR}.{MINOR}.{PATCH}"] + "lib/build.gradle": ["version = \"{MAJOR}.{MINOR}.{PATCH}\""] }, "prefixVersion": false } \ No newline at end of file From 3d3980de9c0a84b6265de9263647cdbfda7c8a5b Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Sat, 22 Oct 2022 21:02:48 -0500 Subject: [PATCH 085/134] Update ship orb (#629) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 32e9d4de..9cf198c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - ship: auth0/ship@0.7.2 + ship: auth0/ship@0.7.3 codecov: codecov/codecov@3 commands: From c8d0ba995543c9cee50abe9f4aa4f9873b29489f Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 24 Oct 2022 09:14:06 -0500 Subject: [PATCH 086/134] Bump `com.fasterxml.jackson.core:jackson-databind` to 2.13.4.2 (#630) Resolves https://www.cve.org/CVERecord?id=CVE-2022-42003 --- lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/build.gradle b/lib/build.gradle index 05807472..9cc4349c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -65,7 +65,7 @@ javadoc { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4.2' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' From 3cff66f1a23b51ab85ae4d7c5c1837b90677c75e Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Mon, 24 Oct 2022 16:52:15 -0500 Subject: [PATCH 087/134] Use latest ship orb (#634) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9cf198c8..6c87574b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - ship: auth0/ship@0.7.3 + ship: auth0/ship@0 codecov: codecov/codecov@3 commands: From 4c2533dbd0bc1aa714ac7d0e291652cdaecdd265 Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Tue, 25 Oct 2022 06:08:09 +0400 Subject: [PATCH 088/134] Remove emoji to fix the broken documentation link (#632) Co-authored-by: Jim Anderson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89b67ad8..f96e806f 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); > Note: How you obtain or read keys is not in the scope of this library. For an example of how you might implement this, see [this gist](https://gist.github.com/lbalmaceda/9a0c7890c2965826c04119dcfb1a5469). -##### :key: HMAC Key Length and Security +##### HMAC Key Length and Security When using a Hash-based Message Authentication Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recommendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. From 1e38286a52936d7ccdae3f457369389ad7474b7a Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Tue, 25 Oct 2022 07:26:20 -0500 Subject: [PATCH 089/134] Release 4.2.1 (#636) --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- lib/build.gradle | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c2d511..ed3706dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [4.2.1](https://github.com/auth0/java-jwt/tree/4.2.1) (2022-10-24) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.0...4.2.1) + +**Security** +- Use latest ship orb [\#634](https://github.com/auth0/java-jwt/pull/634) ([jimmyjames](https://github.com/jimmyjames)) +- Bump `com.fasterxml.jackson.core:jackson-databind` to 2.13.4.2 [\#630](https://github.com/auth0/java-jwt/pull/630) ([evansims](https://github.com/evansims)) + ## [4.2.0](https://github.com/auth0/java-jwt/tree/4.2.0) (2022-10-19) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.1.0...4.2.0) diff --git a/README.md b/README.md index f96e806f..bfa4345d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This library is supported for Java 8, 11, and 17. For issues on non-LTS versions ### Gradle ```gradle -implementation 'com.auth0:java-jwt:4.2.0' +implementation 'com.auth0:java-jwt:4.2.1' ``` ### Maven @@ -48,7 +48,7 @@ implementation 'com.auth0:java-jwt:4.2.0' com.auth0 java-jwt - 4.2.0 + 4.2.1 ``` diff --git a/lib/build.gradle b/lib/build.gradle index 9cc4349c..d6c9b061 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,5 +1,5 @@ buildscript { - version = "4.2.0" + version = "4.2.1" } plugins { From d0ebc3f50581f3341a9b214f32612926b8b1a201 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Wed, 26 Oct 2022 03:38:39 -0500 Subject: [PATCH 090/134] [SDK-3694] README redesign (#617) --- EXAMPLES.md | 130 +++++++++++++ README.md | 523 ++++++++-------------------------------------------- 2 files changed, 206 insertions(+), 447 deletions(-) create mode 100644 EXAMPLES.md diff --git a/EXAMPLES.md b/EXAMPLES.md new file mode 100644 index 00000000..8a849303 --- /dev/null +++ b/EXAMPLES.md @@ -0,0 +1,130 @@ +# Examples using java-jwt + +* [Inspecting a DecodedJWT](#inspecting-a-decodedjwt) +* [DateTime Claim Validation](#datetime-claim-validation) +* [Using custom claims](#using-custom-claims) +* [Using a KeyProvider](#using-a-keyprovider) + +## Inspecting a DecodedJWT + +The successful verification of a JWT returns a `DecodedJWT`, from which you can obtain its contents. + +```java +DecodedJWT jwt = JWT.require(algorithm) + .build() + .verify("a.b.c"); + +// standard claims can be retrieved through first-class methods +String subject = jwt.getSubject(); +String aud = jwt.getAudience(); +// ... + +// custom claims can also be obtained +String customStringClaim = jwt.getClaim("custom-string-claim").asString(); +``` + +When retrieving custom claims, a [Claim](https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/interfaces/Claim.html) is returned, which can then be used to obtain the value depending on the value's underlying type. + +## DateTime Claim Validation + +A JWT token may include DateNumber fields that can be used to validate that: + +* The token was issued in a past date `"iat" < NOW` +* The token hasn't expired yet `"exp" > NOW` +* The token can already be used. `"nbf" < NOW` + +When verifying a JWT, the standard DateTime claims are validated by default. A `JWTVerificationException` is thrown if any of the claim values are invalid. + +To specify a **leeway** in which the JWT should still be considered valid, use the `acceptLeeway()` method in the `JWTVerifier` builder and pass a positive seconds value. This applies to every item listed above. + +```java +JWTVerifier verifier = JWT.require(algorithm) + .acceptLeeway(1) // 1 sec for nbf, iat and exp + .build(); +``` + +You can also specify a custom value for a given DateTime claim and override the default one for only that claim. + +```java +JWTVerifier verifier = JWT.require(algorithm) + .acceptLeeway(1) //1 sec for nbf and iat + .acceptExpiresAt(5) //5 secs for exp + .build(); +``` + +If you need to test this behavior in your application, cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a `java.time.Clock`. e.g.: + +```java +BaseVerification verification = (BaseVerification) JWT.require(algorithm) + .acceptLeeway(1) + .acceptExpiresAt(5); +private final Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); +JWTVerifier verifier = verification.build(clock); +``` + +## Using custom claims + +### JWT creation +A JWT can be built with custom payload and header claims, by using the `withHeader` and `withClaim` methods. + +```java +String jwt = JWT.create() + .withHeader(headerMap) + .withClaim("string-claim", "string-value") + .withClaim("number-claim", 42) + .withClaim("bool-claim", true) + .withClaim("datetime-claim", Instant.now()) + .sign(algorithm); +``` + +See the [JavaDoc](https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/JWTCreator.Builder.html) for all available custom claim methods. + +### JWT verification + +You can also verify a JWT's custom claims: + +```java +JWTVerifier verifier = JWT.require(algorithm) + .withClaim("number-claim", 123) + .withClaimPresence("some-claim-that-just-needs-to-be-present") + .withClaim("predicate-claim", (claim, decodedJWT) -> "custom value".equals(claim.asString())) + .build(); +DecodedJWT jwt = verifier.verify("my.jwt.token"); +``` + +See the [JavaDoc](https://javadoc.io/doc/com.auth0/java-jwt/latest/com/auth0/jwt/JWTVerifier.BaseVerification.html) for all available custom claim verification methods. + +## Using a KeyProvider + +A `KeyProvider` can be used to obtain the keys needed for signing and verifying a JWT. How these keys are constructed are beyond the scope of this library, but the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library provides the ability to obtain the public key from a JWK. +The example below demonstrates this for the RSA algorithm (`ECDSAKeyProvider` can be used for ECDSA). + +```java +JwkProvider provider = new JwkProviderBuilder("https://samples.auth0.com/") + .cached(10, 24, TimeUnit.HOURS) + .rateLimited(10, 1, TimeUnit.MINUTES) + .build(); +final RSAPrivateKey privateKey = // private key +final String privateKeyId = // private key ID + +RSAKeyProvider keyProvider = new RSAKeyProvider() { + @Override + public RSAPublicKey getPublicKeyById(String kid) { + return (RSAPublicKey) jwkProvider.get(kid).getPublicKey(); + } + + @Override + public RSAPrivateKey getPrivateKey() { + // return the private key used + return rsaPrivateKey; + } + + @Override + public String getPrivateKeyId() { + return rsaPrivateKeyId; + } +}; + +Algorithm algorithm = Algorithm.RSA256(keyProvider); +//Use the Algorithm to create and verify JWTs. +``` \ No newline at end of file diff --git a/README.md b/README.md index bfa4345d..7786cbaf 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,26 @@ - - -# Java JWT +![A Java implementation of JSON Web Token (JWT) - RFC 7519.](https://cdn.auth0.com/website/sdks/banners/java-jwt-banner.png) [![CircleCI](https://img.shields.io/circleci/project/github/auth0/java-jwt.svg?style=flat-square)](https://circleci.com/gh/auth0/java-jwt/tree/master) [![Coverage Status](https://img.shields.io/codecov/c/github/auth0/java-jwt.svg?style=flat-square)](https://codecov.io/github/auth0/java-jwt) -[![License](https://img.shields.io/:license-mit-blue.svg?style=flat)](https://doge.mit-license.org) -[![Javadoc](https://javadoc.io/badge2/com.auth0/java-jwt/javadoc.svg)](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html) - -A Java implementation of [JSON Web Token (JWT) - RFC 7519](https://tools.ietf.org/html/rfc7519). +[![License](http://img.shields.io/:license-mit-blue.svg?style=flat)](https://doge.mit-license.org/) +[![Maven Central](https://img.shields.io/maven-central/v/com.auth0/java-jwt.svg?style=flat-square)](https://mvnrepository.com/artifact/com.auth0/java-jwt) +[![javadoc](https://javadoc.io/badge2/com.auth0/auth0/javadoc.svg)](https://javadoc.io/doc/com.auth0/java-jwt) -> :warning: **Important security note:** JVM has a critical vulnerability for ECDSA Algorithms - [CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449). Please review the details of the vulnerability and update your environment. - -If you're looking for an **Android** version of the JWT Decoder take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library. +:books: [Documentation](#documentation) - :rocket: [Getting Started](#getting-started) - :computer: [API Reference](#api-reference) :speech_balloon: [Feedback](#feedback) -> You are viewing the documentation for the v4 beta release. For the latest stable release, please see the [version 3.x documentation](https://github.com/auth0/java-jwt). +## Documentation +- [Examples](./EXAMPLES.md) - code samples for common java-jwt scenarios. +- [Docs site](https://www.auth0.com/docs) - explore our docs site and learn more about Auth0. -## Table of Contents -- [**Requirements**](#requirements) -- [**Installation**](#installation) -- [**Available Algorithms**](#available-algorithms) -- [**Quickstart**](#quickstart) - + [**Create and Sign a Token**](#create-and-sign-a-token) - + [**Verify a Token**](#verify-a-token) -- [**Usage**](#usage) - + [**Pick the algorithm**](#pick-the-algorithm) - + [**Time Validation**](#time-validation) - + [**Header Claims**](#header-claims) - + [**Payload Claims**](#payload-claims) - + [**Claim Class**](#claim-class) -- [**Javadoc**](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html) +## Getting Started -## Requirements +### Requirements -This library is supported for Java 8, 11, and 17. For issues on non-LTS versions above 8, consideration will be given on a case-by-case basis. +This library is supported for Java LTS versions 8, 11, and 17. For issues on non-LTS versions above 8, consideration will be given on a case-by-case basis. -## Installation +> `java-jwt` is intended for server-side JVM applications. Android applications should use [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android). -### Gradle - -```gradle -implementation 'com.auth0:java-jwt:4.2.1' -``` - -### Maven - -```xml - - com.auth0 - java-jwt - 4.2.1 - -``` - -## Available Algorithms - -The library implements JWT Verification and Signing using the following algorithms: +`java-jwt` supports the following algorithms for both signing and verification: | JWS | Algorithm | Description | | :-------------: | :-------------: | :----- | @@ -70,434 +36,97 @@ The library implements JWT Verification and Signing using the following algorith > Note - Support for ECDSA with curve secp256k1 and SHA-256 (ES256K) has been dropped since it has been [disabled in Java 15](https://www.oracle.com/java/technologies/javase/15-relnote-issues.html#JDK-8237219) -## Quickstart - -### Create and Sign a Token - -You'll first need to create a `JWTCreator` instance by calling `JWT.create()`. Use the builder to define the custom Claims your token needs to have. Finally to get the String token call `sign()` and pass the `Algorithm` instance. - -* Example using `HS256` - - ```java - try { - Algorithm algorithm = Algorithm.HMAC256("secret"); - String token = JWT.create() - .withIssuer("auth0") - .sign(algorithm); - } catch (JWTCreationException exception){ - //Invalid Signing configuration / Couldn't convert Claims. - } - ``` - -* Example using `RS256` - - ```java - RSAPublicKey publicKey = //Get the key instance - RSAPrivateKey privateKey = //Get the key instance - try { - Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); - String token = JWT.create() - .withIssuer("auth0") - .sign(algorithm); - } catch (JWTCreationException exception){ - //Invalid Signing configuration / Couldn't convert Claims. - } - ``` - -If a Claim couldn't be converted to JSON or the Key used in the signing process was invalid a `JWTCreationException` will raise. - -### Verify a Token - -You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` and passing the `Algorithm` instance. If you require the token to have specific Claim values, use the builder to define them. The instance returned by the method `build()` is reusable, so you can define it once and use it to verify different tokens. Finally call `verifier.verify()` passing the token. - -* Example using `HS256` - - ```java - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; - try { - Algorithm algorithm = Algorithm.HMAC256("secret"); //use more secure key - JWTVerifier verifier = JWT.require(algorithm) - .withIssuer("auth0") - .build(); //Reusable verifier instance - DecodedJWT jwt = verifier.verify(token); - } catch (JWTVerificationException exception){ - //Invalid signature/claims - } - ``` - -* Example using `RS256` - - ```java - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; - RSAPublicKey publicKey = //Get the key instance - RSAPrivateKey privateKey = //Get the key instance - try { - Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); - JWTVerifier verifier = JWT.require(algorithm) - .withIssuer("auth0") - .build(); //Reusable verifier instance - DecodedJWT jwt = verifier.verify(token); - } catch (JWTVerificationException exception){ - //Invalid signature/claims - } - ``` - -If the token has an invalid signature or the Claim requirement is not met, a `JWTVerificationException` will raise. - -
-Need to peek into a JWT without verifying it? (Click to expand) - -### Decode a Token - -> __Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `JWTVerifier` as documented above instead. - -```java -String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; -try { - DecodedJWT jwt = JWT.decode(token); -} catch (JWTDecodeException exception){ - //Invalid token -} -``` - -If the token has an invalid syntax or the header or payload are not JSONs, a `JWTDecodeException` will raise. - -
- -## Usage - -### Pick the Algorithm - -The Algorithm defines how a token is signed and verified. It can be instantiated with the raw value of the secret in the case of HMAC algorithms, or the key pairs or `KeyProvider` in the case of RSA and ECDSA algorithms. Once created, the instance is reusable for token signing and verification operations. - -When using RSA or ECDSA algorithms and you just need to **sign** JWTs you can avoid specifying a Public Key by passing a `null` value. The same can be done with the Private Key when you just need to **verify** JWTs. - - -#### Using static secrets or keys: - -```java -//HMAC -Algorithm algorithmHS = Algorithm.HMAC256("secret"); //use more secure key - -//RSA -RSAPublicKey publicKey = //Get the key instance -RSAPrivateKey privateKey = //Get the key instance -Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); -``` - -> Note: How you obtain or read keys is not in the scope of this library. For an example of how you might implement this, see [this gist](https://gist.github.com/lbalmaceda/9a0c7890c2965826c04119dcfb1a5469). - -##### HMAC Key Length and Security - -When using a Hash-based Message Authentication Code, e.g. HS256 or HS512, in order to comply with the strict requirements of the JSON Web Algorithms (JWA) specification (RFC7518), you **must** use a secret key which has the same (or larger) bit length as the size of the output hash. This is to avoid weakening the security strength of the authentication code (see NIST recommendations NIST SP 800-117). For example, when using HMAC256, the secret key length must be a minimum of 256 bits. - -#### Using a KeyProvider: -By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: - -- `getPublicKeyById(String kid)`: Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. [JWK](https://tools.ietf.org/html/rfc7517) it can fetch the correct rotation key using the id. (Or just return the same key all the time). -- `getPrivateKey()`: Its called during token signing and it should return the key that will be used to sign the JWT. -- `getPrivateKeyId()`: Its called during token signing and it should return the id of the key that identifies the one returned by `getPrivateKey()`. This value is preferred over the one set in the `JWTCreator.Builder#withKeyId(String)` method. If you don't need to set a `kid` value avoid instantiating an Algorithm using a `KeyProvider`. - - -The following example shows how this would work with `JwkProvider` from the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. - -```java -final JwkProvider jwkProvider = new UrlJwkProvider("https://samples.auth0.com/"); -final RSAPrivateKey privateKey = //Get the key instance -final String privateKeyId = //Create an Id for the above key - -RSAKeyProvider keyProvider = new RSAKeyProvider() { - @Override - public RSAPublicKey getPublicKeyById(String kid) { - //Received 'kid' value might be null if it wasn't defined in the Token's header - PublicKey publicKey = jwkProvider.get(kid).getPublicKey(); - return (RSAPublicKey) publicKey; - } - - @Override - public RSAPrivateKey getPrivateKey() { - return privateKey; - } - - @Override - public String getPrivateKeyId() { - return privateKeyId; - } -}; - -Algorithm algorithm = Algorithm.RSA256(keyProvider); -//Use the Algorithm to create and verify JWTs. -``` - - -### Time Validation - -The JWT token may include DateNumber fields that can be used to validate that: -* The token was issued in a past date `"iat" < TODAY` -* The token hasn't expired yet `"exp" > TODAY` and -* The token can already be used. `"nbf" < TODAY` - -When verifying a token the time validation occurs automatically, resulting in a `JWTVerificationException` being throw when the values are invalid. If any of the previous fields are missing they won't be considered in this validation. - -To specify a **leeway window** in which the Token should still be considered valid, use the `acceptLeeway()` method in the `JWTVerifier` builder and pass a positive seconds value. This applies to every item listed above. - -```java -JWTVerifier verifier = JWT.require(algorithm) - .acceptLeeway(1) // 1 sec for nbf, iat and exp - .build(); -``` - -You can also specify a custom value for a given Date claim and override the default one for only that claim. - -```java -JWTVerifier verifier = JWT.require(algorithm) - .acceptLeeway(1) //1 sec for nbf and iat - .acceptExpiresAt(5) //5 secs for exp - .build(); -``` - -If you need to test this behavior in your lib/app cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a `java.time.Clock`. e.g.: - -```java -BaseVerification verification = (BaseVerification) JWT.require(algorithm) - .acceptLeeway(1) - .acceptExpiresAt(5); -private final Clock mockNow = Clock.fixed(Instant.ofEpochSecond(1477592), ZoneId.of("UTC")); -JWTVerifier verifier = verification.build(clock); -``` - -### Header Claims - -#### Algorithm ("alg") - -Returns the Algorithm value or null if it's not defined in the Header. - -```java -String algorithm = jwt.getAlgorithm(); -``` - -#### Type ("typ") - -Returns the Type value or null if it's not defined in the Header. - -```java -String type = jwt.getType(); -``` - -#### Content Type ("cty") - -Returns the Content Type value or null if it's not defined in the Header. - -```java -String contentType = jwt.getContentType(); -``` - -#### Key Id ("kid") - -Returns the Key Id value or null if it's not defined in the Header. - -```java -String keyId = jwt.getKeyId(); -``` - -#### Private Claims - -Additional Claims defined in the token's Header can be obtained by calling `getHeaderClaim()` and passing the Claim name. A Claim will always be returned, even if it can't be found. You can check if a Claim's value is null by calling `claim.isNull()`. - -```java -Claim claim = jwt.getHeaderClaim("owner"); -``` - -When creating a Token with the `JWT.create()` you can specify header Claims by calling `withHeader()` and passing both the map of claims. - -```java -Map headerClaims = new HashMap(); -headerClaims.put("owner", "auth0"); -String token = JWT.create() - .withHeader(headerClaims) - .sign(algorithm); -``` - -> The `alg` and `typ` values will always be included in the Header after the signing process. - - -### Payload Claims - -#### Issuer ("iss") - -Returns the Issuer value or null if it's not defined in the Payload. - -```java -String issuer = jwt.getIssuer(); -``` - -#### Subject ("sub") - -Returns the Subject value or null if it's not defined in the Payload. - -```java -String subject = jwt.getSubject(); -``` - -#### Audience ("aud") - -Returns the Audience value or null if it's not defined in the Payload. - -```java -List audience = jwt.getAudience(); -``` - -#### Expiration Time ("exp") - -Returns the Expiration Time value or null if it's not defined in the Payload. - -```java -Date expiresAt = jwt.getExpiresAt(); -``` - -If you prefer to work with `java.time.Instant` instead of `java.util.Date`: - -```java -Instant expiresAt = jwt.getExpiresAtAsInstant(); -``` - -#### Not Before ("nbf") - -Returns the Not Before value or null if it's not defined in the Payload. - -```java -Date notBefore = jwt.getNotBefore(); -``` - -If you prefer to work with `java.time.Instant` instead of `java.util.Date`: - -```java -Instant notBefore = jwt.getNotBeforeAsInstant(); -``` - -#### Issued At ("iat") - -Returns the Issued At value or null if it's not defined in the Payload. - -```java -Date issuedAt = jwt.getIssuedAt(); -``` - -If you prefer to work with `java.time.Instant` instead of `java.util.Date`: - -```java -Instant issuedAt = jwt.getIssuedAtAsInstant(); -``` - -#### JWT ID ("jti") +> :warning: **Important security note:** JVM has a critical vulnerability for ECDSA Algorithms - [CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449). Please review the details of the vulnerability and update your environment. +### Installation -Returns the JWT ID value or null if it's not defined in the Payload. +Add the dependency via Maven: -```java -String id = jwt.getId(); +```xml + + com.auth0 + java-jwt + 4.2.1 + ``` -#### Private Claims +or Gradle: -Additional Claims defined in the token's Payload can be obtained by calling `getClaims()` or `getClaim()` and passing the Claim name. A Claim will always be returned, even if it can't be found. You can check if a Claim's value is null by calling `claim.isNull()`. - -```java -Map claims = jwt.getClaims(); //Key is the Claim name -Claim claim = claims.get("isAdmin"); +```gradle +implementation 'com.auth0:jva-jwt:4.2.1' ``` -or +### Create a JWT -```java -Claim claim = jwt.getClaim("isAdmin"); -``` +Use `JWT.create()`, configure the claims, and then call `sign(algorithm)` to sign the JWT. -When creating a Token with the `JWT.create()` you can specify a custom Claim by calling `withClaim()` and passing both the name and the value. +The example below demonstrates this using the `RS256` signing algorithm: ```java -String token = JWT.create() - .withClaim("name", 123) - .withArrayClaim("array", new Integer[]{1, 2, 3}) - .withNullClaim("claim_name") +try { + Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); + String token = JWT.create() + .withIssuer("auth0") .sign(algorithm); +} catch (JWTCreationException exception){ + // Invalid Signing configuration / Couldn't convert Claims. +} ``` -You can also create a JWT by calling `withPayload()` and passing a map of claim names to values: +### Verify a JWT -```java -Map payloadClaims = new HashMap<>(); -payloadClaims.put("@context", "https://auth0.com/"); -String token = JWT.create() - .withPayload(payloadClaims) - .sign(algorithm); -``` +Create a `JWTVerifier` passing the `Algorithm`, and specify any required claim values. -You can also verify custom Claims on the `JWT.require()` by calling `withClaim()` and passing both the name and the required value. +The following example uses `RS256` to verify the JWT. ```java -JWTVerifier verifier = JWT.require(algorithm) - .withClaim("name", 123) - .withArrayClaim("array", 1, 2, 3) - .withNullClaim("null_value") //checks if the claim name provided has null value - .withClaimPresence("claim_presence") //checks if the claim name provided is in the payload - .withClaim("predicate", (claim, decodedJWT) -> "custom_check".equals(claim.asString())) //can be used to run custom verification - .build(); -DecodedJWT jwt = verifier.verify("my.jwt.token"); +String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; +DecodedJWT decodedJWT; +try { + Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); + JWTVerifier verifier = JWT.require(algorithm) + // specify an specific claim validations + .withIssuer("auth0") + // reusable verifier instance + .build(); + + decodedJWT jwt = verifier.verify(token); +} catch (JWTVerificationException exception){ + // Invalid signature/claims +} ``` -> Currently supported classes for custom JWT Claim creation and verification are: Boolean, Integer, Double, String, Date and Arrays of type String and Integer. - - -### Claim Class -The Claim class is a wrapper for the Claim values. It allows you to get the Claim as different class types. The available helpers are: - -#### Primitives -* **asBoolean()**: Returns the Boolean value or null if it can't be converted. -* **asInt()**: Returns the Integer value or null if it can't be converted. -* **asDouble()**: Returns the Double value or null if it can't be converted. -* **asLong()**: Returns the Long value or null if it can't be converted. -* **asString()**: Returns the String value or null if it can't be converted. -* **asInstant()**: Returns the Instant value or null if it can't be converted. -* **asDate()**: Returns the Date value or null if it can't be converted. - -> For `asInstant()` and `asDate()` the value must be a NumericDate (Unix Epoch/Timestamp). Note that the [JWT Standard](https://tools.ietf.org/html/rfc7519#section-2) specified that all the *NumericDate* values must be in seconds. - -#### Custom Classes and Collections -To obtain a Claim as a Collection you'll need to provide the **Class Type** of the contents to convert from. - -* **as(class)**: Returns the value parsed as **Class Type**. For collections you should use the `asArray` and `asList` methods. -* **asMap()**: Returns the value parsed as **Map**. -* **asArray(class)**: Returns the value parsed as an Array of elements of type **Class Type**, or null if the value isn't a JSON Array. -* **asList(class)**: Returns the value parsed as a List of elements of type **Class Type**, or null if the value isn't a JSON Array. - -If the values can't be converted to the given **Class Type** a `JWTDecodeException` will raise. - - +If the token has an invalid signature or the Claim requirement is not met, a `JWTVerificationException` will be thrown. -## What is Auth0? +See the [examples](./EXAMPLES.md) and [JavaDocs](https://javadoc.io/doc/com.auth0/java-jwt/latest) for additional documentation. -Auth0 helps you to: +## API Reference -* Add authentication with [multiple authentication sources](https://auth0.com/docs/identityproviders), either social like **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce, among others**, or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS or any SAML Identity Provider**. -* Add authentication through more traditional **[username/password databases](https://auth0.com/docs/connections/database)**. -* Add support for **[linking different user accounts](https://auth0.com/docs/users/user-account-linking)** with the same user. -* Support for generating signed [Json Web Tokens](https://auth0.com/docs/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. -* Analytics of how, when and where users are logging in. -* Pull data from other sources and add it to the user profile, through [JavaScript rules](https://auth0.com/docs/rules). +- [java-jwt JavaDocs](https://javadoc.io/doc/com.auth0/java-jwt/latest) -## Create a free account in Auth0 +## Feedback -1. Go to [Auth0](https://auth0.com) and click Sign Up. -2. Use Google, GitHub or Microsoft Account to login. +### Contributing -## Issue Reporting +We appreciate feedback and contribution to this repo! Before you get started, please see the following: -If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. +- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) +- [Auth0's code of conduct guidelines]((https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)) -## Author +### Raise an issue +To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/java-jwt/issues). -[Auth0](https://auth0.com/) +### Vulnerability Reporting +Please do not report security vulnerabilities on the public Github issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. -## License +--- -This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info. +

+ + + + Auth0 Logo + +

+

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

+

+This project is licensed under the MIT license. See the LICENSE file for more info.

From 56e663c3b5830e0329160f2165043aff89f8d3bb Mon Sep 17 00:00:00 2001 From: Jeff Allen <103958546+trestletech-dd@users.noreply.github.com> Date: Wed, 26 Oct 2022 16:03:25 -0500 Subject: [PATCH 091/134] Fix the spelling of the dependency name in README (#638) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7786cbaf..8e634ee6 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Add the dependency via Maven: or Gradle: ```gradle -implementation 'com.auth0:jva-jwt:4.2.1' +implementation 'com.auth0:java-jwt:4.2.1' ``` ### Create a JWT From 931cd1243c4653744c0f1cc59f182566139cd2c5 Mon Sep 17 00:00:00 2001 From: Wilson Chuks Date: Wed, 23 Nov 2022 07:17:22 +0900 Subject: [PATCH 092/134] Fixed a typographical error on the readme file (#641) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e634ee6..903e37ba 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ try { // reusable verifier instance .build(); - decodedJWT jwt = verifier.verify(token); + decodedJWT = verifier.verify(token); } catch (JWTVerificationException exception){ // Invalid signature/claims } From 14618b5af545e382ce734ef3cb54ba12398460dc Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 11 Jan 2023 14:32:18 +0530 Subject: [PATCH 093/134] Temporarily disable auto release --- .circleci/config.yml | 12 ------------ lib/build.gradle | 11 ----------- 2 files changed, 23 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6c87574b..1675c39f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,5 @@ version: 2.1 orbs: - ship: auth0/ship@0 codecov: codecov/codecov@3 commands: @@ -57,17 +56,6 @@ workflows: build-and-test: jobs: - build - - ship/java-publish: - prefix-tag: false - context: - - publish-gh - - publish-sonatype - filters: - branches: - only: - - master - requires: - - build api-diff: jobs: - api-diff diff --git a/lib/build.gradle b/lib/build.gradle index d6c9b061..6b2fdfe3 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,6 +1,3 @@ -buildscript { - version = "4.2.1" -} plugins { id 'java' @@ -9,13 +6,6 @@ plugins { id 'checkstyle' } -def signingKey = findProperty('signingKey') -def signingKeyPwd = findProperty('signingPassword') - -signing { - useInMemoryPgpKeys(signingKey, signingKeyPwd) -} - checkstyle { toolVersion '10.0' checkstyleTest.enabled = false //We are disabling lint checks for tests @@ -29,7 +19,6 @@ oss { organization "auth0" description "Java implementation of JSON Web Token (JWT)" baselineCompareVersion "4.1.0" - skipAssertSigningConfiguration true developers { auth0 { From b4fae643ad27ed5efb28a12da7ac7d52f9917706 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Wed, 11 Jan 2023 17:50:24 +0100 Subject: [PATCH 094/134] Release 4.2.2 (#650) --- CHANGELOG.md | 6 ++++++ README.md | 9 +++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed3706dc..eaf3feec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [4.2.2](https://github.com/auth0/java-jwt/tree/4.2.2) (2023-01-11) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.1...4.2.2) + +This patch release does not contain any functional changes, but is being released using an updated signing key for verification as part of our commitment to best security practices. +Please review [the README note for additional details.](https://github.com/auth0/java-jwt/blob/master/README.md) + ## [4.2.1](https://github.com/auth0/java-jwt/tree/4.2.1) (2022-10-24) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.0...4.2.1) diff --git a/README.md b/README.md index 903e37ba..8583ed7a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +> **Note** +> As part of our ongoing commitment to best security practices, we have rotated the signing keys used to sign previous releases of this SDK. As a result, new patch builds have been released using the new signing key. Please upgrade at your earliest convenience. +> +> While this change won't affect most developers, if you have implemented a dependency signature validation step in your build process, you may notice a warning that past releases can't be verified. This is expected, and a result of the key rotation process. Updating to the latest version will resolve this for you. + ![A Java implementation of JSON Web Token (JWT) - RFC 7519.](https://cdn.auth0.com/website/sdks/banners/java-jwt-banner.png) [![CircleCI](https://img.shields.io/circleci/project/github/auth0/java-jwt.svg?style=flat-square)](https://circleci.com/gh/auth0/java-jwt/tree/master) @@ -45,14 +50,14 @@ Add the dependency via Maven: com.auth0 java-jwt - 4.2.1 + 4.2.2 ``` or Gradle: ```gradle -implementation 'com.auth0:java-jwt:4.2.1' +implementation 'com.auth0:java-jwt:4.2.2' ``` ### Create a JWT From 6e80ea1e5a8624f34f133c3be71078ee9ab83906 Mon Sep 17 00:00:00 2001 From: CodeDead Date: Thu, 26 Jan 2023 22:44:56 +0100 Subject: [PATCH 095/134] Feature/cleanup (#642) * GIT compliance * Simpler HashMap declaration * Replaced usage of deprecated JsonMapper methods, removed unneeded null check * Removed unused import * Removed unused imports Co-authored-by: Jim Anderson --- EXAMPLES.md | 2 +- LICENSE | 2 +- lib/src/main/java/com/auth0/jwt/JWTCreator.java | 11 +++++++---- .../java/com/auth0/jwt/algorithms/RSAAlgorithm.java | 1 - lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java | 2 +- .../test/java/com/auth0/jwt/ConcurrentVerifyTest.java | 3 --- lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java | 2 -- .../com/auth0/jwt/algorithms/HMACAlgorithmTest.java | 1 - settings.gradle | 2 +- 9 files changed, 11 insertions(+), 15 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 8a849303..995e4c1d 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -127,4 +127,4 @@ RSAKeyProvider keyProvider = new RSAKeyProvider() { Algorithm algorithm = Algorithm.RSA256(keyProvider); //Use the Algorithm to create and verify JWTs. -``` \ No newline at end of file +``` diff --git a/LICENSE b/LICENSE index 4a7a13ad..bcd1854c 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index a99f0fa0..7ed83940 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import java.nio.charset.StandardCharsets; @@ -31,12 +32,14 @@ public final class JWTCreator { private static final SimpleModule module; static { - mapper = new ObjectMapper(); module = new SimpleModule(); module.addSerializer(PayloadClaimsHolder.class, new PayloadSerializer()); module.addSerializer(HeaderClaimsHolder.class, new HeaderSerializer()); - mapper.registerModule(module); - mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); + + mapper = JsonMapper.builder() + .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true) + .build() + .registerModule(module); } private JWTCreator(Algorithm algorithm, Map headerClaims, Map payloadClaims) @@ -489,7 +492,7 @@ private static boolean validateClaim(Map map) { return false; } - if (entry.getKey() == null || !(entry.getKey() instanceof String)) { + if (!(entry.getKey() instanceof String)) { return false; } } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java index 0c7a5b57..ca892e60 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java @@ -5,7 +5,6 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.RSAKeyProvider; -import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; diff --git a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java index 3746dcd2..8031d8c0 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java +++ b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java @@ -37,7 +37,7 @@ class BasicHeader implements Header, Serializable { this.type = type; this.contentType = contentType; this.keyId = keyId; - this.tree = Collections.unmodifiableMap(tree == null ? new HashMap() : tree); + this.tree = Collections.unmodifiableMap(tree == null ? new HashMap<>() : tree); this.objectReader = objectReader; } diff --git a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java index a06df7b7..32ede1de 100644 --- a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java +++ b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java @@ -10,14 +10,11 @@ import org.junit.rules.ExpectedException; import java.security.interfaces.ECKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAKey; import java.util.Collections; import java.util.List; import java.util.concurrent.*; -import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; //@Ignore("Skipping concurrency tests") diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 020e5e37..8fc83b44 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -16,9 +16,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java index 4a0269cc..9b6ac0c0 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java @@ -13,7 +13,6 @@ import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; diff --git a/settings.gradle b/settings.gradle index a4cda2d7..8d5f112c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,4 @@ pluginManagement { } include ':java-jwt' -project(':java-jwt').projectDir = new File(rootProject.projectDir, '/lib') \ No newline at end of file +project(':java-jwt').projectDir = new File(rootProject.projectDir, '/lib') From 12ae664a60d5e12d824c0896d5a82ef8522a8b69 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 26 Jan 2023 17:04:32 -0600 Subject: [PATCH 096/134] Fix for `exp` claim considered valid if equal to now (#652) exp claim cannot be equal to now --- .../main/java/com/auth0/jwt/JWTVerifier.java | 6 ++-- lib/src/test/java/com/auth0/jwt/JWTTest.java | 5 ++-- .../java/com/auth0/jwt/JWTVerifierTest.java | 30 +++++++++++++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 07c86a4c..6cec2026 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -346,7 +346,7 @@ private boolean assertValidInstantClaim(String claimName, Claim claim, long leew throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal), claimVal); } } else { - isValid = assertInstantIsPast(claimVal, leeway, now); + isValid = assertInstantIsLessThanOrEqualToNow(claimVal, leeway, now); if (!isValid) { throw new IncorrectClaimException( String.format("The Token can't be used before %s.", claimVal), claimName, claim); @@ -356,10 +356,10 @@ private boolean assertValidInstantClaim(String claimName, Claim claim, long leew } private boolean assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { - return !(claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)); + return claimVal == null || now.minus(Duration.ofSeconds(leeway)).isBefore(claimVal); } - private boolean assertInstantIsPast(Instant claimVal, long leeway, Instant now) { + private boolean assertInstantIsLessThanOrEqualToNow(Instant claimVal, long leeway, Instant now) { return !(claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)); } diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index b9f56a2e..087f1e9e 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -12,6 +12,7 @@ import java.security.interfaces.ECKey; import java.security.interfaces.RSAKey; import java.time.Clock; +import java.time.Duration; import java.time.Instant; import java.time.ZoneId; import java.util.Base64; @@ -270,12 +271,12 @@ public void shouldGetStringAudience() { @Test public void shouldGetExpirationTime() { long seconds = 1477592L; - Clock clock = Clock.fixed(Instant.ofEpochSecond(seconds), ZoneId.of("UTC")); + Clock mockNow = Clock.fixed(Instant.ofEpochSecond(seconds - 1), ZoneId.of("UTC")); String token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0Nzc1OTJ9.x_ZjkPkKYUV5tdvc0l8go6D_z2kez1MQcOxokXrDc3k"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification - .build(clock) + .build(mockNow) .verify(token); assertThat(jwt, is(notNullValue())); diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 6d8ba201..5a784b87 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -657,6 +657,7 @@ public void shouldThrowOnNegativeCustomLeeway() { } // Expires At + @Test public void shouldValidateExpiresAtWithLeeway() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; @@ -674,12 +675,26 @@ public void shouldValidateExpiresAtIfPresent() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification - .build(mockNow) + .build(mockOneSecondEarlier) .verify(token); assertThat(jwt, is(notNullValue())); } + @Test + public void shouldThrowWhenExpiresAtIsNow() { + // exp must be > now + TokenExpiredException e = assertThrows(null, TokenExpiredException.class, () -> { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(mockNow) + .verify(token); + }); + assertThat(e.getMessage(), is("The Token has expired on 1970-01-18T02:26:32Z.")); + assertThat(e.getExpiredOn(), is(Instant.ofEpochSecond(1477592L))); + } + @Test public void shouldThrowOnInvalidExpiresAtIfPresent() { TokenExpiredException e = assertThrows(null, TokenExpiredException.class, () -> { @@ -731,7 +746,18 @@ public void shouldThrowOnInvalidNotBeforeIfPresent() { @Test public void shouldValidateNotBeforeIfPresent() { - String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; + String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTN9.f4zVV0TbbTG5xxDjSoGZ320JIMchGoQCWrnT5MyQdT0"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(mockOneSecondLater) + .verify(token); + + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldAcceptNotBeforeEqualToNow() { + String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTJ9.71XBtRmkAa4iKnyhbS4NPW-Xr26eAVAdHZgmupS7a5o"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); DecodedJWT jwt = verification .build(mockNow) From 902431804ee68a0e4727f41397cd56608918ba37 Mon Sep 17 00:00:00 2001 From: noetro Date: Tue, 31 Jan 2023 03:09:45 +0100 Subject: [PATCH 097/134] Improve JWT parse / decode performance (#620) * Optimise parsing of token for well-defined JWT format * Update error message in test to match new code * Fixing checkstyle issues * Added missing test case for no parts * Return new JWTDecodeException Return a new JWTDecodeException from private utility method `wrongNumberOfParts`, instead of throwing, since we throw from `splitToken()`. * Add JMH support to build script * Add benchmark for decoder and cleanup build file * Optimise JWT deserialisation by re-using threadsafe Jackson objects * Disable lint checks on JMH source set that is for testing * Remove extra line break --------- Co-authored-by: Jim Anderson Co-authored-by: Jim Anderson --- lib/build.gradle | 46 ++++++++++++++++++- .../jwt/benchmark/JWTDecoderBenchmark.java | 20 ++++++++ .../java/com/auth0/jwt/impl/BasicHeader.java | 13 +++--- .../auth0/jwt/impl/HeaderDeserializer.java | 20 +++----- .../java/com/auth0/jwt/impl/JWTParser.java | 22 +++++++-- .../com/auth0/jwt/impl/JsonNodeClaim.java | 36 ++++++++------- .../auth0/jwt/impl/PayloadDeserializer.java | 22 ++++----- .../java/com/auth0/jwt/impl/PayloadImpl.java | 20 ++++---- .../jwt/impl/HeaderDeserializerTest.java | 10 ++-- .../com/auth0/jwt/impl/JWTParserTest.java | 2 +- .../com/auth0/jwt/impl/JsonNodeClaimTest.java | 25 ++++++---- .../jwt/impl/PayloadDeserializerTest.java | 19 ++++---- .../com/auth0/jwt/impl/PayloadImplTest.java | 29 ++++++------ 13 files changed, 181 insertions(+), 103 deletions(-) create mode 100644 lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java diff --git a/lib/build.gradle b/lib/build.gradle index 6b2fdfe3..6190a239 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -6,10 +6,28 @@ plugins { id 'checkstyle' } +sourceSets { + jmh { + + } +} + +configurations { + jmhImplementation { + extendsFrom implementation + } +} + checkstyle { toolVersion '10.0' - checkstyleTest.enabled = false //We are disabling lint checks for tests } +//We are disabling lint checks for tests +tasks.named("checkstyleTest").configure({ + enabled = false +}) +tasks.named("checkstyleJmh").configure({ + enabled = false +}) logger.lifecycle("Using version ${version} for ${group}.${name}") @@ -61,6 +79,10 @@ dependencies { testImplementation 'net.jodah:concurrentunit:0.4.6' testImplementation 'org.hamcrest:hamcrest:2.2' testImplementation 'org.mockito:mockito-core:4.4.0' + + jmhImplementation sourceSets.main.output + jmhImplementation 'org.openjdk.jmh:jmh-core:1.35' + jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.35' } jacoco { @@ -143,3 +165,25 @@ task exportVersion() { new File(rootDir, "version.txt").text = "$version" } } + +// you can pass any arguments JMH accepts via Gradle args. +// Example: ./gradlew runJMH --args="-lrf" +tasks.register('runJMH', JavaExec) { + description 'Run JMH benchmarks.' + group 'verification' + + main 'org.openjdk.jmh.Main' + classpath sourceSets.jmh.runtimeClasspath + + args project.hasProperty("args") ? project.property("args").split() : "" +} +tasks.register('jmhHelp', JavaExec) { + description 'Prints the available command line options for JMH.' + group 'help' + + main 'org.openjdk.jmh.Main' + classpath sourceSets.jmh.runtimeClasspath + + args '-h' +} + diff --git a/lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java b/lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java new file mode 100644 index 00000000..81d3737a --- /dev/null +++ b/lib/src/jmh/java/com/auth0/jwt/benchmark/JWTDecoderBenchmark.java @@ -0,0 +1,20 @@ +package com.auth0.jwt.benchmark; + +import com.auth0.jwt.JWT; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.infra.Blackhole; + +/** + * This class is a JMH benchmark for decoding JWTs. + */ +public class JWTDecoderBenchmark { + private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void throughputDecodeTime(Blackhole blackhole) { + blackhole.consume(JWT.decode(TOKEN)); + } +} diff --git a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java index 8031d8c0..5a881ab5 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java +++ b/lib/src/main/java/com/auth0/jwt/impl/BasicHeader.java @@ -2,12 +2,11 @@ import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.Header; +import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectReader; import java.io.Serializable; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import static com.auth0.jwt.impl.JsonNodeClaim.extractClaim; @@ -23,7 +22,7 @@ class BasicHeader implements Header, Serializable { private final String contentType; private final String keyId; private final Map tree; - private final ObjectReader objectReader; + private final ObjectCodec objectCodec; BasicHeader( String algorithm, @@ -31,14 +30,14 @@ class BasicHeader implements Header, Serializable { String contentType, String keyId, Map tree, - ObjectReader objectReader + ObjectCodec objectCodec ) { this.algorithm = algorithm; this.type = type; this.contentType = contentType; this.keyId = keyId; - this.tree = Collections.unmodifiableMap(tree == null ? new HashMap<>() : tree); - this.objectReader = objectReader; + this.tree = tree == null ? Collections.emptyMap() : Collections.unmodifiableMap(tree); + this.objectCodec = objectCodec; } Map getTree() { @@ -67,6 +66,6 @@ public String getKeyId() { @Override public Claim getHeaderClaim(String name) { - return extractClaim(name, tree, objectReader); + return extractClaim(name, tree, objectCodec); } } diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java index 9293fd4d..ad6e4ce0 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java @@ -2,11 +2,11 @@ import com.auth0.jwt.HeaderParams; import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.Header; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; @@ -19,22 +19,14 @@ * * @see JWTParser */ -class HeaderDeserializer extends StdDeserializer { +class HeaderDeserializer extends StdDeserializer
{ - private final ObjectReader objectReader; - - HeaderDeserializer(ObjectReader objectReader) { - this(null, objectReader); - } - - private HeaderDeserializer(Class vc, ObjectReader objectReader) { - super(vc); - - this.objectReader = objectReader; + HeaderDeserializer() { + super(Header.class); } @Override - public BasicHeader deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + public Header deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { Map tree = p.getCodec().readValue(p, new TypeReference>() { }); if (tree == null) { @@ -45,7 +37,7 @@ public BasicHeader deserialize(JsonParser p, DeserializationContext ctxt) throws String type = getString(tree, HeaderParams.TYPE); String contentType = getString(tree, HeaderParams.CONTENT_TYPE); String keyId = getString(tree, HeaderParams.KEY_ID); - return new BasicHeader(algorithm, type, contentType, keyId, tree, objectReader); + return new BasicHeader(algorithm, type, contentType, keyId, tree, p.getCodec()); } String getString(Map tree, String claimName) { diff --git a/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java b/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java index fe1600bd..022520f5 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JWTParser.java @@ -16,15 +16,21 @@ * {@link HeaderSerializer} and {@link PayloadSerializer}. */ public class JWTParser implements JWTPartsParser { + private static final ObjectMapper DEFAULT_OBJECT_MAPPER = createDefaultObjectMapper(); + private static final ObjectReader DEFAULT_PAYLOAD_READER = DEFAULT_OBJECT_MAPPER.readerFor(Payload.class); + private static final ObjectReader DEFAULT_HEADER_READER = DEFAULT_OBJECT_MAPPER.readerFor(Header.class); + private final ObjectReader payloadReader; private final ObjectReader headerReader; public JWTParser() { - this(getDefaultObjectMapper()); + this.payloadReader = DEFAULT_PAYLOAD_READER; + this.headerReader = DEFAULT_HEADER_READER; } JWTParser(ObjectMapper mapper) { addDeserializers(mapper); + this.payloadReader = mapper.readerFor(Payload.class); this.headerReader = mapper.readerFor(Header.class); } @@ -55,18 +61,24 @@ public Header parseHeader(String json) throws JWTDecodeException { } } - private void addDeserializers(ObjectMapper mapper) { + static void addDeserializers(ObjectMapper mapper) { SimpleModule module = new SimpleModule(); - ObjectReader reader = mapper.reader(); - module.addDeserializer(Payload.class, new PayloadDeserializer(reader)); - module.addDeserializer(Header.class, new HeaderDeserializer(reader)); + module.addDeserializer(Payload.class, new PayloadDeserializer()); + module.addDeserializer(Header.class, new HeaderDeserializer()); mapper.registerModule(module); } static ObjectMapper getDefaultObjectMapper() { + return DEFAULT_OBJECT_MAPPER; + } + + private static ObjectMapper createDefaultObjectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + + addDeserializers(mapper); + return mapper; } diff --git a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java index 456d1515..0a7e22f3 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java @@ -4,9 +4,9 @@ import com.auth0.jwt.interfaces.Claim; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectReader; import java.io.IOException; import java.lang.reflect.Array; @@ -21,12 +21,12 @@ */ class JsonNodeClaim implements Claim { - private final ObjectReader objectReader; + private final ObjectCodec codec; private final JsonNode data; - private JsonNodeClaim(JsonNode node, ObjectReader objectReader) { + private JsonNodeClaim(JsonNode node, ObjectCodec codec) { this.data = node; - this.objectReader = objectReader; + this.codec = codec; } @Override @@ -82,7 +82,7 @@ public T[] asArray(Class clazz) throws JWTDecodeException { T[] arr = (T[]) Array.newInstance(clazz, data.size()); for (int i = 0; i < data.size(); i++) { try { - arr[i] = objectReader.treeToValue(data.get(i), clazz); + arr[i] = codec.treeToValue(data.get(i), clazz); } catch (JsonProcessingException e) { throw new JWTDecodeException("Couldn't map the Claim's array contents to " + clazz.getSimpleName(), e); } @@ -99,7 +99,7 @@ public List asList(Class clazz) throws JWTDecodeException { List list = new ArrayList<>(); for (int i = 0; i < data.size(); i++) { try { - list.add(objectReader.treeToValue(data.get(i), clazz)); + list.add(codec.treeToValue(data.get(i), clazz)); } catch (JsonProcessingException e) { throw new JWTDecodeException("Couldn't map the Claim's array contents to " + clazz.getSimpleName(), e); } @@ -113,11 +113,11 @@ public Map asMap() throws JWTDecodeException { return null; } - try { - TypeReference> mapType = new TypeReference>() { - }; - JsonParser thisParser = objectReader.treeAsTokens(data); - return thisParser.readValueAs(mapType); + TypeReference> mapType = new TypeReference>() { + }; + + try (JsonParser parser = codec.treeAsTokens(data)) { + return parser.readValueAs(mapType); } catch (IOException e) { throw new JWTDecodeException("Couldn't map the Claim value to Map", e); } @@ -129,8 +129,8 @@ public T as(Class clazz) throws JWTDecodeException { if (isMissing() || isNull()) { return null; } - return objectReader.treeAsTokens(data).readValueAs(clazz); - } catch (IOException e) { + return codec.treeToValue(data, clazz); + } catch (JsonProcessingException e) { throw new JWTDecodeException("Couldn't map the Claim value to " + clazz.getSimpleName(), e); } } @@ -160,21 +160,23 @@ public String toString() { * * @param claimName the Claim to search for. * @param tree the JsonNode tree to search the Claim in. + * @param objectCodec the object codec in use for deserialization * @return a valid non-null Claim. */ - static Claim extractClaim(String claimName, Map tree, ObjectReader objectReader) { + static Claim extractClaim(String claimName, Map tree, ObjectCodec objectCodec) { JsonNode node = tree.get(claimName); - return claimFromNode(node, objectReader); + return claimFromNode(node, objectCodec); } /** * Helper method to create a Claim representation from the given JsonNode. * * @param node the JsonNode to convert into a Claim. + * @param objectCodec the object codec in use for deserialization * @return a valid Claim instance. If the node is null or missing, a NullClaim will be returned. */ - static Claim claimFromNode(JsonNode node, ObjectReader objectReader) { - return new JsonNodeClaim(node, objectReader); + static Claim claimFromNode(JsonNode node, ObjectCodec objectCodec) { + return new JsonNodeClaim(node, objectCodec); } } \ No newline at end of file diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 37e70f7a..65fba3ac 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -5,6 +5,7 @@ import com.auth0.jwt.interfaces.Payload; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; @@ -24,16 +25,8 @@ */ class PayloadDeserializer extends StdDeserializer { - private final ObjectReader objectReader; - - PayloadDeserializer(ObjectReader reader) { - this(null, reader); - } - - private PayloadDeserializer(Class vc, ObjectReader reader) { - super(vc); - - this.objectReader = reader; + PayloadDeserializer() { + super(Payload.class); } @Override @@ -46,16 +39,17 @@ public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOE String issuer = getString(tree, RegisteredClaims.ISSUER); String subject = getString(tree, RegisteredClaims.SUBJECT); - List audience = getStringOrArray(tree, RegisteredClaims.AUDIENCE); + List audience = getStringOrArray(p.getCodec(), tree, RegisteredClaims.AUDIENCE); Instant expiresAt = getInstantFromSeconds(tree, RegisteredClaims.EXPIRES_AT); Instant notBefore = getInstantFromSeconds(tree, RegisteredClaims.NOT_BEFORE); Instant issuedAt = getInstantFromSeconds(tree, RegisteredClaims.ISSUED_AT); String jwtId = getString(tree, RegisteredClaims.JWT_ID); - return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, objectReader); + return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, p.getCodec()); } - List getStringOrArray(Map tree, String claimName) throws JWTDecodeException { + List getStringOrArray(ObjectCodec codec, Map tree, String claimName) + throws JWTDecodeException { JsonNode node = tree.get(claimName); if (node == null || node.isNull() || !(node.isArray() || node.isTextual())) { return null; @@ -67,7 +61,7 @@ List getStringOrArray(Map tree, String claimName) thro List list = new ArrayList<>(node.size()); for (int i = 0; i < node.size(); i++) { try { - list.add(objectReader.treeToValue(node.get(i), String.class)); + list.add(codec.treeToValue(node.get(i), String.class)); } catch (JsonProcessingException e) { throw new JWTDecodeException("Couldn't map the Claim's array contents to String", e); } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java index 75e79474..bfd9b0ea 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java @@ -2,12 +2,16 @@ import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.Payload; +import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectReader; import java.io.Serializable; import java.time.Instant; -import java.util.*; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static com.auth0.jwt.impl.JsonNodeClaim.extractClaim; @@ -30,7 +34,7 @@ class PayloadImpl implements Payload, Serializable { private final Instant issuedAt; private final String jwtId; private final Map tree; - private final ObjectReader objectReader; + private final ObjectCodec objectCodec; PayloadImpl( String issuer, @@ -41,7 +45,7 @@ class PayloadImpl implements Payload, Serializable { Instant issuedAt, String jwtId, Map tree, - ObjectReader objectReader + ObjectCodec objectCodec ) { this.issuer = issuer; this.subject = subject; @@ -50,8 +54,8 @@ class PayloadImpl implements Payload, Serializable { this.notBefore = notBefore; this.issuedAt = issuedAt; this.jwtId = jwtId; - this.tree = tree != null ? Collections.unmodifiableMap(tree) : Collections.emptyMap(); - this.objectReader = objectReader; + this.tree = tree != null ? Collections.unmodifiableMap(tree) : Collections.emptyMap(); + this.objectCodec = objectCodec; } Map getTree() { @@ -111,14 +115,14 @@ public String getId() { @Override public Claim getClaim(String name) { - return extractClaim(name, tree, objectReader); + return extractClaim(name, tree, objectCodec); } @Override public Map getClaims() { Map claims = new HashMap<>(tree.size() * 2); for (String name : tree.keySet()) { - claims.put(name, extractClaim(name, tree, objectReader)); + claims.put(name, extractClaim(name, tree, objectCodec)); } return Collections.unmodifiableMap(claims); } diff --git a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java index 328f4ab4..02d782a7 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java @@ -10,7 +10,6 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.node.NullNode; import com.fasterxml.jackson.databind.node.TextNode; import org.junit.Before; @@ -22,8 +21,10 @@ import java.util.HashMap; import java.util.Map; -import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -34,11 +35,10 @@ public class HeaderDeserializerTest { @Rule public ExpectedException exception = ExpectedException.none(); private HeaderDeserializer deserializer; - private ObjectReader objectReader = new ObjectMapper().reader(); @Before public void setUp() { - deserializer = new HeaderDeserializer(objectReader); + deserializer = new HeaderDeserializer(); } @Test @@ -46,7 +46,7 @@ public void shouldThrowOnNullTree() throws Exception { exception.expect(JWTDecodeException.class); exception.expectMessage("Parsing the Header's JSON resulted on a Null map"); - JsonDeserializer deserializer = new HeaderDeserializer(objectReader); + JsonDeserializer deserializer = new HeaderDeserializer(); JsonParser parser = mock(JsonParser.class); ObjectCodec codec = mock(ObjectCodec.class); DeserializationContext context = mock(DeserializationContext.class); diff --git a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java index a40a23d4..da62131a 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java @@ -42,7 +42,7 @@ public void shouldGetDefaultObjectMapper() { @Test public void shouldAddDeserializers() { ObjectMapper mapper = mock(ObjectMapper.class); - new JWTParser(mapper); + JWTParser.addDeserializers(mapper); verify(mapper).registerModule(any(Module.class)); } diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java index 18f59f04..a0364953 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.node.JsonNodeType; import com.fasterxml.jackson.databind.node.MissingNode; import com.fasterxml.jackson.databind.node.NullNode; @@ -21,20 +20,31 @@ import java.io.IOException; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; public class JsonNodeClaimTest { private ObjectMapper mapper; - private ObjectReader objectReader; @Rule public ExpectedException exception = ExpectedException.none(); @@ -42,7 +52,6 @@ public class JsonNodeClaimTest { @Before public void setUp() { mapper = getDefaultObjectMapper(); - objectReader = mapper.reader(); } @Test @@ -55,7 +64,7 @@ public void shouldGetBooleanValue() { } private Claim claimFromNode(JsonNode value) { - return JsonNodeClaim.claimFromNode(value, objectReader); + return JsonNodeClaim.claimFromNode(value, mapper); } @Test @@ -282,7 +291,7 @@ public void shouldThrowIfAnExtraordinaryExceptionHappensWhenParsingAsGenericMap( JsonNode value = mock(ObjectNode.class); when(value.getNodeType()).thenReturn(JsonNodeType.OBJECT); - ObjectReader mockedMapper = mock(ObjectReader.class); + ObjectMapper mockedMapper = mock(ObjectMapper.class); JsonNodeClaim claim = (JsonNodeClaim) JsonNodeClaim.claimFromNode(value, mockedMapper); JsonNodeClaim spiedClaim = spy(claim); diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 2d80bed9..86c4f10f 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -35,9 +35,12 @@ public class PayloadDeserializerTest { public ExpectedException exception = ExpectedException.none(); private PayloadDeserializer deserializer; + private ObjectMapper objectMapper; + @Before public void setUp() { - deserializer = new PayloadDeserializer(new ObjectMapper().reader()); + objectMapper = new ObjectMapper(); + deserializer = new PayloadDeserializer(); } @Test @@ -68,7 +71,7 @@ public void shouldThrowWhenParsingArrayWithObjectValue() throws Exception { ArrayNode arrNode = new ArrayNode(JsonNodeFactory.instance, subNodes); tree.put("key", arrNode); - deserializer.getStringOrArray(tree, "key"); + deserializer.getStringOrArray(objectMapper, tree, "key"); } @Test @@ -123,7 +126,7 @@ public void shouldGetStringArrayWhenParsingArrayNode() { ArrayNode arrNode = new ArrayNode(JsonNodeFactory.instance, subNodes); tree.put("key", arrNode); - List values = deserializer.getStringOrArray(tree, "key"); + List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(notNullValue())); assertThat(values, is(IsCollectionWithSize.hasSize(2))); assertThat(values, is(IsIterableContaining.hasItems("one", "two"))); @@ -135,7 +138,7 @@ public void shouldGetStringArrayWhenParsingTextNode() { TextNode textNode = new TextNode("something"); tree.put("key", textNode); - List values = deserializer.getStringOrArray(tree, "key"); + List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(notNullValue())); assertThat(values, is(IsCollectionWithSize.hasSize(1))); assertThat(values, is(IsIterableContaining.hasItems("something"))); @@ -147,7 +150,7 @@ public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() { TextNode textNode = new TextNode(""); tree.put("key", textNode); - List values = deserializer.getStringOrArray(tree, "key"); + List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(notNullValue())); assertThat(values, is(IsEmptyCollection.empty())); } @@ -158,7 +161,7 @@ public void shouldGetNullArrayWhenParsingNullNode() { NullNode node = NullNode.getInstance(); tree.put("key", node); - List values = deserializer.getStringOrArray(tree, "key"); + List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(nullValue())); } @@ -167,7 +170,7 @@ public void shouldGetNullArrayWhenParsingNullNodeValue() { Map tree = new HashMap<>(); tree.put("key", null); - List values = deserializer.getStringOrArray(tree, "key"); + List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(nullValue())); } @@ -177,7 +180,7 @@ public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() { IntNode node = new IntNode(456789); tree.put("key", node); - List values = deserializer.getStringOrArray(tree, "key"); + List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(nullValue())); } diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java index da0c880e..5ad7ac68 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java @@ -29,29 +29,28 @@ public class PayloadImplTest { private final Instant notBefore = Instant.now(); private final Instant issuedAt = Instant.now(); - private ObjectReader objectReader; + private ObjectMapper objectMapper; @Before public void setUp() { - ObjectMapper mapper = getDefaultObjectMapper(); - objectReader = mapper.reader(); + objectMapper = getDefaultObjectMapper(); Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); - payload = new PayloadImpl("issuer", "subject", Collections.singletonList("audience"), expiresAt, notBefore, issuedAt, "jwtId", tree, objectReader); + payload = new PayloadImpl("issuer", "subject", Collections.singletonList("audience"), expiresAt, notBefore, issuedAt, "jwtId", tree, objectMapper); } @Test public void shouldHaveUnmodifiableTree() { exception.expect(UnsupportedOperationException.class); - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap<>(), objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap<>(), objectMapper); payload.getTree().put("something", null); } @Test public void shouldHaveUnmodifiableAudience() { exception.expect(UnsupportedOperationException.class); - PayloadImpl payload = new PayloadImpl(null, null, new ArrayList<>(), null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, new ArrayList<>(), null, null, null, null, null, objectMapper); payload.getAudience().add("something"); } @@ -63,7 +62,7 @@ public void shouldGetIssuer() { @Test public void shouldGetNullIssuerIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuer(), is(nullValue())); } @@ -76,7 +75,7 @@ public void shouldGetSubject() { @Test public void shouldGetNullSubjectIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getSubject(), is(nullValue())); } @@ -91,7 +90,7 @@ public void shouldGetAudience() { @Test public void shouldGetNullAudienceIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getAudience(), is(nullValue())); } @@ -105,7 +104,7 @@ public void shouldGetExpiresAt() { @Test public void shouldGetNullExpiresAtIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getExpiresAt(), is(nullValue())); assertThat(payload.getExpiresAtAsInstant(), is(nullValue())); @@ -120,7 +119,7 @@ public void shouldGetNotBefore() { @Test public void shouldGetNullNotBeforeIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getNotBefore(), is(nullValue())); assertThat(payload.getNotBeforeAsInstant(), is(nullValue())); @@ -135,7 +134,7 @@ public void shouldGetIssuedAt() { @Test public void shouldGetNullIssuedAtIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuedAt(), is(nullValue())); assertThat(payload.getIssuedAtAsInstant(), is(nullValue())); @@ -149,7 +148,7 @@ public void shouldGetJWTId() { @Test public void shouldGetNullJWTIdIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getId(), is(nullValue())); } @@ -163,7 +162,7 @@ public void shouldGetExtraClaim() { @Test public void shouldGetNotNullExtraClaimIfMissing() { - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectMapper); assertThat(payload, is(notNullValue())); assertThat(payload.getClaim("missing"), is(notNullValue())); assertThat(payload.getClaim("missing").isMissing(), is(true)); @@ -175,7 +174,7 @@ public void shouldGetClaims() { Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); tree.put("sub", new TextNode("auth0")); - PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, tree, objectReader); + PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, tree, objectMapper); assertThat(payload, is(notNullValue())); Map claims = payload.getClaims(); assertThat(claims, is(notNullValue())); From b610b6635ba1ed948a06fea777eeeecca2364303 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Sun, 12 Feb 2023 21:53:23 -0600 Subject: [PATCH 098/134] Release 4.3.0 (#655) --- CHANGELOG.md | 10 ++++++++++ README.md | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaf3feec..61ebad87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [4.3.0](https://github.com/auth0/java-jwt/tree/4.3.0) (2023-02-10) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.2...4.3.0) + +**Changed** +- Improve JWT parse/decode performance [\#620](https://github.com/auth0/java-jwt/pull/620) ([noetro](https://github.com/noetro)) + +**Fixed** +- Fix for exp claim considered valid if equal to now [\#652](https://github.com/auth0/java-jwt/pull/652) ([jimmyjames](https://github.com/jimmyjames)) +- Code cleanup [\#642](https://github.com/auth0/java-jwt/pull/642) ([CodeDead](https://github.com/CodeDead)) + ## [4.2.2](https://github.com/auth0/java-jwt/tree/4.2.2) (2023-01-11) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.1...4.2.2) diff --git a/README.md b/README.md index 8583ed7a..9391f87d 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,14 @@ Add the dependency via Maven: com.auth0 java-jwt - 4.2.2 + 4.3.0 ``` or Gradle: ```gradle -implementation 'com.auth0:java-jwt:4.2.2' +implementation 'com.auth0:java-jwt:4.3.0' ``` ### Create a JWT From a18955bb99bf6994e424971db3f621bc0cc64a86 Mon Sep 17 00:00:00 2001 From: Andreas Rigas <48296471+andrewrigas@users.noreply.github.com> Date: Mon, 27 Mar 2023 15:27:30 +0100 Subject: [PATCH 099/134] Add support for passing json values for header and payload (#643) --- lib/build.gradle | 2 +- .../main/java/com/auth0/jwt/JWTCreator.java | 48 ++++++++++++ .../java/com/auth0/jwt/JWTCreatorTest.java | 78 ++++++++++++++++++- 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/lib/build.gradle b/lib/build.gradle index 6190a239..d147f2d0 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -72,7 +72,7 @@ javadoc { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index 7ed83940..f554cbc3 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -98,6 +98,27 @@ public Builder withHeader(Map headerClaims) { return this; } + /** + * Add specific Claims to set as the Header. + * If provided json is null then nothing is changed + * + * @param headerClaimsJson the values to use as Claims in the token's Header. + * @return this same Builder instance. + * @throws IllegalArgumentException if json value has invalid structure + */ + public Builder withHeader(String headerClaimsJson) throws IllegalArgumentException { + if (headerClaimsJson == null) { + return this; + } + + try { + Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); + return withHeader(headerClaims); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Invalid header JSON", e); + } + } + /** * Add a specific Key Id ("kid") claim to the Header. * If the {@link Algorithm} used to sign this token was instantiated with a KeyProvider, @@ -467,6 +488,33 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE return this; } + /** + * Add specific Claims to set as the Payload. If the provided json is null then + * nothing is changed. + * + *

+ * If any of the claims are invalid, none will be added. + *

+ * + * @param payloadClaimsJson the values to use as Claims in the token's payload. + * @return this same Builder instance. + * @throws IllegalArgumentException if any of the claim keys or null, + * or if the values are not of a supported type, + * or if json value has invalid structure. + */ + public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException { + if (payloadClaimsJson == null) { + return this; + } + + try { + Map payloadClaims = mapper.readValue(payloadClaimsJson, HashMap.class); + return withPayload(payloadClaims); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Invalid payload JSON", e); + } + } + private boolean validatePayload(Map payload) { for (Map.Entry entry : payload.entrySet()) { String key = entry.getKey(); diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 8fc83b44..e4ab8cb0 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -3,6 +3,7 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.ECDSAKeyProvider; import com.auth0.jwt.interfaces.RSAKeyProvider; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Rule; import org.junit.Test; @@ -82,13 +83,48 @@ public void shouldAddHeaderClaim() { @Test public void shouldReturnBuilderIfNullMapIsProvided() { + Map nullMap = null; + String nullString = null; String signed = JWTCreator.init() - .withHeader(null) + .withHeader(nullMap) + .withHeader(nullString) .sign(Algorithm.HMAC256("secret")); assertThat(signed, is(notNullValue())); } + @Test + public void shouldSupportJsonValueHeaderWithNestedDataStructure() { + String stringClaim = "someClaim"; + Integer intClaim = 1; + List nestedListClaims = Arrays.asList("1", "2"); + String claimsJson = "{\"stringClaim\": \"someClaim\", \"intClaim\": 1, \"nestedClaim\": { \"listClaim\": [ \"1\", \"2\" ]}}"; + + String jwt = JWTCreator.init() + .withHeader(claimsJson) + .sign(Algorithm.HMAC256("secret")); + + assertThat(jwt, is(notNullValue())); + String[] parts = jwt.split("\\."); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); + + assertThat(headerJson, JsonMatcher.hasEntry("stringClaim", stringClaim)); + assertThat(headerJson, JsonMatcher.hasEntry("intClaim", intClaim)); + assertThat(headerJson, JsonMatcher.hasEntry("listClaim", nestedListClaims)); + } + + @Test + public void shouldFailWithIllegalArgumentExceptionForInvalidJsonForHeaderClaims() { + String invalidJson = "{ invalidJson }"; + + exception.expect(IllegalArgumentException.class); + exception.expectMessage("Invalid header JSON"); + + JWTCreator.init() + .withHeader(invalidJson) + .sign(Algorithm.HMAC256("secret")); + } + @Test public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { Map header = new HashMap<>(); @@ -105,6 +141,7 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { assertThat(headerJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "xyz")); } + @Test public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { Map header = new HashMap<>(); @@ -715,8 +752,11 @@ public void withPayloadShouldAddBasicClaim() { @Test public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() { + Map nullMap = null; + String nullString = null; String jwt = JWTCreator.init() - .withPayload(null) + .withPayload(nullMap) + .withPayload(nullString) .sign(Algorithm.HMAC256("secret")); assertThat(jwt, is(notNullValue())); @@ -921,10 +961,42 @@ public void withPayloadShouldSupportNullValuesEverywhere() { assertThat(headerJson, JsonMatcher.hasEntry("objClaim", objClaim)); } + @Test + public void withPayloadShouldSupportJsonValueWithNestedDataStructure() { + String stringClaim = "someClaim"; + Integer intClaim = 1; + List nestedListClaims = Arrays.asList("1", "2"); + String claimsJson = "{\"stringClaim\": \"someClaim\", \"intClaim\": 1, \"nestedClaim\": { \"listClaim\": [ \"1\", \"2\" ]}}"; + + String jwt = JWTCreator.init() + .withPayload(claimsJson) + .sign(Algorithm.HMAC256("secret")); + + assertThat(jwt, is(notNullValue())); + String[] parts = jwt.split("\\."); + String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); + + assertThat(payloadJson, JsonMatcher.hasEntry("stringClaim", stringClaim)); + assertThat(payloadJson, JsonMatcher.hasEntry("intClaim", intClaim)); + assertThat(payloadJson, JsonMatcher.hasEntry("listClaim", nestedListClaims)); + } + + @Test + public void shouldFailWithIllegalArgumentExceptionForInvalidJsonForPayloadClaims() { + String invalidJson = "{ invalidJson }"; + + exception.expect(IllegalArgumentException.class); + exception.expectMessage("Invalid payload JSON"); + + JWTCreator.init() + .withPayload(invalidJson) + .sign(Algorithm.HMAC256("secret")); + } + @Test public void shouldCreatePayloadWithNullForMap() { String jwt = JWTCreator.init() - .withClaim("name", (Map) null) + .withClaim("name", (Map) null) .sign(Algorithm.HMAC256("secret")); assertThat(jwt, is(notNullValue())); assertTrue(JWT.decode(jwt).getClaim("name").isNull()); From e85a00a00543b2b17d0460e9c1c11c2aa31fbcbc Mon Sep 17 00:00:00 2001 From: Robin Karlsson Date: Mon, 27 Mar 2023 21:57:04 +0200 Subject: [PATCH 100/134] Preserve insertion order for claims (#656) Co-authored-by: Jim Anderson --- .../main/java/com/auth0/jwt/JWTCreator.java | 8 +-- .../java/com/auth0/jwt/JWTCreatorTest.java | 49 ++++++++++++++++++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index f554cbc3..0b0d21e4 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -71,8 +71,8 @@ public static class Builder { private final Map headerClaims; Builder() { - this.payloadClaims = new HashMap<>(); - this.headerClaims = new HashMap<>(); + this.payloadClaims = new LinkedHashMap<>(); + this.headerClaims = new LinkedHashMap<>(); } /** @@ -112,7 +112,7 @@ public Builder withHeader(String headerClaimsJson) throws IllegalArgumentExcepti } try { - Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); + Map headerClaims = mapper.readValue(headerClaimsJson, LinkedHashMap.class); return withHeader(headerClaims); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Invalid header JSON", e); @@ -508,7 +508,7 @@ public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentExcep } try { - Map payloadClaims = mapper.readValue(payloadClaimsJson, HashMap.class); + Map payloadClaims = mapper.readValue(payloadClaimsJson, LinkedHashMap.class); return withPayload(payloadClaims); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Invalid payload JSON", e); diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index e4ab8cb0..53cd267b 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -3,8 +3,8 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.ECDSAKeyProvider; import com.auth0.jwt.interfaces.RSAKeyProvider; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -1010,4 +1010,51 @@ public void shouldCreatePayloadWithNullForList() { assertThat(jwt, is(notNullValue())); assertTrue(JWT.decode(jwt).getClaim("name").isNull()); } + + @Test + public void shouldPreserveInsertionOrder() throws Exception { + String taxonomyJson = "{\"class\": \"mammalia\", \"order\": \"carnivora\", \"family\": \"canidae\", \"genus\": \"vulpes\"}"; + List taxonomyClaims = Arrays.asList("class", "order", "family", "genus"); + List headerInsertionOrder = new ArrayList<>(taxonomyClaims); + Map header = new LinkedHashMap<>(); + for (int i = 0; i < 10; i++) { + String key = "h" + i; + header.put(key, "v" + 1); + headerInsertionOrder.add(key); + } + + List payloadInsertionOrder = new ArrayList<>(taxonomyClaims); + JWTCreator.Builder builder = JWTCreator.init() + .withHeader(taxonomyJson) + .withHeader(header) + .withPayload(taxonomyJson); + for (int i = 0; i < 10; i++) { + String name = "c" + i; + builder = builder.withClaim(name, "v" + i); + payloadInsertionOrder.add(name); + } + String signed = builder.sign(Algorithm.HMAC256("secret")); + + assertThat(signed, is(notNullValue())); + String[] parts = signed.split("\\."); + Base64.Decoder urlDecoder = Base64.getUrlDecoder(); + String headerJson = new String(urlDecoder.decode(parts[0]), StandardCharsets.UTF_8); + String payloadJson = new String(urlDecoder.decode(parts[1]), StandardCharsets.UTF_8); + + ObjectMapper objectMapper = new ObjectMapper(); + + List headerFields = new ArrayList<>(); + objectMapper.readValue(headerJson, ObjectNode.class) + .fieldNames().forEachRemaining(headerFields::add); + headerFields.retainAll(headerInsertionOrder); + assertThat("Header insertion order should be preserved", + headerFields, is(equalTo(headerInsertionOrder))); + + List payloadFields = new ArrayList<>(); + objectMapper.readValue(payloadJson, ObjectNode.class) + .fieldNames().forEachRemaining(payloadFields::add); + payloadFields.retainAll(payloadInsertionOrder); + assertThat("Claim insertion order should be preserved", + payloadFields, is(equalTo(payloadInsertionOrder))); + } } From 652bf7dac4c10d1213609a2db6fb50815920ac09 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 30 Mar 2023 22:12:01 -0500 Subject: [PATCH 101/134] update jackson to 2.14.2 (#657) --- lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/build.gradle b/lib/build.gradle index d147f2d0..c4e11764 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -72,7 +72,7 @@ javadoc { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' From 82548a6e7b69ad0c6974519c9ebb313d15237cad Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Fri, 31 Mar 2023 13:31:38 -0500 Subject: [PATCH 102/134] Release 4.4.0 (#658) --- CHANGELOG.md | 8 ++++++++ README.md | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61ebad87..1b1e75bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [4.4.0](https://github.com/auth0/java-jwt/tree/4.4.0) (2023-03-31) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.3.0...4.4.0) + +**Changed** +- Add support for passing json values for header and payload [\#643](https://github.com/auth0/java-jwt/pull/643) ([andrewrigas](https://github.com/andrewrigas)) +- Preserve insertion order for claims [\#656](https://github.com/auth0/java-jwt/pull/656) ([snago](https://github.com/snago)) +- Update Jackson to 2.14.2 [\#657](https://github.com/auth0/java-jwt/pull/657) ([jimmyjames](https://github.com/jimmyjames)) + ## [4.3.0](https://github.com/auth0/java-jwt/tree/4.3.0) (2023-02-10) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.2.2...4.3.0) diff --git a/README.md b/README.md index 9391f87d..9f425898 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,14 @@ Add the dependency via Maven: com.auth0 java-jwt - 4.3.0 + 4.4.0 ``` or Gradle: ```gradle -implementation 'com.auth0:java-jwt:4.3.0' +implementation 'com.auth0:java-jwt:4.4.0' ``` ### Create a JWT From 923e9c46db888c500ff44032fa900b871fae30ed Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Tue, 25 Apr 2023 23:02:41 -0300 Subject: [PATCH 103/134] Replace issue templates with issue forms [SDK-4167] (#661) --- .github/ISSUE_TEMPLATE/Bug Report.yml | 67 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/Feature Request.yml | 53 +++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 7 +-- .github/ISSUE_TEMPLATE/feature_request.md | 39 ------------- .github/ISSUE_TEMPLATE/report-a-bug.md | 55 ------------------ 5 files changed, 122 insertions(+), 99 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/Bug Report.yml create mode 100644 .github/ISSUE_TEMPLATE/Feature Request.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/report-a-bug.md diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml new file mode 100644 index 00000000..d5d861e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -0,0 +1,67 @@ +name: 🐞 Report a bug +description: Have you found a bug or issue? Create a bug report for this library +labels: ["bug"] + +body: + - type: markdown + attributes: + value: | + **Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. + + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I have looked into the [Readme](https://github.com/auth0/java-jwt#readme) and [Examples](https://github.com/auth0/java-jwt/blob/master/EXAMPLES.md), and have not found a suitable solution or answer. + required: true + - label: I have looked into the [API documentation](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html) and have not found a suitable solution or answer. + required: true + - label: I have searched the [issues](https://github.com/auth0/java-jwt/issues) and have not found a suitable solution or answer. + required: true + - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. + required: true + - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: description + attributes: + label: Description + description: Provide a clear and concise description of the issue, including what you expected to happen. + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Reproduction + description: Detail the steps taken to reproduce this error, and whether this issue can be reproduced consistently or if it is intermittent. + placeholder: | + 1. Step 1... + 2. Step 2... + 3. ... + validations: + required: true + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Other libraries that might be involved, or any other relevant information you think would be useful. + validations: + required: false + + - type: input + id: environment-version + attributes: + label: java-jwt version + validations: + required: true + + - type: input + id: environment-java-version + attributes: + label: Java version + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml new file mode 100644 index 00000000..38fee433 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature Request.yml @@ -0,0 +1,53 @@ +name: 🧩 Feature request +description: Suggest an idea or a feature for this library +labels: ["feature request"] + +body: + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I have looked into the [Readme](https://github.com/auth0/java-jwt#readme) and [Examples](https://github.com/auth0/java-jwt/blob/master/EXAMPLES.md), and have not found a suitable solution or answer. + required: true + - label: I have looked into the [API documentation](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html) and have not found a suitable solution or answer. + required: true + - label: I have searched the [issues](https://github.com/auth0/java-jwt/issues) and have not found a suitable solution or answer. + required: true + - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. + required: true + - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: description + attributes: + label: Describe the problem you'd like to have solved + description: A clear and concise description of what the problem is. + placeholder: I'm always frustrated when... + validations: + required: true + + - type: textarea + id: ideal-solution + attributes: + label: Describe the ideal solution + description: A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + id: alternatives-and-workarounds + attributes: + label: Alternatives and current workarounds + description: A clear and concise description of any alternatives you've considered or any workarounds that are currently in place. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3cd7aa53..f58e0249 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: false contact_links: - name: Auth0 Community - url: https://community.auth0.com/c/sdks/5 - about: Discuss this SDK in the Auth0 Community forums - - name: Library Documentation - url: https://github.com/auth0/java-jwt/blob/master/README.md - about: Read the library documentation + url: https://community.auth0.com + about: Discuss this library in the Auth0 Community forums diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 68352ba2..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Feature request -about: Suggest an idea or a feature for this project -title: '' -labels: feature request -assignees: '' ---- - - - -### Describe the problem you'd like to have solved - - - -### Describe the ideal solution - - - -## Alternatives and current work-arounds - - - -### Additional information, if any - - \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/report-a-bug.md b/.github/ISSUE_TEMPLATE/report-a-bug.md deleted file mode 100644 index e5cf8c46..00000000 --- a/.github/ISSUE_TEMPLATE/report-a-bug.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: Report a bug -about: Have you found a bug or issue? Create a bug report for this SDK -title: '' -labels: bug report -assignees: '' ---- - - - -### Describe the problem - - - -### What was the expected behavior? - - - -### Reproduction - - -- Step 1.. -- Step 2.. -- ... - -### Environment - - - -- **Version of this library used:** -- **Version of Java used:** -- **Other modules/plugins/libraries that might be involved:** -- **Any other relevant information you think would be useful:** From d8fe9a2654a69ff9c39c1fa711b8abb622a4f7d6 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 8 Jun 2023 21:15:57 -0500 Subject: [PATCH 104/134] Empty string audience claim should be deserialized as empty string (#663) --- lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java | 2 +- .../test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 65fba3ac..b1d32a12 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -54,7 +54,7 @@ List getStringOrArray(ObjectCodec codec, Map tree, Str if (node == null || node.isNull() || !(node.isArray() || node.isTextual())) { return null; } - if (node.isTextual() && !node.asText().isEmpty()) { + if (node.isTextual()) { return Collections.singletonList(node.asText()); } diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 86c4f10f..c3e04013 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -145,14 +145,14 @@ public void shouldGetStringArrayWhenParsingTextNode() { } @Test - public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() { + public void shouldGetEmptyStringInArrayWhenParsingEmptyTextNode() { Map tree = new HashMap<>(); TextNode textNode = new TextNode(""); tree.put("key", textNode); List values = deserializer.getStringOrArray(objectMapper, tree, "key"); assertThat(values, is(notNullValue())); - assertThat(values, is(IsEmptyCollection.empty())); + assertThat(values, is(IsIterableContaining.hasItem(""))); } @Test From 6ef84cf5a11dfdd45f6f00eb067f27123aa68bf7 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 17 Jul 2023 12:46:01 -0500 Subject: [PATCH 105/134] chore(security): Update and pin Graddle workflow actions --- .github/workflows/gradle-wrapper-validation.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index a015578a..20c61e51 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,5 +6,5 @@ jobs: name: "validation/gradlew" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: gradle/wrapper-validation-action@v1 + - uses: actions/checkout@v3 + - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b # pin@v1 From 8c9bbf8d838e6fed8ab589106a47eeb0b381ef28 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Mon, 17 Jul 2023 12:46:59 -0500 Subject: [PATCH 106/134] Update gradle-wrapper-validation.yml --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 20c61e51..ce302cb4 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -7,4 +7,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b # pin@v1 + - uses: gradle/wrapper-validation-action@8d49e559aae34d3e0eb16cde532684bc9702762b # pin@v1.0.6 From ef1825b63c81cad6aa5b1e1b7c943ad639bd3140 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 17 Aug 2023 07:09:19 -0500 Subject: [PATCH 107/134] [SDK-4443] Use GitHub Actions for CI (#668) --- .github/workflows/build-and-test.yml | 27 +++++++++++++++++++++++++++ .github/workflows/dependabot.yml | 14 ++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .github/workflows/build-and-test.yml create mode 100644 .github/workflows/dependabot.yml diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..f86ed60e --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,27 @@ +name: auth0/java-jwt/build-and-test + +on: + pull_request: + merge_group: + push: + branches: ["master", "main", "v1"] + +jobs: + gradle: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + - uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c + with: + arguments: assemble apiDiff check jacocoTestReport --continue --console=plain + - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d + with: + flags: unittests + - uses: actions/upload-artifact@v3 + with: + name: Reports + path: lib/build/reports diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml new file mode 100644 index 00000000..f2839f50 --- /dev/null +++ b/.github/workflows/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "gradle" + directory: "lib" + schedule: + interval: "daily" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] \ No newline at end of file From 9f7eaa49384ea5f66e985ff97ef2a0520e391570 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Thu, 17 Aug 2023 23:16:04 -0500 Subject: [PATCH 108/134] Remove CircleCI (#670) --- .circleci/config.yml | 61 -------------------------------------------- README.md | 2 +- 2 files changed, 1 insertion(+), 62 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 1675c39f..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,61 +0,0 @@ -version: 2.1 -orbs: - codecov: codecov/codecov@3 - -commands: - checkout-and-build: - steps: - - checkout - - run: chmod +x gradlew - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "build.gradle" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - run: ./gradlew clean build - - save_cache: - paths: - - ~/.m2 - key: v1-dependencies-{{ checksum "build.gradle" }} - run-tests: - steps: - - run: ./gradlew check jacocoTestReport --continue --console=plain - - codecov/upload - run-api-diff: - steps: - # run apiDiff task - - run: ./gradlew apiDiff - - store_artifacts: - path: lib/build/reports/apiDiff/apiDiff.txt - - store_artifacts: - path: lib/build/reports/apiDiff/apiDiff.html -jobs: - build: - docker: - - image: openjdk:11.0-jdk - steps: - - checkout-and-build - - run-tests - environment: - GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - TERM: dumb - api-diff: - docker: - - image: openjdk:11.0-jdk - steps: - - checkout-and-build - - run-api-diff - environment: - GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' - _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - TERM: dumb - -workflows: - build-and-test: - jobs: - - build - api-diff: - jobs: - - api-diff diff --git a/README.md b/README.md index 9f425898..4663cbdf 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![A Java implementation of JSON Web Token (JWT) - RFC 7519.](https://cdn.auth0.com/website/sdks/banners/java-jwt-banner.png) -[![CircleCI](https://img.shields.io/circleci/project/github/auth0/java-jwt.svg?style=flat-square)](https://circleci.com/gh/auth0/java-jwt/tree/master) +![Build Status](https://img.shields.io/github/checks-status/auth0/java-jwt/master) [![Coverage Status](https://img.shields.io/codecov/c/github/auth0/java-jwt.svg?style=flat-square)](https://codecov.io/github/auth0/java-jwt) [![License](http://img.shields.io/:license-mit-blue.svg?style=flat)](https://doge.mit-license.org/) [![Maven Central](https://img.shields.io/maven-central/v/com.auth0/java-jwt.svg?style=flat-square)](https://mvnrepository.com/artifact/com.auth0/java-jwt) From a6fa0b4d338386e7f0650b714444633420af0515 Mon Sep 17 00:00:00 2001 From: Wood Hwang Date: Wed, 13 Sep 2023 09:24:47 +0900 Subject: [PATCH 109/134] Fix typo on a comment in JWTCreator.java (#672) --- lib/src/main/java/com/auth0/jwt/JWTCreator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index 0b0d21e4..bfcb9147 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -582,7 +582,7 @@ private static boolean isBasicType(Object value) { } /** - * Creates a new JWT and signs is with the given algorithm. + * Creates a new JWT and signs it with the given algorithm. * * @param algorithm used to sign the JWT * @return a new JWT token From bad6035bb87007d6744f4089857e22f8f085e1e5 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Mon, 20 Nov 2023 10:15:43 -0600 Subject: [PATCH 110/134] Remove dead README links (#676) --- lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index 27d79909..248af7c5 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -132,7 +132,6 @@ public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException { * * @param secret the secret bytes to use in the verify or signing instance. * Ensure the length of the secret is at least 256 bit long - * See HMAC Key Length and Security in README * @return a valid HMAC256 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -145,7 +144,6 @@ public static Algorithm HMAC256(String secret) throws IllegalArgumentException { * * @param secret the secret bytes to use in the verify or signing instance. * Ensure the length of the secret is at least 256 bit long - * See HMAC Key Length and Security in README * @return a valid HMAC256 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -158,7 +156,6 @@ public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException { * * @param secret the secret bytes to use in the verify or signing instance. * Ensure the length of the secret is at least 384 bit long - * See HMAC Key Length and Security in README * @return a valid HMAC384 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -171,7 +168,6 @@ public static Algorithm HMAC384(String secret) throws IllegalArgumentException { * * @param secret the secret bytes to use in the verify or signing instance. * Ensure the length of the secret is at least 384 bit long - * See HMAC Key Length and Security in README * @return a valid HMAC384 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -184,7 +180,6 @@ public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException { * * @param secret the secret bytes to use in the verify or signing instance. * Ensure the length of the secret is at least 512 bit long - * See HMAC Key Length and Security in README * @return a valid HMAC512 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ @@ -197,7 +192,6 @@ public static Algorithm HMAC512(String secret) throws IllegalArgumentException { * * @param secret the secret bytes to use in the verify or signing instance. * Ensure the length of the secret is at least 512 bit long - * See HMAC Key Length and Security in README * @return a valid HMAC512 Algorithm. * @throws IllegalArgumentException if the provided Secret is null. */ From d5c05d73a245b5de84830ea67565556232598fb1 Mon Sep 17 00:00:00 2001 From: Jim Anderson Date: Fri, 1 Dec 2023 06:48:30 -0600 Subject: [PATCH 111/134] empty expected audience array should throw InvalidClaimException (#679) --- lib/src/main/java/com/auth0/jwt/JWTVerifier.java | 15 +++++++++++---- .../test/java/com/auth0/jwt/JWTVerifierTest.java | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 6cec2026..bf180300 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -364,12 +364,19 @@ private boolean assertInstantIsLessThanOrEqualToNow(Instant claimVal, long leewa } private boolean assertValidAudienceClaim( - List audience, - List values, + List actualAudience, + List expectedAudience, boolean shouldContainAll ) { - return !(audience == null || (shouldContainAll && !audience.containsAll(values)) - || (!shouldContainAll && Collections.disjoint(audience, values))); + if (actualAudience == null || expectedAudience == null) { + return false; + } + + if (shouldContainAll) { + return actualAudience.containsAll(expectedAudience); + } else { + return !Collections.disjoint(actualAudience, expectedAudience); + } } private void assertPositive(long leeway) { diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index 5a784b87..732d6365 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -310,6 +310,21 @@ public void shouldThrowWhenAudienceClaimIsNullWithAnAudience() { assertThat(e.getClaimValue().asArray(String.class), is(new String[] {null})); } + @Test + public void shouldThrowWhenExpectedEmptyList() { + IncorrectClaimException e = assertThrows(null, IncorrectClaimException.class, () -> { + // Token 'aud': 'wide audience' + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ3aWRlIGF1ZGllbmNlIn0.c9anq03XepcuEKWEVsPk9cck0sIIfrT6hHbBsCar49o"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withAnyOfAudience(new String[0]) + .build() + .verify(token); + }); + assertThat(e.getMessage(), is("The Claim 'aud' value doesn't contain the required audience.")); + assertThat(e.getClaimName(), is(RegisteredClaims.AUDIENCE)); + assertThat(e.getClaimValue().asString(), is("wide audience")); + } + @Test public void shouldNotReplaceWhenMultipleChecksAreAdded() { JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC256("secret")) From d97f4e6df09d5437aede60776fa69e0ad49824af Mon Sep 17 00:00:00 2001 From: Kasper Karlsson Date: Tue, 6 Feb 2024 05:27:38 +0100 Subject: [PATCH 112/134] Fix typo in example code (#682) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4663cbdf..285f56ec 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ DecodedJWT decodedJWT; try { Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); JWTVerifier verifier = JWT.require(algorithm) - // specify an specific claim validations + // specify any specific claim validations .withIssuer("auth0") // reusable verifier instance .build(); From 3aa997afc11d109a8565d3101711bfb0ce110bf6 Mon Sep 17 00:00:00 2001 From: Steven Wong Date: Thu, 25 Jul 2024 22:25:13 +0800 Subject: [PATCH 113/134] Update codeowner file with new GitHub team name --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 60f116c0..7958e8bd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @auth0/dx-sdks-engineer +* @auth0/project-dx-sdks-engineer-codeowner From 0c76c94784e1e00010e9848b09eff2c7df1ae4d6 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 19 Dec 2023 15:07:35 +0100 Subject: [PATCH 114/134] Automate release workflow --- .github/actions/get-prerelease/action.yml | 30 +++++++ .github/actions/get-release-notes/action.yml | 42 ++++++++++ .github/actions/get-version/action.yml | 21 +++++ .github/actions/maven-publish/action.yml | 44 ++++++++++ .github/actions/release-create/action.yml | 47 +++++++++++ .github/actions/tag-exists/action.yml | 36 ++++++++ .github/workflows/java-release.yml | 88 ++++++++++++++++++++ .github/workflows/release.yml | 27 ++++++ lib/build.gradle | 16 ++-- 9 files changed, 343 insertions(+), 8 deletions(-) create mode 100644 .github/actions/get-prerelease/action.yml create mode 100644 .github/actions/get-release-notes/action.yml create mode 100644 .github/actions/get-version/action.yml create mode 100644 .github/actions/maven-publish/action.yml create mode 100644 .github/actions/release-create/action.yml create mode 100644 .github/actions/tag-exists/action.yml create mode 100644 .github/workflows/java-release.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/actions/get-prerelease/action.yml b/.github/actions/get-prerelease/action.yml new file mode 100644 index 00000000..ce7acdc3 --- /dev/null +++ b/.github/actions/get-prerelease/action.yml @@ -0,0 +1,30 @@ +name: Return a boolean indicating if the version contains prerelease identifiers + +# +# Returns a simple true/false boolean indicating whether the version indicates it's a prerelease or not. +# +# TODO: Remove once the common repo is public. +# + +inputs: + version: + required: true + +outputs: + prerelease: + value: ${{ steps.get_prerelease.outputs.PRERELEASE }} + +runs: + using: composite + + steps: + - id: get_prerelease + shell: bash + run: | + if [[ "${VERSION}" == *"beta"* || "${VERSION}" == *"alpha"* ]]; then + echo "PRERELEASE=true" >> $GITHUB_OUTPUT + else + echo "PRERELEASE=false" >> $GITHUB_OUTPUT + fi + env: + VERSION: ${{ inputs.version }} diff --git a/.github/actions/get-release-notes/action.yml b/.github/actions/get-release-notes/action.yml new file mode 100644 index 00000000..287d2066 --- /dev/null +++ b/.github/actions/get-release-notes/action.yml @@ -0,0 +1,42 @@ +name: Return the release notes extracted from the body of the PR associated with the release. + +# +# Returns the release notes from the content of a pull request linked to a release branch. It expects the branch name to be in the format release/vX.Y.Z, release/X.Y.Z, release/vX.Y.Z-beta.N. etc. +# +# TODO: Remove once the common repo is public. +# +inputs: + version: + required: true + repo_name: + required: false + repo_owner: + required: true + token: + required: true + +outputs: + release-notes: + value: ${{ steps.get_release_notes.outputs.RELEASE_NOTES }} + +runs: + using: composite + + steps: + - uses: actions/github-script@v7 + id: get_release_notes + with: + result-encoding: string + script: | + const { data: pulls } = await github.rest.pulls.list({ + owner: process.env.REPO_OWNER, + repo: process.env.REPO_NAME, + state: 'all', + head: `${process.env.REPO_OWNER}:release/${process.env.VERSION}`, + }); + core.setOutput('RELEASE_NOTES', pulls[0].body); + env: + GITHUB_TOKEN: ${{ inputs.token }} + REPO_OWNER: ${{ inputs.repo_owner }} + REPO_NAME: ${{ inputs.repo_name }} + VERSION: ${{ inputs.version }} diff --git a/.github/actions/get-version/action.yml b/.github/actions/get-version/action.yml new file mode 100644 index 00000000..9440ec92 --- /dev/null +++ b/.github/actions/get-version/action.yml @@ -0,0 +1,21 @@ +name: Return the version extracted from the branch name + +# +# Returns the version from the .version file. +# +# TODO: Remove once the common repo is public. +# + +outputs: + version: + value: ${{ steps.get_version.outputs.VERSION }} + +runs: + using: composite + + steps: + - id: get_version + shell: bash + run: | + VERSION=$(head -1 .version) + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml new file mode 100644 index 00000000..ee477061 --- /dev/null +++ b/.github/actions/maven-publish/action.yml @@ -0,0 +1,44 @@ +name: Publish release to Java + +inputs: + ossr-username: + required: true + ossr-password: + required: true + signing-key: + required: true + signing-password: + required: true + java-version: + required: true + is-android: + required: true + version: + required: true + +runs: + using: composite + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Java + shell: bash + run: | + curl -s "https://get.sdkman.io" | bash + source "/home/runner/.sdkman/bin/sdkman-init.sh" + sdk list java + sdk install java ${{ inputs.java-version }} && sdk default java ${{ inputs.java-version }} + + - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 + + - name: Publish Java + shell: bash + if: inputs.is-android == 'false' + run: ./gradlew clean assemble sign publishMavenJavaPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" + + - name: Publish Android + shell: bash + if: inputs.is-android == 'true' + run: ./gradlew clean assemble sign publishAndroidLibraryPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" diff --git a/.github/actions/release-create/action.yml b/.github/actions/release-create/action.yml new file mode 100644 index 00000000..6a2bf804 --- /dev/null +++ b/.github/actions/release-create/action.yml @@ -0,0 +1,47 @@ +name: Create a GitHub release + +# +# Creates a GitHub release with the given version. +# +# TODO: Remove once the common repo is public. +# + +inputs: + token: + required: true + files: + required: false + name: + required: true + body: + required: true + tag: + required: true + commit: + required: true + draft: + default: false + required: false + prerelease: + default: false + required: false + fail_on_unmatched_files: + default: true + required: false + +runs: + using: composite + + steps: + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 + with: + body: ${{ inputs.body }} + name: ${{ inputs.name }} + tag_name: ${{ inputs.tag }} + target_commitish: ${{ inputs.commit }} + draft: ${{ inputs.draft }} + prerelease: ${{ inputs.prerelease }} + fail_on_unmatched_files: ${{ inputs.fail_on_unmatched_files }} + files: ${{ inputs.files }} + env: + GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/actions/tag-exists/action.yml b/.github/actions/tag-exists/action.yml new file mode 100644 index 00000000..b5fbdb73 --- /dev/null +++ b/.github/actions/tag-exists/action.yml @@ -0,0 +1,36 @@ +name: Return a boolean indicating if a tag already exists for the repository + +# +# Returns a simple true/false boolean indicating whether the tag exists or not. +# +# TODO: Remove once the common repo is public. +# + +inputs: + token: + required: true + tag: + required: true + +outputs: + exists: + description: 'Whether the tag exists or not' + value: ${{ steps.tag-exists.outputs.EXISTS }} + +runs: + using: composite + + steps: + - id: tag-exists + shell: bash + run: | + GET_API_URL="https://api.github.com/repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG_NAME}" + http_status_code=$(curl -LI $GET_API_URL -o /dev/null -w '%{http_code}\n' -s -H "Authorization: token ${GITHUB_TOKEN}") + if [ "$http_status_code" -ne "404" ] ; then + echo "EXISTS=true" >> $GITHUB_OUTPUT + else + echo "EXISTS=false" >> $GITHUB_OUTPUT + fi + env: + TAG_NAME: ${{ inputs.tag }} + GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml new file mode 100644 index 00000000..3f81eb14 --- /dev/null +++ b/.github/workflows/java-release.yml @@ -0,0 +1,88 @@ +name: Create Java and GitHub Release + +on: + workflow_call: + inputs: + java-version: + required: true + type: string + is-android: + required: true + type: string + secrets: + ossr-username: + required: true + ossr-password: + required: true + signing-key: + required: true + signing-password: + required: true + github-token: + required: true + +### TODO: Replace instances of './.github/actions/' w/ `auth0/dx-sdk-actions/` and append `@latest` after the common `dx-sdk-actions` repo is made public. +### TODO: Also remove `get-prerelease`, `get-version`, `release-create`, `tag-create` and `tag-exists` actions from this repo's .github/actions folder once the repo is public. + +jobs: + release: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + runs-on: ubuntu-latest + environment: release + + steps: + # Checkout the code + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Get the version from the branch name + - id: get_version + uses: ./.github/actions/get-version + + # Get the prerelease flag from the branch name + - id: get_prerelease + uses: ./.github/actions/get-prerelease + with: + version: ${{ steps.get_version.outputs.version }} + + # Get the release notes + - id: get_release_notes + uses: ./.github/actions/get-release-notes + with: + token: ${{ secrets.github-token }} + version: ${{ steps.get_version.outputs.version }} + repo_owner: ${{ github.repository_owner }} + repo_name: ${{ github.event.repository.name }} + + # Check if the tag already exists + - id: tag_exists + uses: ./.github/actions/tag-exists + with: + tag: ${{ steps.get_version.outputs.version }} + token: ${{ secrets.github-token }} + + # If the tag already exists, exit with an error + - if: steps.tag_exists.outputs.exists == 'true' + run: exit 1 + + # Publish the release to Maven + - uses: ./.github/actions/maven-publish + with: + java-version: ${{ inputs.java-version }} + is-android: ${{ inputs.is-android }} + version: ${{ steps.get_version.outputs.version }} + ossr-username: ${{ secrets.ossr-username }} + ossr-password: ${{ secrets.ossr-password }} + signing-key: ${{ secrets.signing-key }} + signing-password: ${{ secrets.signing-password }} + + # Create a release for the tag + - uses: ./.github/actions/release-create + with: + token: ${{ secrets.github-token }} + name: ${{ steps.get_version.outputs.version }} + body: ${{ steps.get_release_notes.outputs.release-notes }} + tag: ${{ steps.get_version.outputs.version }} + commit: ${{ github.sha }} + prerelease: ${{ steps.get_prerelease.outputs.prerelease }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..63482cca --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,27 @@ +name: Create GitHub Release + +on: + pull_request: + types: + - closed + workflow_dispatch: + +permissions: + contents: write + +### TODO: Replace instances of './.github/workflows/' w/ `auth0/dx-sdk-actions/workflows/` and append `@latest` after the common `dx-sdk-actions` repo is made public. +### TODO: Also remove `get-prerelease`, `get-release-notes`, `get-version`, `maven-publish`, `release-create`, and `tag-exists` actions from this repo's .github/actions folder once the repo is public. +### TODO: Also remove `java-release` workflow from this repo's .github/workflows folder once the repo is public. + +jobs: + release: + uses: ./.github/workflows/java-release.yml + with: + java-version: 8.0.382-tem + is-android: false + secrets: + ossr-username: ${{ secrets.OSSR_USERNAME }} + ossr-password: ${{ secrets.OSSR_PASSWORD }} + signing-key: ${{ secrets.SIGNING_KEY }} + signing-password: ${{ secrets.SIGNING_PASSWORD }} + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/lib/build.gradle b/lib/build.gradle index c4e11764..aa134c32 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -31,12 +31,16 @@ tasks.named("checkstyleJmh").configure({ logger.lifecycle("Using version ${version} for ${group}.${name}") +def signingKey = findProperty('signingKey') +def signingKeyPwd = findProperty('signingPassword') + oss { name "java jwt" repository "java-jwt" organization "auth0" description "Java implementation of JSON Web Token (JWT)" baselineCompareVersion "4.1.0" + skipAssertSigningConfiguration true developers { auth0 { @@ -54,6 +58,10 @@ oss { } } +signing { + useInMemoryPgpKeys(signingKey, signingKeyPwd) +} + java { toolchain { languageVersion = JavaLanguageVersion.of(11) @@ -158,14 +166,6 @@ jar { compileModuleInfoJava.dependsOn compileJava classes.dependsOn compileModuleInfoJava -// Creates a version.txt file containing the current version of the SDK. -// This file is picked up and parsed by our Ship Orb to determine the version. -task exportVersion() { - doLast { - new File(rootDir, "version.txt").text = "$version" - } -} - // you can pass any arguments JMH accepts via Gradle args. // Example: ./gradlew runJMH --args="-lrf" tasks.register('runJMH', JavaExec) { From 05fef18c2b3cdfd5ece2cb51ebcbff5a6ebce127 Mon Sep 17 00:00:00 2001 From: Poovamraj T T Date: Tue, 19 Dec 2023 15:10:35 +0100 Subject: [PATCH 115/134] Add .version and modify .shiprc --- .shiprc | 1 + .version | 1 + 2 files changed, 2 insertions(+) create mode 100644 .version diff --git a/.shiprc b/.shiprc index fe59345e..1b83cc62 100644 --- a/.shiprc +++ b/.shiprc @@ -1,6 +1,7 @@ { "files": { "README.md": [], + ".version": [], "lib/build.gradle": ["version = \"{MAJOR}.{MINOR}.{PATCH}\""] }, "prefixVersion": false diff --git a/.version b/.version new file mode 100644 index 00000000..64b5ae39 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +4.4.0 \ No newline at end of file From 9cd2b043280e3f66778d75198aa34bf821696c3c Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Wed, 20 Dec 2023 14:26:46 +0100 Subject: [PATCH 116/134] Update .github/workflows/release.yml Co-authored-by: Jim Anderson --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 63482cca..7a98f05e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: release: uses: ./.github/workflows/java-release.yml with: - java-version: 8.0.382-tem + java-version: 11.0.21-tem is-android: false secrets: ossr-username: ${{ secrets.OSSR_USERNAME }} From 876d7456d362e031fcb1a56609e2c850bede426f Mon Sep 17 00:00:00 2001 From: Tanya Sinha Date: Thu, 14 Nov 2024 16:05:59 +0530 Subject: [PATCH 117/134] Add reversing lab scanner (#695) --- .github/actions/rl-scanner/action.yml | 66 ++++++++++++++++++++++++ .github/workflows/release.yml | 14 +++++ .github/workflows/rl-secure.yml | 73 +++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 .github/actions/rl-scanner/action.yml create mode 100644 .github/workflows/rl-secure.yml diff --git a/.github/actions/rl-scanner/action.yml b/.github/actions/rl-scanner/action.yml new file mode 100644 index 00000000..fbf81217 --- /dev/null +++ b/.github/actions/rl-scanner/action.yml @@ -0,0 +1,66 @@ +name: 'Reversing Labs Scanner' +description: 'Runs the Reversing Labs scanner on a specified artifact.' +inputs: + artifact-path: + description: 'Path to the artifact to be scanned.' + required: true + version: + description: 'Version of the artifact.' + required: true + +runs: + using: 'composite' + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install Python dependencies + shell: bash + run: | + pip install boto3 requests + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ env.PRODSEC_TOOLS_ARN }} + aws-region: us-east-1 + mask-aws-account-id: true + + - name: Install RL Wrapper + shell: bash + run: | + pip install rl-wrapper>=1.0.0 --index-url "https://${{ env.PRODSEC_TOOLS_USER }}:${{ env.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple" + - name: Run RL Scanner + shell: bash + env: + RLSECURE_LICENSE: ${{ env.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ env.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ env.SIGNAL_HANDLER_TOKEN }} + PYTHONUNBUFFERED: 1 + run: | + if [ ! -f "${{ inputs.artifact-path }}" ]; then + echo "Artifact not found: ${{ inputs.artifact-path }}" + exit 1 + fi + rl-wrapper \ + --artifact "${{ inputs.artifact-path }}" \ + --name "${{ github.event.repository.name }}" \ + --version "${{ inputs.version }}" \ + --repository "${{ github.repository }}" \ + --commit "${{ github.sha }}" \ + --build-env "github_actions" \ + --suppress_output + # Check the outcome of the scanner + if [ $? -ne 0 ]; then + echo "RL Scanner failed." + echo "scan-status=failed" >> $GITHUB_ENV + exit 1 + else + echo "RL Scanner passed." + echo "scan-status=success" >> $GITHUB_ENV + fi +outputs: + scan-status: + description: 'The outcome of the scan process.' + value: ${{ env.scan-status }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a98f05e..49e48059 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,14 +8,28 @@ on: permissions: contents: write + id-token: write # This is required for requesting the JWT ### TODO: Replace instances of './.github/workflows/' w/ `auth0/dx-sdk-actions/workflows/` and append `@latest` after the common `dx-sdk-actions` repo is made public. ### TODO: Also remove `get-prerelease`, `get-release-notes`, `get-version`, `maven-publish`, `release-create`, and `tag-exists` actions from this repo's .github/actions folder once the repo is public. ### TODO: Also remove `java-release` workflow from this repo's .github/workflows folder once the repo is public. jobs: + rl-scanner: + uses: ./.github/workflows/rl-secure.yml + with: + java-version: 11 + artifact-name: 'java-jwt.tgz' + secrets: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} release: uses: ./.github/workflows/java-release.yml + needs: rl-scanner with: java-version: 11.0.21-tem is-android: false diff --git a/.github/workflows/rl-secure.yml b/.github/workflows/rl-secure.yml new file mode 100644 index 00000000..ef329594 --- /dev/null +++ b/.github/workflows/rl-secure.yml @@ -0,0 +1,73 @@ +name: RL-Secure Workflow + +on: + workflow_call: + inputs: + java-version: + required: true + type: string + artifact-name: + required: true + type: string + secrets: + RLSECURE_LICENSE: + required: true + RLSECURE_SITE_KEY: + required: true + SIGNAL_HANDLER_TOKEN: + required: true + PRODSEC_TOOLS_USER: + required: true + PRODSEC_TOOLS_TOKEN: + required: true + PRODSEC_TOOLS_ARN: + required: true + +jobs: + checkout-build-scan-only: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + runs-on: ubuntu-latest + outputs: + scan-status: ${{ steps.rl-scan-conclusion.outcome }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ inputs.java-version }} + + - name: Build with Gradle + uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c + with: + arguments: assemble apiDiff check jacocoTestReport --continue --console=plain + + - name: Get Artifact Version + id: get_version + uses: ./.github/actions/get-version + + - name: Create tgz build artifact + run: | + tar -czvf ${{ inputs.artifact-name }} * + + - name: Run RL Scanner + id: rl-scan-conclusion + uses: ./.github/actions/rl-scanner + with: + artifact-path: "$(pwd)/${{ inputs.artifact-name }}" + version: "${{ steps.get_version.outputs.version }}" + env: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + + - name: Output scan result + run: echo "scan-status=${{ steps.rl-scan-conclusion.outcome }}" >> $GITHUB_ENV \ No newline at end of file From 41d93afce36dd07431f45f39401f24840835f54e Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 15 Nov 2024 21:12:00 +0530 Subject: [PATCH 118/134] added snyk workflow --- .github/workflows/snyk.yml | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/snyk.yml diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml new file mode 100644 index 00000000..9394832d --- /dev/null +++ b/.github/workflows/snyk.yml @@ -0,0 +1,47 @@ +name: Snyk + +on: + merge_group: + workflow_dispatch: + pull_request_target: + types: + - opened + - synchronize + push: + branches: + - master + schedule: + - cron: '30 0 1,15 * *' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +jobs: + authorize: + name: Authorize + environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} + runs-on: ubuntu-latest + steps: + - run: true + + check: + needs: authorize + + name: Check for Vulnerabilities + runs-on: ubuntu-latest + + steps: + - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' + run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. + + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} + + - uses: snyk/actions/gradle-jdk11@b98d498629f1c368650224d6d212bf7dfa89e4bf # pin@0.4.0 + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} \ No newline at end of file From b915cb6ebe089ac68ae70221792576d322c9a924 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 15 Nov 2024 21:16:11 +0530 Subject: [PATCH 119/134] removed pull_request_target --- .github/workflows/snyk.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml index 9394832d..457b6afa 100644 --- a/.github/workflows/snyk.yml +++ b/.github/workflows/snyk.yml @@ -3,7 +3,7 @@ name: Snyk on: merge_group: workflow_dispatch: - pull_request_target: + pull_request: types: - opened - synchronize @@ -21,16 +21,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: - authorize: - name: Authorize - environment: ${{ github.actor != 'dependabot[bot]' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository && 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: true check: - needs: authorize - name: Check for Vulnerabilities runs-on: ubuntu-latest From de23d8f21f49e4d7a5b5572ac1416d13f2ddc5e8 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 3 Jan 2025 18:21:41 +0530 Subject: [PATCH 120/134] add java 21 in CI --- .github/workflows/build-and-test.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f86ed60e..32886d68 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -9,12 +9,17 @@ on: jobs: gradle: runs-on: ubuntu-latest + + strategy: + matrix: + java-version: [11, 17, 21] + steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: distribution: temurin - java-version: 11 + java-version: ${{ matrix.java-version }} - uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c with: arguments: assemble apiDiff check jacocoTestReport --continue --console=plain From 9e04f118db4f3356e673aa981be95a56f8ddf84d Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 3 Jan 2025 18:25:53 +0530 Subject: [PATCH 121/134] added java 21 --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 32886d68..5ca24522 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - java-version: [11, 17, 21] + java-version: [11, 21] steps: - uses: actions/checkout@v3 From cc705395f5099d09a8a33a0ea35c87915e38aa66 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 17 Jan 2025 10:27:38 +0530 Subject: [PATCH 122/134] added java 21 tests --- .github/workflows/build-and-test.yml | 7 +------ lib/build.gradle | 11 +++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5ca24522..f86ed60e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -9,17 +9,12 @@ on: jobs: gradle: runs-on: ubuntu-latest - - strategy: - matrix: - java-version: [11, 21] - steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: distribution: temurin - java-version: ${{ matrix.java-version }} + java-version: 11 - uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c with: arguments: assemble apiDiff check jacocoTestReport --continue --console=plain diff --git a/lib/build.gradle b/lib/build.gradle index aa134c32..77de85a7 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -154,9 +154,20 @@ def testJava17 = tasks.register('testJava17', Test) { shouldRunAfter(tasks.named('test')) } +def testJava21 = tasks.register('testJava21', Test) { + description = 'Runs unit tests on Java 21.' + group = 'verification' + + javaLauncher.set(javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(21) + }) + shouldRunAfter(tasks.named('test')) +} + tasks.named('check') { dependsOn(testJava8) dependsOn(testJava17) + dependsOn(testJava21) } jar { From d20aec6d58cd37ab518b987cd811bb6480a2ff97 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Fri, 17 Jan 2025 10:35:41 +0530 Subject: [PATCH 123/134] updated jacoco toll version --- lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/build.gradle b/lib/build.gradle index 77de85a7..bff7bb9c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -94,7 +94,7 @@ dependencies { } jacoco { - toolVersion = "0.8.7" + toolVersion = "0.8.10" } jacocoTestReport { From 8278f62be812496210c5fa5a11192741d2d6c8c7 Mon Sep 17 00:00:00 2001 From: Carlos Galan Cladera Date: Wed, 11 Dec 2024 14:53:41 +0100 Subject: [PATCH 124/134] fix: upgrade jackson-core to 2.15 --- lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/build.gradle b/lib/build.gradle index aa134c32..c2c77533 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -80,7 +80,7 @@ javadoc { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.0' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' From 3840a1eaf07e2de55c7676b90d6b398526355ff1 Mon Sep 17 00:00:00 2001 From: Carlos Galan Cladera Date: Wed, 11 Dec 2024 15:11:01 +0100 Subject: [PATCH 125/134] fix: upgrade jackson-core to 2.15.4 --- lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/build.gradle b/lib/build.gradle index c2c77533..16a55af1 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -80,7 +80,7 @@ javadoc { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.4' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' testImplementation 'junit:junit:4.13.2' From a52bec0224ea087116c807d8f895fa98d1596013 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 22 Jan 2025 14:02:26 +0530 Subject: [PATCH 126/134] added maven-publish changes --- .github/actions/maven-publish/action.yml | 25 ++--- .github/workflows/java-release.yml | 9 +- .github/workflows/release.yml | 3 +- gradle.properties | 22 +++++ gradle/maven-publish.gradle | 113 +++++++++++++++++++++++ gradle/versioning.gradle | 17 ++++ lib/build.gradle | 89 +++++++++++++----- settings.gradle | 3 - 8 files changed, 231 insertions(+), 50 deletions(-) create mode 100644 gradle/maven-publish.gradle create mode 100644 gradle/versioning.gradle diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml index ee477061..0d280cbe 100644 --- a/.github/actions/maven-publish/action.yml +++ b/.github/actions/maven-publish/action.yml @@ -1,20 +1,16 @@ name: Publish release to Java inputs: + java-version: + required: true ossr-username: required: true - ossr-password: + ossr-token: required: true signing-key: required: true signing-password: required: true - java-version: - required: true - is-android: - required: true - version: - required: true runs: using: composite @@ -33,12 +29,11 @@ runs: - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 - - name: Publish Java - shell: bash - if: inputs.is-android == 'false' - run: ./gradlew clean assemble sign publishMavenJavaPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" - - - name: Publish Android + - name: Publish Android/Java Packages to Maven shell: bash - if: inputs.is-android == 'true' - run: ./gradlew clean assemble sign publishAndroidLibraryPublicationToMavenRepository -PisSnapshot=false -Pversion="${{ inputs.version }}" -PossrhUsername="${{ inputs.ossr-username }}" -PossrhPassword="${{ inputs.ossr-password }}" -PsigningKey="${{ inputs.signing-key }}" -PsigningPassword="${{ inputs.signing-password }}" + run: ./gradlew publish -PisSnapshot=false --stacktrace + env: + MAVEN_USERNAME: ${{ inputs.ossr-username }} + MAVEN_PASSWORD: ${{ inputs.ossr-token }} + SIGNING_KEY: ${{ inputs.signing-key}} + SIGNING_PASSWORD: ${{ inputs.signing-password}} \ No newline at end of file diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml index 3f81eb14..ddce3e59 100644 --- a/.github/workflows/java-release.yml +++ b/.github/workflows/java-release.yml @@ -6,13 +6,10 @@ on: java-version: required: true type: string - is-android: - required: true - type: string secrets: ossr-username: required: true - ossr-password: + ossr-token: required: true signing-key: required: true @@ -70,10 +67,8 @@ jobs: - uses: ./.github/actions/maven-publish with: java-version: ${{ inputs.java-version }} - is-android: ${{ inputs.is-android }} - version: ${{ steps.get_version.outputs.version }} ossr-username: ${{ secrets.ossr-username }} - ossr-password: ${{ secrets.ossr-password }} + ossr-token: ${{ secrets.ossr-token }} signing-key: ${{ secrets.signing-key }} signing-password: ${{ secrets.signing-password }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 49e48059..2b00e426 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,10 +32,9 @@ jobs: needs: rl-scanner with: java-version: 11.0.21-tem - is-android: false secrets: ossr-username: ${{ secrets.OSSR_USERNAME }} - ossr-password: ${{ secrets.OSSR_PASSWORD }} + ossr-token: ${{ secrets.OSSR_TOKEN }} signing-key: ${{ secrets.SIGNING_KEY }} signing-password: ${{ secrets.SIGNING_PASSWORD }} github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/gradle.properties b/gradle.properties index aac7c9b4..b4d8583f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,3 +15,25 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true + +GROUP=com.auth0 +POM_ARTIFACT_ID=java-jwt +VERSION_NAME=4.4.0 + +POM_NAME=java jwt +POM_DESCRIPTION=Java client library for the Auth0 platform +POM_PACKAGING=jar + +POM_URL=https://github.com/auth0/java-jwt +POM_SCM_URL=https://github.com/auth0/java-jwt + +POM_SCM_CONNECTION=scm:git:https://github.com/auth0/java-jwt.git +POM_SCM_DEV_CONNECTION=scm:git:https://github.com/auth0/java-jwt.git + +POM_LICENCE_NAME=The MIT License (MIT) +POM_LICENCE_URL=https://raw.githubusercontent.com/auth0/java-jwt/master/LICENSE +POM_LICENCE_DIST=repo + +POM_DEVELOPER_ID=auth0 +POM_DEVELOPER_NAME=Auth0 +POM_DEVELOPER_EMAIL=oss@auth0.com \ No newline at end of file diff --git a/gradle/maven-publish.gradle b/gradle/maven-publish.gradle new file mode 100644 index 00000000..206a581b --- /dev/null +++ b/gradle/maven-publish.gradle @@ -0,0 +1,113 @@ +apply plugin: 'maven-publish' +apply plugin: 'signing' + +task('sourcesJar', type: Jar, dependsOn: classes) { + archiveClassifier = 'sources' + from sourceSets.main.allSource +} + +task('javadocJar', type: Jar, dependsOn: javadoc) { + archiveClassifier = 'javadoc' + from javadoc.getDestinationDir() +} +tasks.withType(Javadoc).configureEach { + javadocTool = javaToolchains.javadocToolFor { + // Use latest JDK for javadoc generation + languageVersion = JavaLanguageVersion.of(17) + } +} + +javadoc { + // Specify the Java version that the project will use + options.addStringOption('-release', "8") +} +artifacts { + archives sourcesJar, javadocJar +} + + +final releaseRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +final snapshotRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + +publishing { + publications { + mavenJava(MavenPublication) { + + groupId = GROUP + artifactId = POM_ARTIFACT_ID + version = getVersionName() + + artifact("$buildDir/libs/${project.name}-${version}.jar") + artifact sourcesJar + artifact javadocJar + + pom { + name = POM_NAME + packaging = POM_PACKAGING + description = POM_DESCRIPTION + url = POM_URL + + licenses { + license { + name = POM_LICENCE_NAME + url = POM_LICENCE_URL + distribution = POM_LICENCE_DIST + } + } + + developers { + developer { + id = POM_DEVELOPER_ID + name = POM_DEVELOPER_NAME + email = POM_DEVELOPER_EMAIL + } + } + + scm { + url = POM_SCM_URL + connection = POM_SCM_CONNECTION + developerConnection = POM_SCM_DEV_CONNECTION + } + + pom.withXml { + def dependenciesNode = asNode().appendNode('dependencies') + + project.configurations.implementation.allDependencies.each { + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', it.group) + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + } + } + } + } + } + repositories { + maven { + name = "sonatype" + url = version.endsWith('SNAPSHOT') ? snapshotRepositoryUrl : releaseRepositoryUrl + credentials { + username = System.getenv("MAVEN_USERNAME") + password = System.getenv("MAVEN_PASSWORD") + } + } + } +} + +signing { + def signingKey = System.getenv("SIGNING_KEY") + def signingPassword = System.getenv("SIGNING_PASSWORD") + useInMemoryPgpKeys(signingKey, signingPassword) + + sign publishing.publications.mavenJava +} + +javadoc { + if(JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } +} + +tasks.named('publish').configure { + dependsOn tasks.named('assemble') +} \ No newline at end of file diff --git a/gradle/versioning.gradle b/gradle/versioning.gradle new file mode 100644 index 00000000..3441ae11 --- /dev/null +++ b/gradle/versioning.gradle @@ -0,0 +1,17 @@ +def getVersionFromFile() { + def versionFile = rootProject.file('.version') + return versionFile.text.readLines().first().trim() +} + +def isSnapshot() { + return hasProperty('isSnapshot') ? isSnapshot.toBoolean() : true +} + +def getVersionName() { + return isSnapshot() ? project.version+"-SNAPSHOT" : project.version +} + +ext { + getVersionName = this.&getVersionName + getVersionFromFile = this.&getVersionFromFile +} \ No newline at end of file diff --git a/lib/build.gradle b/lib/build.gradle index 148bce72..167f234a 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,9 +1,19 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + // https://github.com/melix/japicmp-gradle-plugin/issues/36 + classpath 'com.google.guava:guava:31.1-jre' + } +} plugins { id 'java' id 'jacoco' - id 'com.auth0.gradle.oss-library.java' id 'checkstyle' + id 'me.champeau.gradle.japicmp' version '0.2.9' } sourceSets { @@ -29,37 +39,69 @@ tasks.named("checkstyleJmh").configure({ enabled = false }) -logger.lifecycle("Using version ${version} for ${group}.${name}") +apply from: rootProject.file('gradle/versioning.gradle') + +version = getVersionFromFile() +group = GROUP +logger.lifecycle("Using version ${version} for ${name} group $group") -def signingKey = findProperty('signingKey') -def signingKeyPwd = findProperty('signingPassword') +import me.champeau.gradle.japicmp.JapicmpTask -oss { - name "java jwt" - repository "java-jwt" - organization "auth0" - description "Java implementation of JSON Web Token (JWT)" - baselineCompareVersion "4.1.0" - skipAssertSigningConfiguration true +project.afterEvaluate { - developers { - auth0 { - displayName = "Auth0" - email = "oss@auth0.com" + def versions = project.ext.testInJavaVersions + for (pluginJavaTestVersion in versions) { + def taskName = "testInJava-${pluginJavaTestVersion}" + tasks.register(taskName, Test) { + def versionToUse = taskName.split("-").getAt(1) as Integer + description = "Runs unit tests on Java version ${versionToUse}." + project.logger.quiet("Test will be running in ${versionToUse}") + group = 'verification' + javaLauncher.set(javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(versionToUse) + }) + shouldRunAfter(tasks.named('test')) } - lbalmaceda { - displayName = "Luciano Balmaceda" - email = "luciano.balmaceda@auth0.com" + tasks.named('check') { + dependsOn(taskName) } - hzalaz { - displayName = "Hernan Zalazar" - email = "hernan@auth0.com" + } + + project.configure(project) { + def baselineVersion = project.ext.baselineCompareVersion + task('apiDiff', type: JapicmpTask, dependsOn: 'jar') { + oldClasspath = files(getBaselineJar(project, baselineVersion)) + newClasspath = files(jar.archiveFile) + onlyModified = true + failOnModification = true + ignoreMissingClasses = true + htmlOutputFile = file("$buildDir/reports/apiDiff/apiDiff.html") + txtOutputFile = file("$buildDir/reports/apiDiff/apiDiff.txt") + doLast { + project.logger.quiet("Comparing against baseline version ${baselineVersion}") + } + } + } +} + +private static File getBaselineJar(Project project, String baselineVersion) { + // Use detached configuration: https://github.com/square/okhttp/blob/master/build.gradle#L270 + def group = project.group + try { + def baseline = "${project.group}:${project.name}:$baselineVersion" + project.group = 'virtual_group_for_japicmp' + def dependency = project.dependencies.create(baseline + "@jar") + return project.configurations.detachedConfiguration(dependency).files.find { + it.name == "${project.name}-${baselineVersion}.jar" } + } finally { + project.group = group } } -signing { - useInMemoryPgpKeys(signingKey, signingKeyPwd) +ext { + baselineCompareVersion = '4.1.0' + testInJavaVersions = [8, 11, 17, 21] } java { @@ -198,3 +240,4 @@ tasks.register('jmhHelp', JavaExec) { args '-h' } +apply from: rootProject.file('gradle/maven-publish.gradle') diff --git a/settings.gradle b/settings.gradle index 8d5f112c..d3c4c85b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,9 +2,6 @@ pluginManagement { repositories { gradlePluginPortal() } - plugins { - id 'com.auth0.gradle.oss-library.java' version '0.17.2' - } } include ':java-jwt' From 2643ca2a464dbb159377b67ae32c9e0b7c276b55 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 22 Jan 2025 15:55:30 +0530 Subject: [PATCH 127/134] removed version from gralde properties --- gradle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b4d8583f..74a5a049 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,6 @@ org.gradle.jvmargs=-Xmx1536m GROUP=com.auth0 POM_ARTIFACT_ID=java-jwt -VERSION_NAME=4.4.0 POM_NAME=java jwt POM_DESCRIPTION=Java client library for the Auth0 platform From 87710ed5aca11004ee7bc104fb60bb7c5994b0a5 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 22 Jan 2025 19:12:50 +0530 Subject: [PATCH 128/134] updated version --- gradle/maven-publish.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/maven-publish.gradle b/gradle/maven-publish.gradle index 206a581b..a9ad38d3 100644 --- a/gradle/maven-publish.gradle +++ b/gradle/maven-publish.gradle @@ -19,7 +19,7 @@ tasks.withType(Javadoc).configureEach { javadoc { // Specify the Java version that the project will use - options.addStringOption('-release', "8") + options.addStringOption('-release', "11") } artifacts { archives sourcesJar, javadocJar From 65181f8838bcd8cebb8585c8024baba9680d77d9 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 22 Jan 2025 19:47:05 +0530 Subject: [PATCH 129/134] Release 4.5.0 --- .version | 2 +- CHANGELOG.md | 14 ++++++++++++++ README.md | 4 ++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.version b/.version index 64b5ae39..ae153944 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -4.4.0 \ No newline at end of file +4.5.0 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b1e75bd..6bb634fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Change Log +## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-22) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) + +**Added** +- Fix jackson vuln [\#705](https://github.com/auth0/java-jwt/pull/705) ([tanya732](https://github.com/tanya732)) +- Fix typo in example code [\#682](https://github.com/auth0/java-jwt/pull/682) ([kasperkarlsson](https://github.com/kasperkarlsson)) +- Remove dead README links [\#676](https://github.com/auth0/java-jwt/pull/676) ([jimmyjames](https://github.com/jimmyjames)) +- Fix typo on a comment in JWTCreator.java [\#672](https://github.com/auth0/java-jwt/pull/672) ([sgc109](https://github.com/sgc109)) +- Remove CircleCI [\#670](https://github.com/auth0/java-jwt/pull/670) ([jimmyjames](https://github.com/jimmyjames)) +- Empty string audience claim should be deserialized as empty string [\#663](https://github.com/auth0/java-jwt/pull/663) ([jimmyjames](https://github.com/jimmyjames)) + +**Fixed** +- empty expected audience array should throw InvalidClaimException [\#679](https://github.com/auth0/java-jwt/pull/679) ([jimmyjames](https://github.com/jimmyjames)) + ## [4.4.0](https://github.com/auth0/java-jwt/tree/4.4.0) (2023-03-31) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.3.0...4.4.0) diff --git a/README.md b/README.md index 285f56ec..9d0ae41c 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,14 @@ Add the dependency via Maven: com.auth0 java-jwt - 4.4.0 + 4.5.0 ``` or Gradle: ```gradle -implementation 'com.auth0:java-jwt:4.4.0' +implementation 'com.auth0:java-jwt:4.5.0' ``` ### Create a JWT From 6e76728a92249fd8595e79ee8fdd742a063aa61c Mon Sep 17 00:00:00 2001 From: tanya732 Date: Mon, 27 Jan 2025 12:24:01 +0530 Subject: [PATCH 130/134] upgraded plugin --- lib/build.gradle | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/build.gradle b/lib/build.gradle index 167f234a..83093fc1 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -13,7 +13,7 @@ plugins { id 'java' id 'jacoco' id 'checkstyle' - id 'me.champeau.gradle.japicmp' version '0.2.9' + id 'me.champeau.gradle.japicmp' version '0.4.1' } sourceSets { @@ -70,8 +70,8 @@ project.afterEvaluate { project.configure(project) { def baselineVersion = project.ext.baselineCompareVersion task('apiDiff', type: JapicmpTask, dependsOn: 'jar') { - oldClasspath = files(getBaselineJar(project, baselineVersion)) - newClasspath = files(jar.archiveFile) + oldClasspath.from(files(getBaselineJar(project, baselineVersion))) + newClasspath.from(files(jar.archiveFile)) onlyModified = true failOnModification = true ignoreMissingClasses = true @@ -122,6 +122,7 @@ javadoc { } dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.15.4' implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.4' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.70' From dcbc560d44903fb47012b291beebad60fe37da73 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Tue, 28 Jan 2025 10:58:19 +0530 Subject: [PATCH 131/134] added JAVA_HOME path --- .github/actions/maven-publish/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml index 0d280cbe..88fdaa1a 100644 --- a/.github/actions/maven-publish/action.yml +++ b/.github/actions/maven-publish/action.yml @@ -26,6 +26,8 @@ runs: source "/home/runner/.sdkman/bin/sdkman-init.sh" sdk list java sdk install java ${{ inputs.java-version }} && sdk default java ${{ inputs.java-version }} + export JAVA_HOME=${SDKMAN_DIR}/candidates/java/current + echo "JAVA_HOME is set to $JAVA_HOME" - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 From ca4f842509e7523b9a6e0f94b1f9b02e8509be93 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Tue, 28 Jan 2025 11:16:45 +0530 Subject: [PATCH 132/134] Release 4.5.0 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bb634fb..577ccf1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log +## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-28) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) + +**Added** +- Upgraded Plugin [\#711](https://github.com/auth0/java-jwt/pull/711) ([tanya732](https://github.com/tanya732)) +- Fix jackson vuln [\#705](https://github.com/auth0/java-jwt/pull/705) ([tanya732](https://github.com/tanya732)) +- Fix typo in example code [\#682](https://github.com/auth0/java-jwt/pull/682) ([kasperkarlsson](https://github.com/kasperkarlsson)) +- Remove dead README links [\#676](https://github.com/auth0/java-jwt/pull/676) ([jimmyjames](https://github.com/jimmyjames)) +- Fix typo on a comment in JWTCreator.java [\#672](https://github.com/auth0/java-jwt/pull/672) ([sgc109](https://github.com/sgc109)) +- Remove CircleCI [\#670](https://github.com/auth0/java-jwt/pull/670) ([jimmyjames](https://github.com/jimmyjames)) +- Empty string audience claim should be deserialized as empty string [\#663](https://github.com/auth0/java-jwt/pull/663) ([jimmyjames](https://github.com/jimmyjames)) + +**Fixed** +- empty expected audience array should throw InvalidClaimException [\#679](https://github.com/auth0/java-jwt/pull/679) ([jimmyjames](https://github.com/jimmyjames)) + ## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-22) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) From 05bc0027837cf85be597efbea51ce7b2104136d9 Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 29 Jan 2025 03:09:12 +0530 Subject: [PATCH 133/134] added JAVA_HOME --- .github/actions/maven-publish/action.yml | 3 +++ .github/workflows/java-release.yml | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/.github/actions/maven-publish/action.yml b/.github/actions/maven-publish/action.yml index 88fdaa1a..01e3a621 100644 --- a/.github/actions/maven-publish/action.yml +++ b/.github/actions/maven-publish/action.yml @@ -30,11 +30,14 @@ runs: echo "JAVA_HOME is set to $JAVA_HOME" - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # pin@1.1.0 + env: + JAVA_HOME: ${{ env.JAVA_HOME }} - name: Publish Android/Java Packages to Maven shell: bash run: ./gradlew publish -PisSnapshot=false --stacktrace env: + JAVA_HOME: ${{ env.JAVA_HOME }} MAVEN_USERNAME: ${{ inputs.ossr-username }} MAVEN_PASSWORD: ${{ inputs.ossr-token }} SIGNING_KEY: ${{ inputs.signing-key}} diff --git a/.github/workflows/java-release.yml b/.github/workflows/java-release.yml index ddce3e59..00771307 100644 --- a/.github/workflows/java-release.yml +++ b/.github/workflows/java-release.yml @@ -63,6 +63,12 @@ jobs: - if: steps.tag_exists.outputs.exists == 'true' run: exit 1 + # Set JAVA_HOME here and pass it to subsequent steps + - name: Set JAVA_HOME for Gradle + run: echo "JAVA_HOME=/home/runner/.sdkman/candidates/java/current" >> $GITHUB_ENV # This ensures JAVA_HOME is set globally + env: + SDKMAN_DIR: /home/runner/.sdkman + # Publish the release to Maven - uses: ./.github/actions/maven-publish with: @@ -71,6 +77,8 @@ jobs: ossr-token: ${{ secrets.ossr-token }} signing-key: ${{ secrets.signing-key }} signing-password: ${{ secrets.signing-password }} + env: + JAVA_HOME: ${{ env.JAVA_HOME }} # Create a release for the tag - uses: ./.github/actions/release-create From 051e1c3efba283c5dc6812f7bffb715995d4794c Mon Sep 17 00:00:00 2001 From: tanya732 Date: Wed, 29 Jan 2025 10:21:20 +0530 Subject: [PATCH 134/134] Release 4.5.0 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 577ccf1b..b97fab71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log +## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-29) +[Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0) + +**Added** +- Upgraded Plugin [\#711](https://github.com/auth0/java-jwt/pull/711) ([tanya732](https://github.com/tanya732)) +- Fix jackson vuln [\#705](https://github.com/auth0/java-jwt/pull/705) ([tanya732](https://github.com/tanya732)) +- Fix typo in example code [\#682](https://github.com/auth0/java-jwt/pull/682) ([kasperkarlsson](https://github.com/kasperkarlsson)) +- Remove dead README links [\#676](https://github.com/auth0/java-jwt/pull/676) ([jimmyjames](https://github.com/jimmyjames)) +- Fix typo on a comment in JWTCreator.java [\#672](https://github.com/auth0/java-jwt/pull/672) ([sgc109](https://github.com/sgc109)) +- Remove CircleCI [\#670](https://github.com/auth0/java-jwt/pull/670) ([jimmyjames](https://github.com/jimmyjames)) +- Empty string audience claim should be deserialized as empty string [\#663](https://github.com/auth0/java-jwt/pull/663) ([jimmyjames](https://github.com/jimmyjames)) + +**Fixed** +- empty expected audience array should throw InvalidClaimException [\#679](https://github.com/auth0/java-jwt/pull/679) ([jimmyjames](https://github.com/jimmyjames)) + ## [4.5.0](https://github.com/auth0/java-jwt/tree/4.5.0) (2025-01-28) [Full Changelog](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0)