mirror of https://github.com/jwtk/jjwt.git
Issue #6: ensured that a (new) ExpiredJwtException is thrown when parsing an expired Claims JWT or JWS.
This commit is contained in:
parent
c0ff23ae6c
commit
adbcf46de3
|
@ -88,6 +88,10 @@ These feature sets will be implemented in a future release when possible. Commu
|
|||
|
||||
## Release Notes
|
||||
|
||||
### 0.3
|
||||
|
||||
Parsing a expired Claims JWT or JWS (as determined by the `exp` claims field) will now throw an `ExpiredJwtException`.
|
||||
|
||||
### 0.2
|
||||
|
||||
#### More convenient Claims building
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2014 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
/**
|
||||
* Exception indicating that a JWT was referenced after it expired and should be rejected.
|
||||
*
|
||||
* @since 0.3
|
||||
*/
|
||||
public class ExpiredJwtException extends JwtException {
|
||||
|
||||
public ExpiredJwtException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ExpiredJwtException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -106,6 +106,8 @@ public interface JwtParser {
|
|||
* JWTs should not be trusted and should be discarded.
|
||||
* @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail
|
||||
* signature validation should not be trusted and should be discarded.
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace.
|
||||
* @see #parse(String, JwtHandler)
|
||||
* @see #parsePlaintextJwt(String)
|
||||
|
@ -113,7 +115,7 @@ public interface JwtParser {
|
|||
* @see #parsePlaintextJws(String)
|
||||
* @see #parseClaimsJws(String)
|
||||
*/
|
||||
Jwt parse(String jwt) throws MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
|
||||
|
@ -150,6 +152,8 @@ public interface JwtParser {
|
|||
* Invalid JWTs should not be trusted and should be discarded.
|
||||
* @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail
|
||||
* signature validation should not be trusted and should be discarded.
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the specified string is {@code null} or empty or only whitespace, or if the
|
||||
* {@code handler} is {@code null}.
|
||||
* @see #parsePlaintextJwt(String)
|
||||
|
@ -160,7 +164,7 @@ public interface JwtParser {
|
|||
* @since 0.2
|
||||
*/
|
||||
<T> T parse(String jwt, JwtHandler<T> handler)
|
||||
throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWT string based on the builder's current configuration state and
|
||||
|
@ -210,6 +214,8 @@ public interface JwtParser {
|
|||
* @throws MalformedJwtException if the {@code claimsJwt} string is not a valid JWT
|
||||
* @throws SignatureException if the {@code claimsJwt} string is actually a JWS and signature validation
|
||||
* fails
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the {@code claimsJwt} string is {@code null} or empty or only whitespace
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parsePlaintextJws(String)
|
||||
|
@ -219,7 +225,7 @@ public interface JwtParser {
|
|||
* @since 0.2
|
||||
*/
|
||||
Jwt<Header, Claims> parseClaimsJwt(String claimsJwt)
|
||||
throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parses the specified compact serialized JWS string based on the builder's current configuration state and
|
||||
|
@ -265,6 +271,8 @@ public interface JwtParser {
|
|||
* @throws UnsupportedJwtException if the {@code claimsJws} argument does not represent an Claims JWS
|
||||
* @throws MalformedJwtException if the {@code claimsJws} string is not a valid JWS
|
||||
* @throws SignatureException if the {@code claimsJws} JWS signature validation fails
|
||||
* @throws ExpiredJwtException if the specified JWT is a Claims JWT and the Claims has an expiration time
|
||||
* before the time this method is invoked.
|
||||
* @throws IllegalArgumentException if the {@code claimsJws} string is {@code null} or empty or only whitespace
|
||||
* @see #parsePlaintextJwt(String)
|
||||
* @see #parseClaimsJwt(String)
|
||||
|
@ -274,5 +282,5 @@ public interface JwtParser {
|
|||
* @since 0.2
|
||||
*/
|
||||
Jws<Claims> parseClaimsJws(String claimsJws)
|
||||
throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package io.jsonwebtoken.impl;
|
|||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
|
@ -37,6 +38,8 @@ import io.jsonwebtoken.lang.Strings;
|
|||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.security.Key;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -94,7 +97,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Jwt parse(String jwt) throws MalformedJwtException, SignatureException {
|
||||
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
|
||||
|
||||
Assert.hasText(jwt, "JWT String argument cannot be null or empty.");
|
||||
|
||||
|
@ -161,6 +164,28 @@ public class DefaultJwtParser implements JwtParser {
|
|||
claims = new DefaultClaims(claimsMap);
|
||||
}
|
||||
|
||||
//since 0.3:
|
||||
if (claims != null) {
|
||||
|
||||
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
|
||||
|
||||
String expVal = sdf.format(exp);
|
||||
String nowVal = sdf.format(now);
|
||||
|
||||
String msg = "JWT expired at " + expVal + ". Current time: " + nowVal;
|
||||
throw new ExpiredJwtException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============== Signature =================
|
||||
if (base64UrlEncodedDigest != null) { //it is signed - validate the signature
|
||||
|
||||
|
@ -223,7 +248,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> T parse(String compact, JwtHandler<T> handler) throws 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.");
|
||||
|
||||
|
|
|
@ -160,6 +160,20 @@ class JwtParserTest {
|
|||
assertEquals jwt.body, payload
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseWithExpiredJwt() {
|
||||
|
||||
Date exp = new Date(System.currentTimeMillis() - 1000);
|
||||
|
||||
String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact();
|
||||
|
||||
try {
|
||||
Jwts.parser().parse(compact);
|
||||
} catch (ExpiredJwtException e) {
|
||||
assertTrue e.getMessage().startsWith('JWT expired at ')
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// parsePlaintextJwt tests
|
||||
// ========================================================================
|
||||
|
@ -275,6 +289,23 @@ class JwtParserTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseClaimsJwtWithExpiredJwt() {
|
||||
|
||||
long nowMillis = System.currentTimeMillis();
|
||||
//some time in the past:
|
||||
Date exp = new Date(nowMillis - 1000);
|
||||
|
||||
String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact()
|
||||
|
||||
try {
|
||||
Jwts.parser().parseClaimsJwt(compact);
|
||||
fail();
|
||||
} catch (ExpiredJwtException e) {
|
||||
assertTrue e.getMessage().startsWith('JWT expired at ')
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// parsePlaintextJws tests
|
||||
// ========================================================================
|
||||
|
@ -359,6 +390,25 @@ class JwtParserTest {
|
|||
assertEquals jwt.getBody().getSubject(), sub
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseClaimsJwsWithExpiredJws() {
|
||||
|
||||
byte[] key = randomKey()
|
||||
|
||||
long nowMillis = System.currentTimeMillis();
|
||||
//some time in the past:
|
||||
Date exp = new Date(nowMillis - 1000);
|
||||
|
||||
String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, key).setExpiration(exp).compact()
|
||||
|
||||
try {
|
||||
Jwts.parser().parseClaimsJwt(compact);
|
||||
fail();
|
||||
} catch (ExpiredJwtException e) {
|
||||
assertTrue e.getMessage().startsWith('JWT expired at ')
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseClaimsJwsWithPlaintextJwt() {
|
||||
|
||||
|
|
Loading…
Reference in New Issue