This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/4.1.x-fixes by this push:
new f2967eb72d1 Handle NaN or infinite times in JSON/JWT (#3137)
f2967eb72d1 is described below
commit f2967eb72d19e454149477b81ec7c0adb9b330dc
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon May 25 09:36:47 2026 +0100
Handle NaN or infinite times in JSON/JWT (#3137)
(cherry picked from commit 942a663f30b677a644ce9e9dd7aa217e76cf50a0)
---
.../json/basic/JsonMapObjectReaderWriter.java | 6 +++-
.../json/basic/JsonMapObjectReaderWriterTest.java | 22 ++++++++++++
.../apache/cxf/rs/security/jose/jwt/JwtUtils.java | 37 +++++++++++++++-----
.../cxf/rs/security/jose/jwt/JwtUtilsTest.java | 40 ++++++++++++++++++++++
4 files changed, 95 insertions(+), 10 deletions(-)
diff --git
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
index 88445b17e68..a99e7c43e73 100644
---
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
+++
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
@@ -258,7 +258,11 @@ public class JsonMapObjectReaderWriter {
try {
value = Long.valueOf(valueStr);
} catch (NumberFormatException ex) {
- value = Double.valueOf(valueStr);
+ Double doubleValue = Double.valueOf(valueStr);
+ if (doubleValue.isInfinite() || doubleValue.isNaN()) {
+ throw new NumberFormatException("Non-finite numeric value
is not allowed");
+ }
+ value = doubleValue;
}
}
diff --git
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
index 424eb72c5dd..9c66add08c1 100644
---
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
+++
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
@@ -33,6 +33,7 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
public class JsonMapObjectReaderWriterTest {
@@ -210,4 +211,25 @@ public class JsonMapObjectReaderWriterTest {
assertEquals("a\\", entry.getValue());
}
+ @Test
+ public void testRejectInfinityNumericValue() {
+ assertInvalidNumericLiteral("Infinity");
+ assertInvalidNumericLiteral("-Infinity");
+ }
+
+ @Test
+ public void testRejectNaNNumericValue() {
+ assertInvalidNumericLiteral("NaN");
+ }
+
+ private void assertInvalidNumericLiteral(String value) {
+ JsonMapObjectReaderWriter jsonMapObjectReaderWriter = new
JsonMapObjectReaderWriter();
+ try {
+ jsonMapObjectReaderWriter.fromJson("{\"exp\":" + value + "}");
+ fail("Expected NumberFormatException for invalid numeric value: "
+ value);
+ } catch (NumberFormatException ex) {
+ // expected
+ }
+ }
+
}
diff --git
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtUtils.java
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtUtils.java
index 31653190db8..10b08220a93 100644
---
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtUtils.java
+++
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtUtils.java
@@ -50,9 +50,14 @@ public final class JwtUtils {
return;
}
Instant now = Instant.now();
- Instant expires = Instant.ofEpochMilli(expiryTime * 1000L);
- if (clockOffset != 0) {
- expires = expires.plusSeconds(clockOffset);
+ Instant expires;
+ try {
+ expires = Instant.ofEpochSecond(expiryTime);
+ if (clockOffset != 0) {
+ expires = expires.plusSeconds(clockOffset);
+ }
+ } catch (RuntimeException ex) {
+ throw new JwtException("The token has expired", ex);
}
if (expires.isBefore(now)) {
throw new JwtException("The token has expired");
@@ -69,10 +74,15 @@ public final class JwtUtils {
}
Instant validCreation = Instant.now();
- if (clockOffset != 0) {
- validCreation = validCreation.plusSeconds(clockOffset);
+ Instant notBeforeDate;
+ try {
+ if (clockOffset != 0) {
+ validCreation = validCreation.plusSeconds(clockOffset);
+ }
+ notBeforeDate = Instant.ofEpochSecond(notBeforeTime);
+ } catch (RuntimeException ex) {
+ throw new JwtException("The token cannot be accepted yet", ex);
}
- Instant notBeforeDate = Instant.ofEpochMilli(notBeforeTime * 1000L);
// Check to see if the not before time is in the future
if (notBeforeDate.isAfter(validCreation)) {
@@ -89,11 +99,20 @@ public final class JwtUtils {
return;
}
- Instant createdDate = Instant.ofEpochMilli(issuedAtInSecs * 1000L);
+ Instant createdDate;
+ try {
+ createdDate = Instant.ofEpochSecond(issuedAtInSecs);
+ } catch (RuntimeException ex) {
+ throw new JwtException("Invalid issuedAt", ex);
+ }
Instant validCreation = Instant.now();
- if (clockOffset != 0) {
- validCreation = validCreation.plusSeconds(clockOffset);
+ try {
+ if (clockOffset != 0) {
+ validCreation = validCreation.plusSeconds(clockOffset);
+ }
+ } catch (RuntimeException ex) {
+ throw new JwtException("Invalid issuedAt", ex);
}
// Check to see if the IssuedAt time is in the future
diff --git
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwt/JwtUtilsTest.java
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwt/JwtUtilsTest.java
index e53a47060c8..af58d2d0e7c 100644
---
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwt/JwtUtilsTest.java
+++
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwt/JwtUtilsTest.java
@@ -174,4 +174,44 @@ public class JwtUtilsTest {
}
}
+ @org.junit.Test
+ public void testInfiniteExpiryTokenRejected() {
+ try {
+ String claimsJson =
"{\"sub\":\"alice\",\"iss\":\"DoubleItSTSIssuer\","
+ + "\"exp\":Infinity}";
+ JwtClaims claims = JwtUtils.jsonToClaims(claimsJson);
+ JwtUtils.validateJwtExpiry(claims, 0, true);
+ fail("Failure expected on a token with infinite expiry");
+ } catch (JwtException | NumberFormatException ex) {
+ // expected
+ }
+ }
+
+ @org.junit.Test
+ public void testInfiniteNotBeforeTokenRejected() {
+ try {
+ String claimsJson =
"{\"sub\":\"alice\",\"iss\":\"DoubleItSTSIssuer\","
+ + "\"nbf\":Infinity}";
+ JwtClaims claims = JwtUtils.jsonToClaims(claimsJson);
+ JwtUtils.validateJwtNotBefore(claims, 0, true);
+ fail("Failure expected on a token with infinite not before");
+ } catch (JwtException | NumberFormatException ex) {
+ // expected
+ }
+ }
+
+ @org.junit.Test
+ public void testInfiniteIssuedAtTokenRejected() {
+ try {
+ String claimsJson =
"{\"sub\":\"alice\",\"iss\":\"DoubleItSTSIssuer\","
+ + "\"iat\":Infinity}";
+ JwtClaims claims = JwtUtils.jsonToClaims(claimsJson);
+ JwtUtils.validateJwtIssuedAt(claims, 0, 0, true);
+ fail("Failure expected on a token with infinite issued at");
+ } catch (JwtException | NumberFormatException ex) {
+ // expected
+ }
+ }
+
+
}