mirror of https://github.com/jwtk/jjwt.git
Issue #6: Fixed tests to not reference static (stale) expiration dates
This commit is contained in:
parent
076fa3074c
commit
35a42826ea
|
@ -16,7 +16,7 @@
|
|||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception indicating that a JWT was referenced after it expired and should be rejected.
|
||||
* Exception indicating that a JWT was accepted after it expired and must be rejected.
|
||||
*
|
||||
* @since 0.3
|
||||
*/
|
||||
|
|
|
@ -20,8 +20,8 @@ import io.jsonwebtoken.Claims;
|
|||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.JwtHandler;
|
||||
import io.jsonwebtoken.JwtHandlerAdapter;
|
||||
import io.jsonwebtoken.JwtParser;
|
||||
|
@ -45,6 +45,9 @@ import java.util.Map;
|
|||
@SuppressWarnings("unchecked")
|
||||
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:ssZ";
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private byte[] keyBytes;
|
||||
|
@ -167,16 +170,18 @@ public class DefaultJwtParser implements JwtParser {
|
|||
//since 0.3:
|
||||
if (claims != null) {
|
||||
|
||||
Date exp = claims.getExpiration();
|
||||
Date now = null;
|
||||
SimpleDateFormat sdf;
|
||||
|
||||
//https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.4
|
||||
//token MUST NOT be accepted on or after any specified exp time:
|
||||
Date exp = claims.getExpiration();
|
||||
if (exp != null) {
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
if (now.after(exp)) {
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); //don't need millis since JWT exp field only has second granularity
|
||||
now = new Date();
|
||||
|
||||
if (now.equals(exp) || now.after(exp)) {
|
||||
sdf = new SimpleDateFormat(ISO_8601_FORMAT);
|
||||
String expVal = sdf.format(exp);
|
||||
String nowVal = sdf.format(now);
|
||||
|
||||
|
@ -184,12 +189,33 @@ public class DefaultJwtParser implements JwtParser {
|
|||
throw new ExpiredJwtException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4.1.5
|
||||
//token MUST NOT be accepted before any specified nbf time:
|
||||
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);
|
||||
String nowVal = sdf.format(now);
|
||||
|
||||
String msg = "JWT must not be accepted before " + nbfVal + ". Current time: " + nowVal;
|
||||
throw new PrematureJwtException(msg);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// =============== Signature =================
|
||||
if (base64UrlEncodedDigest != null) { //it is signed - validate the signature
|
||||
|
||||
JwsHeader jwsHeader = (JwsHeader)header;
|
||||
JwsHeader jwsHeader = (JwsHeader) header;
|
||||
|
||||
SignatureAlgorithm algorithm = null;
|
||||
|
||||
|
@ -218,7 +244,8 @@ public class DefaultJwtParser implements JwtParser {
|
|||
|
||||
if (!Objects.isEmpty(this.keyBytes)) {
|
||||
|
||||
Assert.isTrue(!algorithm.isRsa(), "Key bytes cannot be specified for RSA signatures. Please specify a PublicKey or PrivateKey instance.");
|
||||
Assert.isTrue(!algorithm.isRsa(),
|
||||
"Key bytes cannot be specified for RSA signatures. Please specify a PublicKey or PrivateKey instance.");
|
||||
|
||||
key = new SecretKeySpec(keyBytes, algorithm.getJcaName());
|
||||
}
|
||||
|
@ -241,26 +268,27 @@ public class DefaultJwtParser implements JwtParser {
|
|||
Object body = claims != null ? claims : payload;
|
||||
|
||||
if (base64UrlEncodedDigest != null) {
|
||||
return new DefaultJws<Object>((JwsHeader)header, body, base64UrlEncodedDigest);
|
||||
return new DefaultJws<Object>((JwsHeader) header, body, base64UrlEncodedDigest);
|
||||
} else {
|
||||
return new DefaultJwt<Object>(header, body);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T parse(String compact, JwtHandler<T> handler) throws ExpiredJwtException, MalformedJwtException, SignatureException {
|
||||
public <T> T parse(String compact, JwtHandler<T> handler)
|
||||
throws ExpiredJwtException, MalformedJwtException, SignatureException {
|
||||
Assert.notNull(handler, "JwtHandler argument cannot be null.");
|
||||
Assert.hasText(compact, "JWT String argument cannot be null or empty.");
|
||||
|
||||
Jwt jwt = parse(compact);
|
||||
|
||||
if (jwt instanceof Jws) {
|
||||
Jws jws = (Jws)jwt;
|
||||
Jws jws = (Jws) jwt;
|
||||
Object body = jws.getBody();
|
||||
if (body instanceof Claims) {
|
||||
return handler.onClaimsJws((Jws<Claims>)jws);
|
||||
return handler.onClaimsJws((Jws<Claims>) jws);
|
||||
} else {
|
||||
return handler.onPlaintextJws((Jws<String>)jws);
|
||||
return handler.onPlaintextJws((Jws<String>) jws);
|
||||
}
|
||||
} else {
|
||||
Object body = jwt.getBody();
|
||||
|
|
|
@ -174,6 +174,22 @@ class JwtParserTest {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
void testParseWithPrematureJwt() {
|
||||
|
||||
Date nbf = new Date(System.currentTimeMillis() + 100000);
|
||||
|
||||
String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact();
|
||||
|
||||
try {
|
||||
Jwts.parser().parse(compact);
|
||||
} catch (PrematureJwtException e) {
|
||||
assertTrue e.getMessage().startsWith('JWT must not be accepted before ')
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ========================================================================
|
||||
// parsePlaintextJwt tests
|
||||
// ========================================================================
|
||||
|
|
|
@ -91,7 +91,7 @@ class JwtsTest {
|
|||
@Test
|
||||
void testParsePlaintextToken() {
|
||||
|
||||
def claims = [iss: 'joe', exp: 1300819380, 'http://example.com/is_root':true]
|
||||
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
|
||||
|
||||
String jwt = Jwts.builder().setClaims(claims).compact();
|
||||
|
||||
|
@ -220,10 +220,22 @@ class JwtsTest {
|
|||
assertNull claims.getAudience()
|
||||
}
|
||||
|
||||
private static Date dateWithOnlySecondPrecision() {
|
||||
private static Date now() {
|
||||
return dateWithOnlySecondPrecision(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private static int later() {
|
||||
return laterDate().getTime() / 1000;
|
||||
}
|
||||
|
||||
private static Date laterDate(int seconds) {
|
||||
return dateWithOnlySecondPrecision(System.currentTimeMillis() + (seconds * 1000));
|
||||
}
|
||||
|
||||
private static Date laterDate() {
|
||||
return laterDate(10000);
|
||||
}
|
||||
|
||||
private static Date dateWithOnlySecondPrecision(long millis) {
|
||||
long seconds = millis / 1000;
|
||||
long secondOnlyPrecisionMillis = seconds * 1000;
|
||||
|
@ -232,14 +244,14 @@ class JwtsTest {
|
|||
|
||||
@Test
|
||||
void testConvenienceExpiration() {
|
||||
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
|
||||
String compact = Jwts.builder().setExpiration(now).compact();
|
||||
Date then = laterDate();
|
||||
String compact = Jwts.builder().setExpiration(then).compact();
|
||||
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||
def claimedDate = claims.getExpiration()
|
||||
assertEquals claimedDate, now
|
||||
assertEquals claimedDate, then
|
||||
|
||||
compact = Jwts.builder().setIssuer("Me")
|
||||
.setExpiration(now) //set it
|
||||
.setExpiration(then) //set it
|
||||
.setExpiration(null) //null should remove it
|
||||
.compact();
|
||||
|
||||
|
@ -249,7 +261,7 @@ class JwtsTest {
|
|||
|
||||
@Test
|
||||
void testConvenienceNotBefore() {
|
||||
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
|
||||
Date now = now() //jwt exp only supports *seconds* since epoch:
|
||||
String compact = Jwts.builder().setNotBefore(now).compact();
|
||||
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||
def claimedDate = claims.getNotBefore()
|
||||
|
@ -266,7 +278,7 @@ class JwtsTest {
|
|||
|
||||
@Test
|
||||
void testConvenienceIssuedAt() {
|
||||
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
|
||||
Date now = now() //jwt exp only supports *seconds* since epoch:
|
||||
String compact = Jwts.builder().setIssuedAt(now).compact();
|
||||
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||
def claimedDate = claims.getIssuedAt()
|
||||
|
@ -370,7 +382,7 @@ class JwtsTest {
|
|||
PublicKey publicKey = kp.getPublic();
|
||||
PrivateKey privateKey = kp.getPrivate();
|
||||
|
||||
def claims = [iss: 'joe', exp: 1300819380, 'http://example.com/is_root':true]
|
||||
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
|
||||
|
||||
String jwt = Jwts.builder().setClaims(claims).signWith(alg, privateKey).compact();
|
||||
|
||||
|
@ -393,7 +405,7 @@ class JwtsTest {
|
|||
byte[] key = new byte[64];
|
||||
random.nextBytes(key);
|
||||
|
||||
def claims = [iss: 'joe', exp: 1300819380, 'http://example.com/is_root':true]
|
||||
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
|
||||
|
||||
String jwt = Jwts.builder().setClaims(claims).signWith(alg, key).compact();
|
||||
|
||||
|
|
Loading…
Reference in New Issue