Argument validation for allowedClockSkewSeconds (#601)

* 583: ensured setting allowedClockSkewSeconds to be greater than (Long.MAX_VALUE / 1000) will throw an IllegalArgumentException.
This commit is contained in:
Les Hazlewood 2020-06-11 13:46:03 -04:00 committed by GitHub
parent 2b00ed1819
commit 72973f9b9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 4 deletions

View File

@ -191,13 +191,15 @@ public interface JwtParser {
* @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims. * @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
* @return the parser for method chaining. * @return the parser for method chaining.
* @since 0.7.0 * @since 0.7.0
* @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
* any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
* @deprecated see {@link JwtParserBuilder#setAllowedClockSkewSeconds(long)}. * @deprecated see {@link JwtParserBuilder#setAllowedClockSkewSeconds(long)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser. * immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b> * <p><b>NOTE: this method will be removed before version 1.0</b>
*/ */
@Deprecated @Deprecated
JwtParser setAllowedClockSkewSeconds(long seconds); JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
/** /**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not

View File

@ -147,8 +147,10 @@ public interface JwtParserBuilder {
* *
* @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims. * @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
* @return the parser builder for method chaining. * @return the parser builder for method chaining.
* @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
* any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
*/ */
JwtParserBuilder setAllowedClockSkewSeconds(long seconds); JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
/** /**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not

View File

@ -180,7 +180,8 @@ public class DefaultJwtParser implements JwtParser {
} }
@Override @Override
public JwtParser setAllowedClockSkewSeconds(long seconds) { public JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException {
Assert.isTrue(seconds <= DefaultJwtParserBuilder.MAX_CLOCK_SKEW_MILLIS, DefaultJwtParserBuilder.MAX_CLOCK_SKEW_ILLEGAL_MSG);
this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND); this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND);
return this; return this;
} }

View File

@ -39,6 +39,16 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
private static final int MILLISECONDS_PER_SECOND = 1000; private static final int MILLISECONDS_PER_SECOND = 1000;
/**
* To prevent overflow per <a href="https://github.com/jwtk/jjwt/issues/583">Issue 583</a>.
*
* Package-protected on purpose to allow use in backwards-compatible {@link DefaultJwtParser} implementation.
* TODO: enable private modifier on these two variables when deleting DefaultJwtParser
*/
static final long MAX_CLOCK_SKEW_MILLIS = Long.MAX_VALUE / MILLISECONDS_PER_SECOND;
static final String MAX_CLOCK_SKEW_ILLEGAL_MSG = "Illegal allowedClockSkewMillis value: multiplying this " +
"value by 1000 to obtain the number of milliseconds would cause a numeric overflow.";
private byte[] keyBytes; private byte[] keyBytes;
private Key key; private Key key;
@ -130,7 +140,8 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
} }
@Override @Override
public JwtParserBuilder setAllowedClockSkewSeconds(long seconds) { public JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException {
Assert.isTrue(seconds <= MAX_CLOCK_SKEW_MILLIS, MAX_CLOCK_SKEW_ILLEGAL_MSG);
this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND); this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND);
return this; return this;
} }

View File

@ -75,4 +75,21 @@ class DefaultJwtParserBuilderTest {
assertEquals 'bar', p.setSigningKey(key).build().parseClaimsJws(jws).getBody().get('foo') assertEquals 'bar', p.setSigningKey(key).build().parseClaimsJws(jws).getBody().get('foo')
} }
@Test
void testMaxAllowedClockSkewSeconds() {
long max = Long.MAX_VALUE / 1000 as long
new DefaultJwtParserBuilder().setAllowedClockSkewSeconds(max) // no exception should be thrown
}
@Test
void testExceededAllowedClockSkewSeconds() {
long value = Long.MAX_VALUE / 1000 as long
value = value + 1L
try {
new DefaultJwtParserBuilder().setAllowedClockSkewSeconds(value)
} catch (IllegalArgumentException expected) {
assertEquals DefaultJwtParserBuilder.MAX_CLOCK_SKEW_ILLEGAL_MSG, expected.message
}
}
} }

View File

@ -131,4 +131,21 @@ class DefaultJwtParserTest {
new DefaultJwtParser().setSigningKey(key).parseClaimsJws(invalidJws) new DefaultJwtParser().setSigningKey(key).parseClaimsJws(invalidJws)
} }
@Test
void testMaxAllowedClockSkewSeconds() {
long max = Long.MAX_VALUE / 1000 as long
new DefaultJwtParser().setAllowedClockSkewSeconds(max) // no exception should be thrown
}
@Test
void testExceededAllowedClockSkewSeconds() {
long value = Long.MAX_VALUE / 1000 as long
value = value + 1L
try {
new DefaultJwtParser().setAllowedClockSkewSeconds(value)
} catch (IllegalArgumentException expected) {
assertEquals DefaultJwtParserBuilder.MAX_CLOCK_SKEW_ILLEGAL_MSG, expected.message
}
}
} }