From 78a10b3fb3c2cd9ec831f54c75810c22282ed052 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sat, 26 Nov 2022 16:05:43 +0000 Subject: [PATCH 1/9] Add support for passing json values for header and payload --- .../main/java/com/auth0/jwt/JWTCreator.java | 40 ++++++++++++ .../java/com/auth0/jwt/JWTCreatorTest.java | 62 ++++++++++++++++--- 2 files changed, 94 insertions(+), 8 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index a99f0fa0..8f87ad42 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -95,6 +95,23 @@ 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. + */ + public Builder withHeader(String headerClaimsJson) throws JsonProcessingException { + if (headerClaimsJson == null) { + return this; + } + + Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); + + return withHeader(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, @@ -464,6 +481,29 @@ 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. + */ + public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException, JsonProcessingException { + if (payloadClaimsJson == null) { + return this; + } + + Map payloadClaims = mapper.readValue(payloadClaimsJson, HashMap.class); + + return withPayload(payloadClaims); + } + 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 020e5e37..70e1be31 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; @@ -16,9 +17,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; @@ -83,16 +82,39 @@ public void shouldAddHeaderClaim() { } @Test - public void shouldReturnBuilderIfNullMapIsProvided() { + public void shouldReturnBuilderIfNullMapIsProvided() throws JsonProcessingException { + 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 shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { + public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws JsonProcessingException { + 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 shouldSupportJsonValueHeaderWithNestedDataStructure() { Map header = new HashMap<>(); header.put(HeaderParams.KEY_ID, "xyz"); @@ -107,6 +129,7 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { assertThat(headerJson, JsonMatcher.hasEntry(HeaderParams.KEY_ID, "xyz")); } + @Test public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { Map header = new HashMap<>(); @@ -716,9 +739,12 @@ public void withPayloadShouldAddBasicClaim() { } @Test - public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() { + public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() throws JsonProcessingException { + Map nullMap = null; + String nullString = null; String jwt = JWTCreator.init() - .withPayload(null) + .withPayload(nullMap) + .withPayload(nullString) .sign(Algorithm.HMAC256("secret")); assertThat(jwt, is(notNullValue())); @@ -923,10 +949,30 @@ public void withPayloadShouldSupportNullValuesEverywhere() { assertThat(headerJson, JsonMatcher.hasEntry("objClaim", objClaim)); } + @Test + public void withPayloadShouldSupportJsonValueWithNestedDataStructure() throws JsonProcessingException { + 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 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 186df4df96631d575163d10f56f4eec0c72447a3 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sat, 26 Nov 2022 16:12:43 +0000 Subject: [PATCH 2/9] rename functions --- lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 70e1be31..38c47137 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -94,7 +94,7 @@ public void shouldReturnBuilderIfNullMapIsProvided() throws JsonProcessingExcept } @Test - public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws JsonProcessingException { + public void shouldSupportJsonValueHeaderWithNestedDataStructure() throws JsonProcessingException { String stringClaim = "someClaim"; Integer intClaim = 1; List nestedListClaims = Arrays.asList("1", "2"); @@ -114,7 +114,7 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws } @Test - public void shouldSupportJsonValueHeaderWithNestedDataStructure() { + public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { Map header = new HashMap<>(); header.put(HeaderParams.KEY_ID, "xyz"); From a95382daeec4cea9ce8c428c5115068cc7cf0669 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sat, 26 Nov 2022 16:13:12 +0000 Subject: [PATCH 3/9] remove extra space --- lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 38c47137..61537558 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -972,7 +972,7 @@ public void withPayloadShouldSupportJsonValueWithNestedDataStructure() throws Js @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 d171fbceb6dd0b2a4bf3ea0e6e60818107ff7081 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sat, 26 Nov 2022 17:21:28 +0000 Subject: [PATCH 4/9] formated --- lib/src/main/java/com/auth0/jwt/JWTCreator.java | 4 ++-- 1 file changed, 2 insertions(+), 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 8f87ad42..d545c8da 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -107,7 +107,7 @@ public Builder withHeader(String headerClaimsJson) throws JsonProcessingExceptio return this; } - Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); + Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); return withHeader(headerClaims); } @@ -499,7 +499,7 @@ public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentExcep return this; } - Map payloadClaims = mapper.readValue(payloadClaimsJson, HashMap.class); + Map payloadClaims = mapper.readValue(payloadClaimsJson, HashMap.class); return withPayload(payloadClaims); } From 3a531a301b3779118d93f9a2ab44755ace02b293 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sat, 10 Dec 2022 01:40:05 +0000 Subject: [PATCH 5/9] add documentation --- lib/build.gradle | 2 +- lib/src/main/java/com/auth0/jwt/JWTCreator.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/build.gradle b/lib/build.gradle index d6c9b061..2c7f016c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -65,7 +65,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 d545c8da..ed74bab4 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -100,6 +100,7 @@ public Builder withHeader(Map headerClaims) { * If provided json is null then nothing is changed * * @param headerClaimsJson the values to use as Claims in the token's Header. + * @throws JsonProcessingException if json value has invalid structure * @return this same Builder instance. */ public Builder withHeader(String headerClaimsJson) throws JsonProcessingException { @@ -493,6 +494,7 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE * @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. + * @throws JsonProcessingException if json value has invalid structure */ public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException, JsonProcessingException { if (payloadClaimsJson == null) { From 8c3f5c78f14f2285134b28eb642d0e255dfb6bda Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sat, 10 Dec 2022 01:40:35 +0000 Subject: [PATCH 6/9] remove extra space --- lib/src/main/java/com/auth0/jwt/JWTCreator.java | 4 ++-- 1 file changed, 2 insertions(+), 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 ed74bab4..2deff94d 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -100,7 +100,7 @@ public Builder withHeader(Map headerClaims) { * If provided json is null then nothing is changed * * @param headerClaimsJson the values to use as Claims in the token's Header. - * @throws JsonProcessingException if json value has invalid structure + * @throws JsonProcessingException if json value has invalid structure * @return this same Builder instance. */ public Builder withHeader(String headerClaimsJson) throws JsonProcessingException { @@ -494,7 +494,7 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE * @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. - * @throws JsonProcessingException if json value has invalid structure + * @throws JsonProcessingException if json value has invalid structure */ public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException, JsonProcessingException { if (payloadClaimsJson == null) { From dbc90eb80e9271ff69a2837fd4e78fa62b87924f Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Tue, 14 Mar 2023 20:48:08 +0200 Subject: [PATCH 7/9] reorder params --- 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 5a4cfcec..c8b00c3b 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -103,8 +103,8 @@ public Builder withHeader(Map headerClaims) { * If provided json is null then nothing is changed * * @param headerClaimsJson the values to use as Claims in the token's Header. - * @throws JsonProcessingException if json value has invalid structure * @return this same Builder instance. + * @throws JsonProcessingException if json value has invalid structure */ public Builder withHeader(String headerClaimsJson) throws JsonProcessingException { if (headerClaimsJson == null) { From f1dcc62047b65fa8717f4a22b5b8f8b63b8c9ae9 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Wed, 15 Mar 2023 22:14:04 +0200 Subject: [PATCH 8/9] resolve comments --- .../main/java/com/auth0/jwt/JWTCreator.java | 28 +++++++++++-------- .../java/com/auth0/jwt/JWTCreatorTest.java | 8 +++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index c8b00c3b..f554cbc3 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -104,16 +104,19 @@ public Builder withHeader(Map headerClaims) { * * @param headerClaimsJson the values to use as Claims in the token's Header. * @return this same Builder instance. - * @throws JsonProcessingException if json value has invalid structure + * @throws IllegalArgumentException if json value has invalid structure */ - public Builder withHeader(String headerClaimsJson) throws JsonProcessingException { + public Builder withHeader(String headerClaimsJson) throws IllegalArgumentException { if (headerClaimsJson == null) { return this; } - Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); - - return withHeader(headerClaims); + try { + Map headerClaims = mapper.readValue(headerClaimsJson, HashMap.class); + return withHeader(headerClaims); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Invalid header JSON", e); + } } /** @@ -496,17 +499,20 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE * @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. - * @throws JsonProcessingException if json value has invalid structure + * or if the values are not of a supported type, + * or if json value has invalid structure. */ - public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException, JsonProcessingException { + public Builder withPayload(String payloadClaimsJson) throws IllegalArgumentException { if (payloadClaimsJson == null) { return this; } - Map payloadClaims = mapper.readValue(payloadClaimsJson, HashMap.class); - - return withPayload(payloadClaims); + 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) { diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 61537558..0b895cea 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -82,7 +82,7 @@ public void shouldAddHeaderClaim() { } @Test - public void shouldReturnBuilderIfNullMapIsProvided() throws JsonProcessingException { + public void shouldReturnBuilderIfNullMapIsProvided() { Map nullMap = null; String nullString = null; String signed = JWTCreator.init() @@ -94,7 +94,7 @@ public void shouldReturnBuilderIfNullMapIsProvided() throws JsonProcessingExcept } @Test - public void shouldSupportJsonValueHeaderWithNestedDataStructure() throws JsonProcessingException { + public void shouldSupportJsonValueHeaderWithNestedDataStructure() { String stringClaim = "someClaim"; Integer intClaim = 1; List nestedListClaims = Arrays.asList("1", "2"); @@ -739,7 +739,7 @@ public void withPayloadShouldAddBasicClaim() { } @Test - public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() throws JsonProcessingException { + public void withPayloadShouldCreateJwtWithEmptyBodyIfPayloadNull() { Map nullMap = null; String nullString = null; String jwt = JWTCreator.init() @@ -950,7 +950,7 @@ public void withPayloadShouldSupportNullValuesEverywhere() { } @Test - public void withPayloadShouldSupportJsonValueWithNestedDataStructure() throws JsonProcessingException { + public void withPayloadShouldSupportJsonValueWithNestedDataStructure() { String stringClaim = "someClaim"; Integer intClaim = 1; List nestedListClaims = Arrays.asList("1", "2"); From 6233867d542655650141675ed976ff411d92ae18 Mon Sep 17 00:00:00 2001 From: Andreas Rigas Date: Sun, 19 Mar 2023 21:38:30 +0200 Subject: [PATCH 9/9] update tests to include error case --- .../java/com/auth0/jwt/JWTCreatorTest.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index 0b895cea..e4ab8cb0 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -113,6 +113,18 @@ public void shouldSupportJsonValueHeaderWithNestedDataStructure() { 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<>(); @@ -969,10 +981,22 @@ public void withPayloadShouldSupportJsonValueWithNestedDataStructure() { 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());