From 2e452a42b10173ee0708eedacb845ba0b315c5d0 Mon Sep 17 00:00:00 2001 From: Micah Silverman Date: Wed, 23 Sep 2015 04:33:31 -0400 Subject: [PATCH] Added requireExpiration and requireNotBefore --- src/main/java/io/jsonwebtoken/JwtParser.java | 16 +++ .../jsonwebtoken/impl/DefaultJwtParser.java | 14 ++ .../io/jsonwebtoken/JwtParserTest.groovy | 136 ++++++++++++++++++ 3 files changed, 166 insertions(+) diff --git a/src/main/java/io/jsonwebtoken/JwtParser.java b/src/main/java/io/jsonwebtoken/JwtParser.java index 1ed015ff..828563ea 100644 --- a/src/main/java/io/jsonwebtoken/JwtParser.java +++ b/src/main/java/io/jsonwebtoken/JwtParser.java @@ -67,6 +67,22 @@ public interface JwtParser { */ JwtParser requireIssuedAt(Date issuedAt); + /** + * Sets an expected value for the expiration claim. + * + * @param expiration + * @return the parser for method chaining. + */ + JwtParser requireExpiration(Date expiration); + + /** + * Sets an expected value for the notBefore claim. + * + * @param notBefore + * @return the parser for method chaining + */ + JwtParser requireNotBefore(Date notBefore); + /** * 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 a52e7b54..37c5f5a0 100644 --- a/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -99,6 +99,20 @@ public class DefaultJwtParser implements JwtParser { return this; } + @Override + public JwtParser requireExpiration(Date expiration) { + expectedClaims.setExpiration(expiration); + + return this; + } + + @Override + public JwtParser requireNotBefore(Date notBefore) { + expectedClaims.setNotBefore(notBefore); + + return this; + } + @Override public JwtParser require(String claimName, Object value) { Assert.hasText(claimName, "claim name cannot be null or empty."); diff --git a/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy b/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy index 4fbd36ca..a65aa4dc 100644 --- a/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy +++ b/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy @@ -1191,4 +1191,140 @@ class JwtParserTest { ) } } + + @Test + void testParseRequireExpiration_Success() { + // expire in the future + def expiration = new Date(System.currentTimeMillis() + 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setExpiration(expiration). + compact() + + Jwt jwt = Jwts.parser().setSigningKey(key). + requireExpiration(expiration). + parseClaimsJws(compact) + + // system converts to seconds (lopping off millis precision), then returns millis + def expirationMillis = ((long)expiration.getTime() / 1000) * 1000 + + assertEquals jwt.getBody().getExpiration().getTime(), expirationMillis + } + + @Test + void testParseRequireExpirationAt_Incorrect_Fail() { + def goodExpiration = new Date(System.currentTimeMillis() + 20000) + def badExpiration = new Date(System.currentTimeMillis() + 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setExpiration(badExpiration). + compact() + + try { + Jwts.parser().setSigningKey(key). + requireExpiration(goodExpiration). + parseClaimsJws(compact) + fail() + } catch(IncorrectClaimException e) { + assertEquals( + String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.EXPIRATION, goodExpiration, badExpiration), + e.getMessage() + ) + } + } + + @Test + void testParseRequireExpiration_Missing_Fail() { + def expiration = new Date(System.currentTimeMillis() + 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setSubject("Dummy"). + compact() + + try { + Jwts.parser().setSigningKey(key). + requireExpiration(expiration). + parseClaimsJws(compact) + fail() + } catch(MissingClaimException e) { + assertEquals( + String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.EXPIRATION, expiration), + e.getMessage() + ) + } + } + + @Test + void testParseRequireNotBefore_Success() { + // expire in the future + def notBefore = new Date(System.currentTimeMillis() - 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setNotBefore(notBefore). + compact() + + Jwt jwt = Jwts.parser().setSigningKey(key). + requireNotBefore(notBefore). + parseClaimsJws(compact) + + // system converts to seconds (lopping off millis precision), then returns millis + def notBeforeMillis = ((long)notBefore.getTime() / 1000) * 1000 + + assertEquals jwt.getBody().getNotBefore().getTime(), notBeforeMillis + } + + @Test + void testParseRequireNotBefore_Incorrect_Fail() { + def goodNotBefore = new Date(System.currentTimeMillis() - 20000) + def badNotBefore = new Date(System.currentTimeMillis() - 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setNotBefore(badNotBefore). + compact() + + try { + Jwts.parser().setSigningKey(key). + requireNotBefore(goodNotBefore). + parseClaimsJws(compact) + fail() + } catch(IncorrectClaimException e) { + assertEquals( + String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.NOT_BEFORE, goodNotBefore, badNotBefore), + e.getMessage() + ) + } + } + + @Test + void testParseRequireNotBefore_Missing_Fail() { + def notBefore = new Date(System.currentTimeMillis() - 10000) + + byte[] key = randomKey() + + String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). + setSubject("Dummy"). + compact() + + try { + Jwts.parser().setSigningKey(key). + requireNotBefore(notBefore). + parseClaimsJws(compact) + fail() + } catch(MissingClaimException e) { + assertEquals( + String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.NOT_BEFORE, notBefore), + e.getMessage() + ) + } + } }