Merge branch 'MichaelSims-master' into 61-edits

This commit is contained in:
Les Hazlewood 2016-09-12 16:04:54 -07:00
commit a06e35cf84
3 changed files with 80 additions and 4 deletions

View File

@ -136,6 +136,16 @@ public interface JwtParser {
*/
JwtParser setClock(Clock clock);
/**
* Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp}
* and {@code nbf} claims.
*
* @param seconds
* @return the parser for method chaining.
* @since 0.7.0
*/
JwtParser setAllowedClockSkewInSeconds(int seconds);
/**
* 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.

View File

@ -57,6 +57,7 @@ public class DefaultJwtParser implements JwtParser {
//don't need millis since JWT date fields are only second granularity:
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final int MILLISECONDS_PER_SECOND = 1000;
private ObjectMapper objectMapper = new ObjectMapper();
@ -72,6 +73,8 @@ public class DefaultJwtParser implements JwtParser {
private Clock clock = DefaultClock.INSTANCE;
private int allowedClockSkewInSeconds = 0;
@Override
public JwtParser requireIssuedAt(Date issuedAt) {
expectedClaims.setIssuedAt(issuedAt);
@ -137,6 +140,12 @@ public class DefaultJwtParser implements JwtParser {
return this;
}
@Override
public JwtParser setAllowedClockSkewInSeconds(int seconds) {
allowedClockSkewInSeconds = seconds;
return this;
}
@Override
public JwtParser setSigningKey(byte[] key) {
Assert.notEmpty(key, "signing key cannot be null or empty.");
@ -357,6 +366,7 @@ public class DefaultJwtParser implements JwtParser {
//since 0.3:
if (claims != null) {
long allowedClockSkewInMilliseconds = (long) allowedClockSkewInSeconds * MILLISECONDS_PER_SECOND;
SimpleDateFormat sdf;
final Date now = this.clock.now();
@ -366,12 +376,14 @@ public class DefaultJwtParser implements JwtParser {
Date exp = claims.getExpiration();
if (exp != null) {
if (now.equals(exp) || now.after(exp)) {
Date nowWithAllowedClockSkew = new Date(now.getTime() - allowedClockSkewInMilliseconds);
if (nowWithAllowedClockSkew.equals(exp) || nowWithAllowedClockSkew.after(exp)) {
sdf = new SimpleDateFormat(ISO_8601_FORMAT);
String expVal = sdf.format(exp);
String nowVal = sdf.format(now);
String msg = "JWT expired at " + expVal + ". Current time: " + nowVal;
String msg = "JWT expired at " + expVal + ". Current time: " + nowVal +
". Allowed clock skew: " + allowedClockSkewInSeconds + " second(s).";
throw new ExpiredJwtException(header, claims, msg);
}
}
@ -381,12 +393,14 @@ public class DefaultJwtParser implements JwtParser {
Date nbf = claims.getNotBefore();
if (nbf != null) {
if (now.before(nbf)) {
Date nowWithAllowedClockSkew = new Date(now.getTime() + allowedClockSkewInMilliseconds);
if (nowWithAllowedClockSkew.before(nbf)) {
sdf = new SimpleDateFormat(ISO_8601_FORMAT);
String nbfVal = sdf.format(nbf);
String nowVal = sdf.format(now);
String msg = "JWT must not be accepted before " + nbfVal + ". Current time: " + nowVal;
String msg = "JWT must not be accepted before " + nbfVal + ". Current time: " + nowVal +
". Allowed clock skew: " + allowedClockSkewInSeconds + " second(s).";
throw new PrematureJwtException(header, claims, msg);
}
}

View File

@ -199,6 +199,58 @@ class JwtParserTest {
}
}
@Test
void testParseWithExpiredJwtWithinAllowedClockSkew() {
Date exp = new Date(System.currentTimeMillis() - 3000)
String subject = 'Joe'
String compact = Jwts.builder().setSubject(subject).setExpiration(exp).compact()
Jwt<Header,Claims> jwt = Jwts.parser().setAllowedClockSkewInSeconds(10).parse(compact)
assertEquals jwt.getBody().getSubject(), subject
}
@Test
void testParseWithExpiredJwtNotWithinAllowedClockSkew() {
Date exp = new Date(System.currentTimeMillis() - 3000)
String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact()
try {
Jwts.parser().setAllowedClockSkewInSeconds(1).parse(compact)
fail()
} catch (ExpiredJwtException e) {
assertTrue e.getMessage().startsWith('JWT expired at ')
}
}
@Test
void testParseWithPrematureJwtWithinAllowedClockSkew() {
Date exp = new Date(System.currentTimeMillis() + 3000)
String subject = 'Joe'
String compact = Jwts.builder().setSubject(subject).setNotBefore(exp).compact()
Jwt<Header,Claims> jwt = Jwts.parser().setAllowedClockSkewInSeconds(10).parse(compact)
assertEquals jwt.getBody().getSubject(), subject
}
@Test
void testParseWithPrematureJwtNotWithinAllowedClockSkew() {
Date exp = new Date(System.currentTimeMillis() + 3000)
String compact = Jwts.builder().setSubject('Joe').setNotBefore(exp).compact()
try {
Jwts.parser().setAllowedClockSkewInSeconds(1).parse(compact)
fail()
} catch (PrematureJwtException e) {
assertTrue e.getMessage().startsWith('JWT must not be accepted before ')
}
}
// ========================================================================
// parsePlaintextJwt tests
// ========================================================================