From db339704e5bb4662c0e25a3f3a2abe2d155189e1 Mon Sep 17 00:00:00 2001
From: lhazlewood <121180+lhazlewood@users.noreply.github.com>
Date: Sat, 14 Oct 2023 16:59:35 -0700
Subject: [PATCH] Custom empty claims
Closes #858.
Custom claims can now be empty again (which was the behavior for <= 0.11.5).
---
.../java/io/jsonwebtoken/lang/Objects.java | 4 +-
.../io/jsonwebtoken/impl/ParameterMap.java | 16 ++-----
.../impl/DefaultJwtBuilderTest.groovy | 7 ----
.../jsonwebtoken/issues/Issue858Test.groovy | 42 +++++++++++++++++++
4 files changed, 48 insertions(+), 21 deletions(-)
create mode 100644 impl/src/test/groovy/io/jsonwebtoken/issues/Issue858Test.groovy
diff --git a/api/src/main/java/io/jsonwebtoken/lang/Objects.java b/api/src/main/java/io/jsonwebtoken/lang/Objects.java
index 12a92dfd7..4284713ce 100644
--- a/api/src/main/java/io/jsonwebtoken/lang/Objects.java
+++ b/api/src/main/java/io/jsonwebtoken/lang/Objects.java
@@ -94,7 +94,7 @@ public static boolean isArray(Object obj) {
* Returns {@code true} if the specified argument:
*
* - is {@code null}, or
- * - is a String and {@link Strings#hasText(String)} is {@code false}, or
+ * - is a CharSequence and {@link Strings#hasText(CharSequence)} is {@code false}, or
* - is a Collection or Map with zero size, or
* - is an empty array
*
@@ -106,7 +106,7 @@ public static boolean isArray(Object obj) {
*/
public static boolean isEmpty(Object v) {
return v == null ||
- (v instanceof String && !Strings.hasText((String) v)) ||
+ (v instanceof CharSequence && !Strings.hasText((CharSequence) v)) ||
(v instanceof Collection && Collections.isEmpty((Collection>) v)) ||
(v instanceof Map && Collections.isEmpty((Map, ?>) v)) ||
(v.getClass().isArray() && Array.getLength(v) == 0);
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/ParameterMap.java b/impl/src/main/java/io/jsonwebtoken/impl/ParameterMap.java
index 2daf1b701..c8e462ec0 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/ParameterMap.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/ParameterMap.java
@@ -124,13 +124,6 @@ public Object get(Object o) {
return values.get(o);
}
- private static Object clean(Object o) {
- if (o instanceof String) {
- o = Strings.clean((String) o);
- }
- return o;
- }
-
/**
* Convenience method to put a value for an idiomatic param.
*
@@ -143,7 +136,7 @@ protected final Object put(Parameter param, Object value) {
assertMutable();
Assert.notNull(param, "Parameter cannot be null.");
Assert.hasText(param.getId(), "Parameter id cannot be null or empty.");
- return apply(param, clean(value));
+ return apply(param, value);
}
@Override
@@ -156,12 +149,12 @@ public final Object put(String name, Object value) {
return put(param, value);
} else {
// non-standard or custom property, just apply directly:
- return nullSafePut(name, clean(value));
+ return nullSafePut(name, value);
}
}
private Object nullSafePut(String name, Object value) {
- if (Objects.isEmpty(value)) {
+ if (value == null) {
return remove(name);
} else {
this.idiomaticValues.put(name, value);
@@ -199,9 +192,8 @@ private Object apply(Parameter param, Object rawValue) {
String msg = sb.toString();
throw new IllegalArgumentException(msg, e);
}
- Object retval = nullSafePut(id, canonicalValue);
this.idiomaticValues.put(id, idiomaticValue);
- return retval;
+ return this.values.put(id, canonicalValue);
}
@Override
diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy
index bfeebeb15..3d0dfa949 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy
+++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy
@@ -219,13 +219,6 @@ class DefaultJwtBuilderTest {
assertEquals b.claimsBuilder.foo, 'bar'
}
- @Test
- void testClaimEmptyString() {
- String value = ' '
- builder.claim('foo', value)
- assertTrue builder.claimsBuilder.isEmpty() // shouldn't populate claims instance
- }
-
@Test
void testExistingClaimsAndSetClaim() {
Claims c = Jwts.claims().add('foo', 'bar').build()
diff --git a/impl/src/test/groovy/io/jsonwebtoken/issues/Issue858Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/issues/Issue858Test.groovy
new file mode 100644
index 000000000..a470c10f0
--- /dev/null
+++ b/impl/src/test/groovy/io/jsonwebtoken/issues/Issue858Test.groovy
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2023 jsonwebtoken.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.jsonwebtoken.issues
+
+import io.jsonwebtoken.Jwts
+import org.junit.Test
+
+import static org.junit.Assert.assertEquals
+
+class Issue858Test {
+
+ @Test
+ void testEmptyAndNullEntries() {
+ def jwt = Jwts.builder()
+ .subject('Joe')
+ .claim('foo', '') // empty allowed
+ .claim('list', []) // empty allowed
+ .claim('map', [:]) // empty map allowed
+ .claim('another', null) // null not allowed (same behavior since <= 0.11.5), won't be added
+ .compact()
+
+ def claims = Jwts.parser().unsecured().build().parseUnsecuredClaims(jwt).getPayload()
+ assertEquals 4, claims.size()
+ assertEquals 'Joe', claims.getSubject()
+ assertEquals '', claims.get('foo')
+ assertEquals([], claims.get('list'))
+ assertEquals([:], claims.get('map'))
+ }
+}