From 83054a755d6533d2ac143ad066a9309a7d781bf7 Mon Sep 17 00:00:00 2001 From: Mitchell Morris Date: Tue, 23 Feb 2016 14:43:32 -0600 Subject: [PATCH] allow the injection of a time source --- src/main/java/io/jsonwebtoken/JwtParser.java | 9 +++++++++ .../jsonwebtoken/impl/DefaultJwtParser.java | 20 ++++++++++++------- .../io/jsonwebtoken/JwtParserTest.groovy | 11 ++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/jsonwebtoken/JwtParser.java b/src/main/java/io/jsonwebtoken/JwtParser.java index 11e8a5f6..1c06a093 100644 --- a/src/main/java/io/jsonwebtoken/JwtParser.java +++ b/src/main/java/io/jsonwebtoken/JwtParser.java @@ -124,6 +124,15 @@ public interface JwtParser { */ JwtParser require(String claimName, Object value); + /** + * Replaces the system time-of-day call to return this fixed value instead. A {@code null} value will remove + * the fixed date output and return the system time-of-day instead. + * + * @param now the time-of-day to use for parsimg this JWT or {@code null} to use the current time-of-day + * @return the builder instance for method chaining. + */ + JwtParser setFixedClock(Date now); + /** * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not * a JWS (no signature), this key is not used. diff --git a/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index a5d68aec..076440ac 100644 --- a/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -69,6 +69,8 @@ public class DefaultJwtParser implements JwtParser { Claims expectedClaims = new DefaultClaims(); + private Date now = new Date(); + @Override public JwtParser requireIssuedAt(Date issuedAt) { expectedClaims.setIssuedAt(issuedAt); @@ -127,6 +129,17 @@ public class DefaultJwtParser implements JwtParser { return this; } + @Override + public JwtParser setFixedClock(Date now) { + if (now == null) { + this.now = new Date(); + } else { + this.now = now; + } + + return this; + } + @Override public JwtParser setSigningKey(byte[] key) { Assert.notEmpty(key, "signing key cannot be null or empty."); @@ -346,7 +359,6 @@ public class DefaultJwtParser implements JwtParser { //since 0.3: if (claims != null) { - Date now = null; SimpleDateFormat sdf; //https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.4 @@ -354,8 +366,6 @@ public class DefaultJwtParser implements JwtParser { Date exp = claims.getExpiration(); if (exp != null) { - now = new Date(); - if (now.equals(exp) || now.after(exp)) { sdf = new SimpleDateFormat(ISO_8601_FORMAT); String expVal = sdf.format(exp); @@ -371,10 +381,6 @@ public class DefaultJwtParser implements JwtParser { Date nbf = claims.getNotBefore(); if (nbf != null) { - if (now == null) { - now = new Date(); - } - if (now.before(nbf)) { sdf = new SimpleDateFormat(ISO_8601_FORMAT); String nbfVal = sdf.format(nbf); diff --git a/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy b/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy index 3e37658f..1a93bda3 100644 --- a/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy +++ b/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy @@ -1392,4 +1392,15 @@ class JwtParserTest { ) } } + + @Test + void testParseClockManipulation() { + def then = System.currentTimeMillis() - 1000 + Date expiry = new Date(then) + Date beforeExpiry = new Date(then - 1000) + + String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() + + Jwts.parser().setFixedClock(beforeExpiry).parse(compact) + } }