You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2026/05/22 14:31:34 UTC
(cxf) 01/01: Handle NaN or infinite times in JSON/JWT
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch coheigea/json-nan
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit d4ee0a41964437e3621284cdedb2563046d7f6c5
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Fri May 22 15:31:07 2026 +0100
Handle NaN or infinite times in JSON/JWT
---
.../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
+ }
+ }
+
+
}