From 0fab5504cdf6f179b5ab3f450afec7c5aa644eec Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Sat, 12 Sep 2015 02:53:57 -0400 Subject: [PATCH] Added expectIssuedAt convenience method. --- src/main/java/io/jsonwebtoken/JwtParser.java | 9 +++ .../jsonwebtoken/impl/DefaultJwtParser.java | 24 +++++- .../io/jsonwebtoken/JwtParserTest.groovy | 73 ++++++++++++++++++- 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/jsonwebtoken/JwtParser.java b/src/main/java/io/jsonwebtoken/JwtParser.java index c26da433..fbf2a81f 100644 --- a/src/main/java/io/jsonwebtoken/JwtParser.java +++ b/src/main/java/io/jsonwebtoken/JwtParser.java @@ -16,6 +16,7 @@ package io.jsonwebtoken; import java.security.Key; +import java.util.Date; /** * A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT. @@ -26,6 +27,14 @@ public interface JwtParser { public static final char SEPARATOR_CHAR = '.'; + /** + * Sets an expected value for the issuedAt claim. + * + * @param issuedAt + * @return the parser for method chaining. + */ + JwtParser expectIssuedAt(Date issuedAt); + /** * Sets an expected value for any given claim name. * diff --git a/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index 36142292..26f17f0e 100644 --- a/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -46,7 +46,6 @@ import java.io.IOException; import java.security.Key; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.LinkedHashMap; import java.util.Map; @SuppressWarnings("unchecked") @@ -63,7 +62,16 @@ public class DefaultJwtParser implements JwtParser { private SigningKeyResolver signingKeyResolver; - Map expectedClaims = new LinkedHashMap(); + Claims expectedClaims = new DefaultClaims(); + + @Override + public JwtParser expectIssuedAt(Date issuedAt) { + if (issuedAt != null) { + expectedClaims.setIssuedAt(issuedAt); + } + + return this; + } @Override public JwtParser expect(String claimName, Object value) { @@ -329,8 +337,16 @@ public class DefaultJwtParser implements JwtParser { private void validateExpectedClaims(Header header, Claims claims) { for (String expectedClaimName : expectedClaims.keySet()) { - Object expectedClaimValue = expectedClaims.get(expectedClaimName); - Object actualClaimValue = claims.get(expectedClaimName); + Object expectedClaimValue = null; + Object actualClaimValue = null; + if (Claims.ISSUED_AT.equals(expectedClaimName)) { + expectedClaimValue = expectedClaims.getIssuedAt(); + actualClaimValue = claims.getIssuedAt(); + } else { + expectedClaimValue = expectedClaims.get(expectedClaimName); + actualClaimValue = claims.get(expectedClaimName); + } + InvalidClaimException invalidClaimException = null; if (actualClaimValue == null) { diff --git a/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy b/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy index 40c4986c..c5726dab 100644 --- a/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy +++ b/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy @@ -22,6 +22,8 @@ import javax.crypto.spec.SecretKeySpec import java.security.SecureRandom import static org.junit.Assert.* +import static ClaimJwtException.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE +import static ClaimJwtException.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE class JwtParserTest { @@ -819,7 +821,7 @@ class JwtParserTest { fail() } catch (IncorrectClaimException e) { assertEquals( - String.format(ClaimJwtException.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, goodClaimName, goodClaimValue, badClaimValue), + String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, goodClaimName, goodClaimValue, badClaimValue), e.getMessage() ) } @@ -843,7 +845,74 @@ class JwtParserTest { fail() } catch (MissingClaimException e) { assertEquals( - String.format(ClaimJwtException.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, claimName, claimValue), + String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, claimName, claimValue), + e.getMessage() + ) + } + } + + @Test + void testParseExpectIssuedAt_Success() { + def issuedAt = new Date(System.currentTimeMillis()) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setIssuedAt(issuedAt). + compact() + + Jwt jwt = Jwts.parser().setSigningKey(key). + expectIssuedAt(issuedAt). + parseClaimsJws(compact) + + // system converts to seconds (lopping off millis precision), then returns millis + def issuedAtMillis = ((long)issuedAt.getTime() / 1000) * 1000 + + assertEquals jwt.getBody().getIssuedAt().getTime(), issuedAtMillis + } + + @Test + void testParseExpectIssuedAt_Incorrect_Fail() { + def goodIssuedAt = new Date(System.currentTimeMillis()) + def badIssuedAt = new Date(System.currentTimeMillis() - 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setIssuedAt(badIssuedAt). + compact() + + try { + Jwts.parser().setSigningKey(key). + expectIssuedAt(goodIssuedAt). + parseClaimsJws(compact) + fail() + } catch(IncorrectClaimException e) { + assertEquals( + String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUED_AT, goodIssuedAt, badIssuedAt), + e.getMessage() + ) + } + } + + @Test + void testParseExpectIssuedAt_Missing_Fail() { + def issuedAt = new Date(System.currentTimeMillis() - 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setSubject("Dummy"). + compact() + + try { + Jwts.parser().setSigningKey(key). + expectIssuedAt(issuedAt). + parseClaimsJws(compact) + fail() + } catch(MissingClaimException e) { + assertEquals( + String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUED_AT, issuedAt), e.getMessage() ) }