Add JwtParserBuilder as the preferred way to create a JwtParser instance (#486)

- Added new JwtParserBuilder
- Copied mutator methods from JwtParser into new JwtParserBuilder
- Marked said methods as deprecated in JwtParser
- Copied JwtParserTest and JwtsTest to Deprecated*, as to retain coverage on methods that will be removed in 1.0
- Added ImmutableJwtParser
  This is a stop gap until 1.0, all of the mutable methods will now throw a IllegalStateException.
  NOTE: this only comes into place when using the new Jwts.parserBuilder(), Jwts.parser() is unchanged.

Fixes: #473
This commit is contained in:
Brian Demers 2019-10-01 12:03:20 -04:00 committed by GitHub
parent a236656c00
commit 94d151129d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 3601 additions and 129 deletions

View File

@ -6,6 +6,22 @@ This minor release:
* Updates the Jackson dependency version to [2.9.10](https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.9#patches)
to address three security vulnerabilities in Jackson.
* A new JwtParserBuilder interface has been added and is the recommended way of creating a JwtParser instance. Mutable methods in `JwtParser` will be removed before v1.0.
Migration to the new signatures is straightforward, for example:
Previous Version:
```java
Jwts.parser()
.requireAudience("string")
.parse(jwtString)
```
Current Version:
```java
Jwts.parserBuilder()
.requireAudience("string")
.build()
.parse(jwtString)
```
* Adds support for custom types when deserializing with Jackson. To use configure your parser with `Jwts.parserBuilder().deserializeJsonWith(new JacksonDeserializer(Maps.of("claimName", YourType.class).build())).build()`.
* Adds `io.jsonwebtoken.lang.Maps` utility class to make creation of maps fluent.
* Moves JSON Serializer/Deserializer implementations to a different package name.

View File

@ -33,4 +33,21 @@
<jjwt.root>${basedir}/..</jjwt.root>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<executions>
<execution>
<id>japicmp</id>
<goals>
<goal>cmp</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -41,7 +41,12 @@ public interface JwtParser {
* @return the parser method for chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireId(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireId(String id);
/**
@ -53,7 +58,12 @@ public interface JwtParser {
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireSubject(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireSubject(String subject);
/**
@ -65,7 +75,12 @@ public interface JwtParser {
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireAudience(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireAudience(String audience);
/**
@ -77,7 +92,12 @@ public interface JwtParser {
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireIssuer(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireIssuer(String issuer);
/**
@ -89,7 +109,12 @@ public interface JwtParser {
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireIssuedAt(Date)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireIssuedAt(Date issuedAt);
/**
@ -101,7 +126,12 @@ public interface JwtParser {
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireExpiration(Date)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireExpiration(Date expiration);
/**
@ -113,7 +143,12 @@ public interface JwtParser {
* @return the parser for method chaining
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#requireNotBefore(Date)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser requireNotBefore(Date notBefore);
/**
@ -126,7 +161,12 @@ public interface JwtParser {
* @return the parser for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
* @deprecated see {@link JwtParserBuilder#require(String, Object)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser require(String claimName, Object value);
/**
@ -136,7 +176,12 @@ public interface JwtParser {
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
* @return the parser for method chaining.
* @since 0.7.0
* @deprecated see {@link JwtParserBuilder#setClock(Clock)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setClock(Clock clock);
/**
@ -146,7 +191,12 @@ public interface JwtParser {
* @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.
* @since 0.7.0
* @deprecated see {@link JwtParserBuilder#setAllowedClockSkewSeconds(long)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setAllowedClockSkewSeconds(long seconds);
/**
@ -161,7 +211,12 @@ public interface JwtParser {
* @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
* signature.
* @return the parser for method chaining.
* @deprecated see {@link JwtParserBuilder#setSigningKey(byte[])}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setSigningKey(byte[] key);
/**
@ -202,7 +257,12 @@ public interface JwtParser {
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signature verification key to use to validate
* any discovered JWS digital signature.
* @return the parser for method chaining.
* @deprecated see {@link JwtParserBuilder#setSigningKey(String)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setSigningKey(String base64EncodedSecretKey);
/**
@ -217,7 +277,12 @@ public interface JwtParser {
* @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
* signature.
* @return the parser for method chaining.
* @deprecated see {@link JwtParserBuilder#setSigningKey(Key)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setSigningKey(Key key);
/**
@ -247,7 +312,12 @@ public interface JwtParser {
* @param signingKeyResolver the signing key resolver used to retrieve the signing key.
* @return the parser for method chaining.
* @since 0.4
* @deprecated see {@link JwtParserBuilder#setSigningKeyResolver(SigningKeyResolver)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
/**
@ -269,7 +339,12 @@ public interface JwtParser {
* @param compressionCodecResolver the compression codec resolver used to decompress the JWT body.
* @return the parser for method chaining.
* @since 0.6.0
* @deprecated see {@link JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
/**
@ -281,7 +356,12 @@ public interface JwtParser {
* @param base64UrlDecoder the decoder to use when Base64Url-decoding
* @return the parser for method chaining.
* @since 0.10.0
* @deprecated see {@link JwtParserBuilder#base64UrlDecodeWith(Decoder)}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder);
/**
@ -295,9 +375,14 @@ public interface JwtParser {
* invoked.</p>
*
* @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
* @return the builder for method chaining.
* @return the parser for method chaining.
* @since 0.10.0
* @deprecated see {@link JwtParserBuilder#deserializeJsonWith(Deserializer)} )}.
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
* immutable JwtParser.
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
JwtParser deserializeJsonWith(Deserializer<Map<String,?>> deserializer);
/**

View File

@ -0,0 +1,305 @@
/*
* Copyright (C) 2019 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;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Deserializer;
import java.security.Key;
import java.util.Date;
import java.util.Map;
/**
* A builder to construct a {@link JwtParser}. Example usage:
* <pre>{@code
* Jwts.parserBuilder()
* .setSigningKey(...)
* .requireIssuer("https://issuer.example.com")
* .build()
* .parse(jwtString)
* }</pre>
* @since 0.11.0
*/
public interface JwtParserBuilder {
/**
* Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param id
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireId(String id);
/**
* Ensures that the specified {@code sub} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param subject
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireSubject(String subject);
/**
* Ensures that the specified {@code aud} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param audience
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireAudience(String audience);
/**
* Ensures that the specified {@code iss} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param issuer
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireIssuer(String issuer);
/**
* Ensures that the specified {@code iat} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param issuedAt
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireIssuedAt(Date issuedAt);
/**
* Ensures that the specified {@code exp} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param expiration
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireExpiration(Date expiration);
/**
* Ensures that the specified {@code nbf} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param notBefore
* @return the parser builder for method chaining
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder requireNotBefore(Date notBefore);
/**
* Ensures that the specified {@code claimName} exists in the parsed JWT. If missing or if the parsed
* value does not equal the specified value, an exception will be thrown indicating that the
* JWT is invalid and may not be used.
*
* @param claimName
* @param value
* @return the parser builder for method chaining.
* @see MissingClaimException
* @see IncorrectClaimException
*/
JwtParserBuilder require(String claimName, Object value);
/**
* Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
* The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
*
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
* @return the parser builder for method chaining.
*/
JwtParserBuilder 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 the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setAllowedClockSkewSeconds(long 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.
* <p>
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).</p>
* <p>
* <p>This method overwrites any previously set key.</p>
*
* @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
* signature.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setSigningKey(byte[] key);
/**
* 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.
*
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).</p>
*
* <p>This method overwrites any previously set key.</p>
*
* <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #setSigningKey(byte[])}.</p>
*
* <h4>Deprecation Notice: Deprecated as of 0.10.0, will be removed in 1.0.0</h4>
*
* <p>This method has been deprecated because the {@code key} argument for this method can be confusing: keys for
* cryptographic operations are always binary (byte arrays), and many people were confused as to how bytes were
* obtained from the String argument.</p>
*
* <p>This method always expected a String argument that was effectively the same as the result of the following
* (pseudocode):</p>
*
* <p>{@code String base64EncodedSecretKey = base64Encode(secretKeyBytes);}</p>
*
* <p>However, a non-trivial number of JJWT users were confused by the method signature and attempted to
* use raw password strings as the key argument - for example {@code setSigningKey(myPassword)} - which is
* almost always incorrect for cryptographic hashes and can produce erroneous or insecure results.</p>
*
* <p>See this
* <a href="https://stackoverflow.com/questions/40252903/static-secret-as-byte-key-or-string/40274325#40274325">
* StackOverflow answer</a> explaining why raw (non-base64-encoded) strings are almost always incorrect for
* signature operations.</p>
*
* <p>Finally, please use the {@link #setSigningKey(Key) setSigningKey(Key)} instead, as this method and the
* {@code byte[]} variant will be removed before the 1.0.0 release.</p>
*
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signature verification key to use to validate
* any discovered JWS digital signature.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setSigningKey(String base64EncodedSecretKey);
/**
* 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.
* <p>
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).</p>
* <p>
* <p>This method overwrites any previously set key.</p>
*
* @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
* signature.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setSigningKey(Key key);
/**
* Sets the {@link SigningKeyResolver} used to acquire the <code>signing key</code> that should be used to verify
* a JWS's signature. If the parsed String is not a JWS (no signature), this resolver is not used.
* <p>
* <p>Specifying a {@code SigningKeyResolver} is necessary when the signing key is not already known before parsing
* the JWT and the JWT header or payload (plaintext body or Claims) must be inspected first to determine how to
* look up the signing key. Once returned by the resolver, the JwtParser will then verify the JWS signature with the
* returned key. For example:</p>
* <p>
* <pre>
* Jws&lt;Claims&gt; jws = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
* &#64;Override
* public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
* //inspect the header or claims, lookup and return the signing key
* return getSigningKey(header, claims); //implement me
* }})
* .parseClaimsJws(compact);
* </pre>
* <p>
* <p>A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.</p>
* <p>
* <p>This method should only be used if a signing key is not provided by the other {@code setSigningKey*} builder
* methods.</p>
*
* @param signingKeyResolver the signing key resolver used to retrieve the signing key.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
/**
* Sets the {@link CompressionCodecResolver} used to acquire the {@link CompressionCodec} that should be used to
* decompress the JWT body. If the parsed JWT is not compressed, this resolver is not used.
* <p><b>NOTE:</b> Compression is not defined by the JWT Specification, and it is not expected that other libraries
* (including JJWT versions &lt; 0.6.0) are able to consume a compressed JWT body correctly. This method is only
* useful if the compact JWT was compressed with JJWT &gt;= 0.6.0 or another library that you know implements
* the same behavior.</p>
* <h3>Default Support</h3>
* <p>JJWT's default {@link JwtParser} implementation supports both the
* {@link CompressionCodecs#DEFLATE DEFLATE}
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.</p>
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement
* your own {@link CompressionCodecResolver} and specify that via this method and also when
* {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} JWTs.</p>
*
* @param compressionCodecResolver the compression codec resolver used to decompress the JWT body.
* @return the parser builder for method chaining.
*/
JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
/**
* Perform Base64Url decoding with the specified Decoder
*
* <p>JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method
* to specify a different decoder if you desire.</p>
*
* @param base64UrlDecoder the decoder to use when Base64Url-decoding
* @return the parser builder for method chaining.
*/
JwtParserBuilder base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder);
/**
* Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is
* used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map
* objects.
*
* <p>If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the
* presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
* in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is
* invoked.</p>
*
* @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
* @return the builder for method chaining.
*/
JwtParserBuilder deserializeJsonWith(Deserializer<Map<String,?>> deserializer);
/**
* Returns a {@link JwtParser} created from the configuration from this JwtParserBuilder.
* @return a JwtParser created from the configuration from this JwtParserBuilder.
*/
JwtParser build();
}

View File

@ -99,11 +99,37 @@ public final class Jwts {
* Returns a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
*
* @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
* @deprecated use {@link Jwts#parserBuilder()} instead. See {@link JwtParserBuilder} for usage details.
* <p>Migration to new method structure is minimal, for example:
* <p>Old code:
* <pre>{@code
* Jwts.parser()
* .requireAudience("string")
* .parse(jwtString)
* }</pre>
* <p>New code:
* <pre>{@code
* Jwts.parserBuilder()
* .requireAudience("string")
* .build()
* .parse(jwtString)
* }</pre>
* <p><b>NOTE: this method will be removed before version 1.0</b>
*/
@Deprecated
public static JwtParser parser() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParser");
}
/**
* Returns a new {@link JwtParserBuilder} instance that can be configured and then used to parse JWT strings.
*
* @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
*/
public static JwtParserBuilder parserBuilder() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder");
}
/**
* Returns a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.

View File

@ -63,6 +63,7 @@ public class DefaultJwtParser implements JwtParser {
private static final int MILLISECONDS_PER_SECOND = 1000;
// TODO: make the folling fields final for v1.0
private byte[] keyBytes;
private Key key;
@ -81,6 +82,40 @@ public class DefaultJwtParser implements JwtParser {
private long allowedClockSkewMillis = 0;
/**
* TODO: remove this constructor before 1.0
* @deprecated for backward compatibility only, see other constructors.
*/
@Deprecated
public DefaultJwtParser() { }
DefaultJwtParser(SigningKeyResolver signingKeyResolver,
Key key,
byte[] keyBytes,
Clock clock,
long allowedClockSkewMillis,
Claims expectedClaims,
Decoder<String, byte[]> base64UrlDecoder,
Deserializer<Map<String, ?>> deserializer,
CompressionCodecResolver compressionCodecResolver) {
this.signingKeyResolver = signingKeyResolver;
this.key = key;
this.keyBytes = keyBytes;
this.clock = clock;
this.allowedClockSkewMillis = allowedClockSkewMillis;
this.expectedClaims = expectedClaims;
this.base64UrlDecoder = base64UrlDecoder;
this.deserializer = deserializer;
this.compressionCodecResolver = compressionCodecResolver;
if (this.deserializer == null) {
//try to find one based on the runtime environment:
InstanceLocator<Deserializer<Map<String, ?>>> locator =
Classes.newInstance("io.jsonwebtoken.impl.io.RuntimeClasspathDeserializerLocator");
this.deserializer = locator.getInstance();
}
}
@Override
public JwtParser deserializeJsonWith(Deserializer<Map<String, ?>> deserializer) {
Assert.notNull(deserializer, "deserializer cannot be null.");
@ -220,6 +255,7 @@ public class DefaultJwtParser implements JwtParser {
@Override
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
// TODO move this to constructor before 1.0
if (this.deserializer == null) {
//try to find one based on the runtime environment:
InstanceLocator<Deserializer<Map<String, ?>>> locator =

View File

@ -0,0 +1,184 @@
/*
* Copyright (C) 2019 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.impl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Clock;
import io.jsonwebtoken.CompressionCodecResolver;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.JwtParserBuilder;
import io.jsonwebtoken.SigningKeyResolver;
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert;
import java.security.Key;
import java.util.Date;
import java.util.Map;
/**
* @since 0.11.0
*/
public class DefaultJwtParserBuilder implements JwtParserBuilder {
private static final int MILLISECONDS_PER_SECOND = 1000;
private byte[] keyBytes;
private Key key;
private SigningKeyResolver signingKeyResolver;
private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver();
private Decoder<String, byte[]> base64UrlDecoder = Decoders.BASE64URL;
private Deserializer<Map<String, ?>> deserializer;
private Claims expectedClaims = new DefaultClaims();
private Clock clock = DefaultClock.INSTANCE;
private long allowedClockSkewMillis = 0;
@Override
public JwtParserBuilder deserializeJsonWith(Deserializer<Map<String, ?>> deserializer) {
Assert.notNull(deserializer, "deserializer cannot be null.");
this.deserializer = deserializer;
return this;
}
@Override
public JwtParserBuilder base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder) {
Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null.");
this.base64UrlDecoder = base64UrlDecoder;
return this;
}
@Override
public JwtParserBuilder requireIssuedAt(Date issuedAt) {
expectedClaims.setIssuedAt(issuedAt);
return this;
}
@Override
public JwtParserBuilder requireIssuer(String issuer) {
expectedClaims.setIssuer(issuer);
return this;
}
@Override
public JwtParserBuilder requireAudience(String audience) {
expectedClaims.setAudience(audience);
return this;
}
@Override
public JwtParserBuilder requireSubject(String subject) {
expectedClaims.setSubject(subject);
return this;
}
@Override
public JwtParserBuilder requireId(String id) {
expectedClaims.setId(id);
return this;
}
@Override
public JwtParserBuilder requireExpiration(Date expiration) {
expectedClaims.setExpiration(expiration);
return this;
}
@Override
public JwtParserBuilder requireNotBefore(Date notBefore) {
expectedClaims.setNotBefore(notBefore);
return this;
}
@Override
public JwtParserBuilder require(String claimName, Object value) {
Assert.hasText(claimName, "claim name cannot be null or empty.");
Assert.notNull(value, "The value cannot be null for claim name: " + claimName);
expectedClaims.put(claimName, value);
return this;
}
@Override
public JwtParserBuilder setClock(Clock clock) {
Assert.notNull(clock, "Clock instance cannot be null.");
this.clock = clock;
return this;
}
@Override
public JwtParserBuilder setAllowedClockSkewSeconds(long seconds) {
this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND);
return this;
}
@Override
public JwtParserBuilder setSigningKey(byte[] key) {
Assert.notEmpty(key, "signing key cannot be null or empty.");
this.keyBytes = key;
return this;
}
@Override
public JwtParserBuilder setSigningKey(String base64EncodedSecretKey) {
Assert.hasText(base64EncodedSecretKey, "signing key cannot be null or empty.");
this.keyBytes = Decoders.BASE64.decode(base64EncodedSecretKey);
return this;
}
@Override
public JwtParserBuilder setSigningKey(Key key) {
Assert.notNull(key, "signing key cannot be null.");
this.key = key;
return this;
}
@Override
public JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver) {
Assert.notNull(signingKeyResolver, "SigningKeyResolver cannot be null.");
this.signingKeyResolver = signingKeyResolver;
return this;
}
@Override
public JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) {
Assert.notNull(compressionCodecResolver, "compressionCodecResolver cannot be null.");
this.compressionCodecResolver = compressionCodecResolver;
return this;
}
@Override
public JwtParser build() {
return new ImmutableJwtParser(
new DefaultJwtParser(signingKeyResolver,
key,
keyBytes,
clock,
allowedClockSkewMillis,
expectedClaims,
base64UrlDecoder,
deserializer,
compressionCodecResolver));
}
}

View File

@ -0,0 +1,175 @@
/*
* Copyright (C) 2019 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.impl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Clock;
import io.jsonwebtoken.CompressionCodecResolver;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtHandler;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SigningKeyResolver;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.security.SignatureException;
import java.security.Key;
import java.util.Date;
import java.util.Map;
/**
* This JwtParser implementation exists as a stop gap until the mutable methods are removed from JwtParser.
* TODO: remove this class BEFORE 1.0
* @since 0.11.0
*/
class ImmutableJwtParser implements JwtParser {
private final JwtParser jwtParser;
ImmutableJwtParser(JwtParser jwtParser) {
this.jwtParser = jwtParser;
}
private IllegalStateException doNotMutate() {
return new IllegalStateException("Cannot mutate a JwtParser created from JwtParserBuilder.build(), " +
"the mutable methods in JwtParser will be removed before version 1.0");
}
@Override
public JwtParser requireId(String id) {
throw doNotMutate();
}
@Override
public JwtParser requireSubject(String subject) {
throw doNotMutate();
}
@Override
public JwtParser requireAudience(String audience) {
throw doNotMutate();
}
@Override
public JwtParser requireIssuer(String issuer) {
throw doNotMutate();
}
@Override
public JwtParser requireIssuedAt(Date issuedAt) {
throw doNotMutate();
}
@Override
public JwtParser requireExpiration(Date expiration) {
throw doNotMutate();
}
@Override
public JwtParser requireNotBefore(Date notBefore) {
throw doNotMutate();
}
@Override
public JwtParser require(String claimName, Object value) {
throw doNotMutate();
}
@Override
public JwtParser setClock(Clock clock) {
throw doNotMutate();
}
@Override
public JwtParser setAllowedClockSkewSeconds(long seconds) {
throw doNotMutate();
}
@Override
public JwtParser setSigningKey(byte[] key) {
throw doNotMutate();
}
@Override
public JwtParser setSigningKey(String base64EncodedSecretKey) {
throw doNotMutate();
}
@Override
public JwtParser setSigningKey(Key key) {
throw doNotMutate();
}
@Override
public JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver) {
throw doNotMutate();
}
@Override
public JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) {
throw doNotMutate();
}
@Override
public JwtParser base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder) {
throw doNotMutate();
}
@Override
public JwtParser deserializeJsonWith(Deserializer<Map<String, ?>> deserializer) {
throw doNotMutate();
}
@Override
public boolean isSigned(String jwt) {
return this.jwtParser.isSigned(jwt);
}
@Override
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
return this.jwtParser.parse(jwt);
}
@Override
public <T> T parse(String jwt, JwtHandler<T> handler) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
return this.jwtParser.parse(jwt, handler);
}
@Override
public Jwt<Header, String> parsePlaintextJwt(String plaintextJwt) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
return this.jwtParser.parsePlaintextJwt(plaintextJwt);
}
@Override
public Jwt<Header, Claims> parseClaimsJwt(String claimsJwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
return this.jwtParser.parseClaimsJwt(claimsJwt);
}
@Override
public Jws<String> parsePlaintextJws(String plaintextJws) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
return this.jwtParser.parsePlaintextJws(plaintextJws);
}
@Override
public Jws<Claims> parseClaimsJws(String claimsJws) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
return this.jwtParser.parseClaimsJws(claimsJws);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,798 @@
/*
* 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
import io.jsonwebtoken.impl.DefaultHeader
import io.jsonwebtoken.impl.DefaultJwsHeader
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver
import io.jsonwebtoken.impl.compression.GzipCompressionCodec
import io.jsonwebtoken.impl.io.RuntimeClasspathSerializerLocator
import io.jsonwebtoken.io.Encoders
import io.jsonwebtoken.lang.Strings
import io.jsonwebtoken.security.Keys
import io.jsonwebtoken.security.WeakKeyException
import org.junit.Test
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.nio.charset.Charset
import java.security.KeyPair
import java.security.PrivateKey
import java.security.PublicKey
import static org.junit.Assert.*
class DeprecatedJwtsTest {
protected static String base64Url(String s) {
byte[] bytes = s.getBytes(Strings.UTF_8)
return Encoders.BASE64URL.encode(bytes)
}
protected static String toJson(o) {
def serializer = new RuntimeClasspathSerializerLocator().getInstance()
byte[] bytes = serializer.serialize(o)
return new String(bytes, Strings.UTF_8)
}
@Test
void testSubclass() {
new Jwts()
}
@Test
void testHeaderWithNoArgs() {
def header = Jwts.header()
assertTrue header instanceof DefaultHeader
}
@Test
void testHeaderWithMapArg() {
def header = Jwts.header([alg: "HS256"])
assertTrue header instanceof DefaultHeader
assertEquals header.alg, 'HS256'
}
@Test
void testJwsHeaderWithNoArgs() {
def header = Jwts.jwsHeader()
assertTrue header instanceof DefaultJwsHeader
}
@Test
void testJwsHeaderWithMapArg() {
def header = Jwts.jwsHeader([alg: "HS256"])
assertTrue header instanceof DefaultJwsHeader
assertEquals header.getAlgorithm(), 'HS256'
}
@Test
void testClaims() {
Claims claims = Jwts.claims()
assertNotNull claims
}
@Test
void testClaimsWithMapArg() {
Claims claims = Jwts.claims([sub: 'Joe'])
assertNotNull claims
assertEquals claims.getSubject(), 'Joe'
}
@Test
void testPlaintextJwtString() {
// Assert exact output per example at https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-6.1
// The base64url encoding of the example claims set in the spec shows that their original payload ends lines with
// carriage return + newline, so we have to include them in the test payload to assert our encoded output
// matches what is in the spec:
def payload = '{"iss":"joe",\r\n' +
' "exp":1300819380,\r\n' +
' "http://example.com/is_root":true}'
String val = Jwts.builder().setPayload(payload).compact();
def specOutput = 'eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
assertEquals val, specOutput
}
@Test
void testParsePlaintextToken() {
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).compact();
def token = Jwts.parser().parse(jwt);
//noinspection GrEqualsBetweenInconvertibleTypes
assert token.body == claims
}
@Test(expected = IllegalArgumentException)
void testParseNull() {
Jwts.parser().parse(null)
}
@Test(expected = IllegalArgumentException)
void testParseEmptyString() {
Jwts.parser().parse('')
}
@Test(expected = IllegalArgumentException)
void testParseWhitespaceString() {
Jwts.parser().parse(' ')
}
@Test
void testParseWithNoPeriods() {
try {
Jwts.parser().parse('foo')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT strings must contain exactly 2 period characters. Found: 0"
}
}
@Test
void testParseWithOnePeriodOnly() {
try {
Jwts.parser().parse('.')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT strings must contain exactly 2 period characters. Found: 1"
}
}
@Test
void testParseWithTwoPeriodsOnly() {
try {
Jwts.parser().parse('..')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string '..' is missing a body/payload."
}
}
@Test
void testParseWithHeaderOnly() {
try {
Jwts.parser().parse('foo..')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string 'foo..' is missing a body/payload."
}
}
@Test
void testParseWithSignatureOnly() {
try {
Jwts.parser().parse('..bar')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string '..bar' is missing a body/payload."
}
}
@Test
void testParseWithHeaderAndSignatureOnly() {
try {
Jwts.parser().parse('foo..bar')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string 'foo..bar' is missing a body/payload."
}
}
@Test
void testWithInvalidCompressionAlgorithm() {
try {
Jwts.builder().setHeaderParam(Header.COMPRESSION_ALGORITHM, "CUSTOM").setId("andId").compact()
} catch (CompressionException e) {
assertEquals "Unsupported compression algorithm 'CUSTOM'", e.getMessage()
}
}
@Test
void testConvenienceIssuer() {
String compact = Jwts.builder().setIssuer("Me").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getIssuer(), "Me"
compact = Jwts.builder().setSubject("Joe")
.setIssuer("Me") //set it
.setIssuer(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getIssuer()
}
@Test
void testConvenienceSubject() {
String compact = Jwts.builder().setSubject("Joe").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getSubject(), "Joe"
compact = Jwts.builder().setIssuer("Me")
.setSubject("Joe") //set it
.setSubject(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getSubject()
}
@Test
void testConvenienceAudience() {
String compact = Jwts.builder().setAudience("You").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getAudience(), "You"
compact = Jwts.builder().setIssuer("Me")
.setAudience("You") //set it
.setAudience(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getAudience()
}
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;
return new Date(secondOnlyPrecisionMillis);
}
@Test
void testConvenienceExpiration() {
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, then
compact = Jwts.builder().setIssuer("Me")
.setExpiration(then) //set it
.setExpiration(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getExpiration()
}
@Test
void testConvenienceNotBefore() {
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()
assertEquals claimedDate, now
compact = Jwts.builder().setIssuer("Me")
.setNotBefore(now) //set it
.setNotBefore(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getNotBefore()
}
@Test
void testConvenienceIssuedAt() {
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()
assertEquals claimedDate, now
compact = Jwts.builder().setIssuer("Me")
.setIssuedAt(now) //set it
.setIssuedAt(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getIssuedAt()
}
@Test
void testConvenienceId() {
String id = UUID.randomUUID().toString();
String compact = Jwts.builder().setId(id).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
assertEquals claims.getId(), id
compact = Jwts.builder().setIssuer("Me")
.setId(id) //set it
.setId(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
assertNull claims.getId()
}
@Test
void testUncompressedJwt() {
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String id = UUID.randomUUID().toString()
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compact()
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Claims claims = jws.body
assertNull jws.header.getCompressionAlgorithm()
assertEquals id, claims.getId()
assertEquals "an audience", claims.getAudience()
assertEquals "hello this is an amazing jwt", claims.state
}
@Test
void testCompressedJwtWithDeflate() {
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String id = UUID.randomUUID().toString()
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compressWith(CompressionCodecs.DEFLATE).compact()
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Claims claims = jws.body
assertEquals "DEF", jws.header.getCompressionAlgorithm()
assertEquals id, claims.getId()
assertEquals "an audience", claims.getAudience()
assertEquals "hello this is an amazing jwt", claims.state
}
@Test
void testCompressedJwtWithGZIP() {
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String id = UUID.randomUUID().toString()
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compressWith(CompressionCodecs.GZIP).compact()
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Claims claims = jws.body
assertEquals "GZIP", jws.header.getCompressionAlgorithm()
assertEquals id, claims.getId()
assertEquals "an audience", claims.getAudience()
assertEquals "hello this is an amazing jwt", claims.state
}
@Test
void testCompressedWithCustomResolver() {
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String id = UUID.randomUUID().toString()
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compressWith(new GzipCompressionCodec() {
@Override
String getAlgorithmName() {
return "CUSTOM"
}
}).compact()
def jws = Jwts.parser().setSigningKey(key).setCompressionCodecResolver(new DefaultCompressionCodecResolver() {
@Override
CompressionCodec resolveCompressionCodec(Header header) {
String algorithm = header.getCompressionAlgorithm()
if ("CUSTOM".equals(algorithm)) {
return CompressionCodecs.GZIP
} else {
return null
}
}
}).parseClaimsJws(compact)
Claims claims = jws.body
assertEquals "CUSTOM", jws.header.getCompressionAlgorithm()
assertEquals id, claims.getId()
assertEquals "an audience", claims.getAudience()
assertEquals "hello this is an amazing jwt", claims.state
}
@Test(expected = CompressionException.class)
void testCompressedJwtWithUnrecognizedHeader() {
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String id = UUID.randomUUID().toString()
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compressWith(new GzipCompressionCodec() {
@Override
String getAlgorithmName() {
return "CUSTOM"
}
}).compact()
Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
}
@Test
void testCompressStringPayloadWithDeflate() {
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String payload = "this is my test for a payload"
String compact = Jwts.builder().setPayload(payload).signWith(alg, key)
.compressWith(CompressionCodecs.DEFLATE).compact()
def jws = Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
String parsed = jws.body
assertEquals "DEF", jws.header.getCompressionAlgorithm()
assertEquals "this is my test for a payload", parsed
}
@Test
void testHS256() {
testHmac(SignatureAlgorithm.HS256)
}
@Test
void testHS384() {
testHmac(SignatureAlgorithm.HS384)
}
@Test
void testHS512() {
testHmac(SignatureAlgorithm.HS512)
}
@Test
void testRS256() {
testRsa(SignatureAlgorithm.RS256)
}
@Test
void testRS384() {
testRsa(SignatureAlgorithm.RS384)
}
@Test
void testRS512() {
testRsa(SignatureAlgorithm.RS512)
}
@Test
void testPS256() {
testRsa(SignatureAlgorithm.PS256)
}
@Test
void testPS384() {
testRsa(SignatureAlgorithm.PS384)
}
@Test
void testPS512() {
testRsa(SignatureAlgorithm.PS512)
}
@Test
void testRSA256WithPrivateKeyValidation() {
testRsa(SignatureAlgorithm.RS256, true)
}
@Test
void testRSA384WithPrivateKeyValidation() {
testRsa(SignatureAlgorithm.RS384, true)
}
@Test
void testRSA512WithPrivateKeyValidation() {
testRsa(SignatureAlgorithm.RS512, true)
}
@Test
void testES256() {
testEC(SignatureAlgorithm.ES256)
}
@Test
void testES384() {
testEC(SignatureAlgorithm.ES384)
}
@Test
void testES512() {
testEC(SignatureAlgorithm.ES512)
}
@Test
void testES256WithPrivateKeyValidation() {
try {
testEC(SignatureAlgorithm.ES256, true)
fail("EC private keys cannot be used to validate EC signatures.")
} catch (UnsupportedJwtException e) {
assertEquals e.cause.message, "Elliptic Curve signature validation requires an ECPublicKey instance."
}
}
@Test
void testParseClaimsJwsWithWeakHmacKey() {
SignatureAlgorithm alg = SignatureAlgorithm.HS384
def key = Keys.secretKeyFor(alg)
def weakKey = Keys.secretKeyFor(SignatureAlgorithm.HS256)
String jws = Jwts.builder().setSubject("Foo").signWith(key, alg).compact()
try {
Jwts.parser().setSigningKey(weakKey).parseClaimsJws(jws)
fail('parseClaimsJws must fail for weak keys')
} catch (WeakKeyException expected) {
}
}
//Asserts correct/expected behavior discussed in https://github.com/jwtk/jjwt/issues/20
@Test
void testParseClaimsJwsWithUnsignedJwt() {
//create random signing key for testing:
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
String notSigned = Jwts.builder().setSubject("Foo").compact()
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(notSigned)
fail('parseClaimsJws must fail for unsigned JWTs')
} catch (UnsupportedJwtException expected) {
assertEquals expected.message, 'Unsigned Claims JWTs are not supported.'
}
}
//Asserts correct/expected behavior discussed in https://github.com/jwtk/jjwt/issues/20
@Test
void testForgedTokenWithSwappedHeaderUsingNoneAlgorithm() {
//create random signing key for testing:
SignatureAlgorithm alg = SignatureAlgorithm.HS256
byte[] key = Keys.secretKeyFor(alg).encoded
//this is a 'real', valid JWT:
String compact = Jwts.builder().setSubject("Joe").signWith(alg, key).compact()
//Now strip off the signature so we can add it back in later on a forged token:
int i = compact.lastIndexOf('.')
String signature = compact.substring(i + 1)
//now let's create a fake header and payload with whatever we want (without signing):
String forged = Jwts.builder().setSubject("Not Joe").compact()
//assert that our forged header has a 'NONE' algorithm:
assertEquals Jwts.parser().parseClaimsJwt(forged).getHeader().get('alg'), 'none'
//now let's forge it by appending the signature the server expects:
forged += signature
//now assert that, when the server tries to parse the forged token, parsing fails:
try {
Jwts.parser().setSigningKey(key).parse(forged)
fail("Parsing must fail for a forged token.")
} catch (MalformedJwtException expected) {
assertEquals expected.message, 'JWT string has a digest/signature, but the header does not reference a valid signature algorithm.'
}
}
//Asserts correct/expected behavior discussed in https://github.com/jwtk/jjwt/issues/20 and https://github.com/jwtk/jjwt/issues/25
@Test
void testParseForgedRsaPublicKeyAsHmacTokenVerifiedWithTheRsaPrivateKey() {
//Create a legitimate RSA public and private key pair:
KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.RS256)
PublicKey publicKey = kp.getPublic()
PrivateKey privateKey = kp.getPrivate()
String header = base64Url(toJson(['alg': 'HS256']))
String body = base64Url(toJson('foo'))
String compact = header + '.' + body + '.'
// Now for the forgery: simulate an attacker using the RSA public key to sign a token, but
// using it as an HMAC signing key instead of RSA:
Mac mac = Mac.getInstance('HmacSHA256');
mac.init(new SecretKeySpec(publicKey.getEncoded(), 'HmacSHA256'));
byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII')))
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes)
//Finally, the forged token is the header + body + forged signature:
String forged = compact + encodedSignature;
// Assert that the server (that should always use the private key) does not recognized the forged token:
try {
Jwts.parser().setSigningKey(privateKey).parse(forged);
fail("Forged token must not be successfully parsed.")
} catch (UnsupportedJwtException expected) {
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
}
}
//Asserts correct behavior for https://github.com/jwtk/jjwt/issues/25
@Test
void testParseForgedRsaPublicKeyAsHmacTokenVerifiedWithTheRsaPublicKey() {
//Create a legitimate RSA public and private key pair:
KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.RS256)
PublicKey publicKey = kp.getPublic();
//PrivateKey privateKey = kp.getPrivate();
String header = base64Url(toJson(['alg': 'HS256']))
String body = base64Url(toJson('foo'))
String compact = header + '.' + body + '.'
// Now for the forgery: simulate an attacker using the RSA public key to sign a token, but
// using it as an HMAC signing key instead of RSA:
Mac mac = Mac.getInstance('HmacSHA256');
mac.init(new SecretKeySpec(publicKey.getEncoded(), 'HmacSHA256'));
byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII')))
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes);
//Finally, the forged token is the header + body + forged signature:
String forged = compact + encodedSignature;
// Assert that the parser does not recognized the forged token:
try {
Jwts.parser().setSigningKey(publicKey).parse(forged);
fail("Forged token must not be successfully parsed.")
} catch (UnsupportedJwtException expected) {
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
}
}
//Asserts correct behavior for https://github.com/jwtk/jjwt/issues/25
@Test
void testParseForgedEllipticCurvePublicKeyAsHmacToken() {
//Create a legitimate RSA public and private key pair:
KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.ES256)
PublicKey publicKey = kp.getPublic();
//PrivateKey privateKey = kp.getPrivate();
String header = base64Url(toJson(['alg': 'HS256']))
String body = base64Url(toJson('foo'))
String compact = header + '.' + body + '.'
// Now for the forgery: simulate an attacker using the Elliptic Curve public key to sign a token, but
// using it as an HMAC signing key instead of Elliptic Curve:
Mac mac = Mac.getInstance('HmacSHA256');
mac.init(new SecretKeySpec(publicKey.getEncoded(), 'HmacSHA256'));
byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII')))
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes);
//Finally, the forged token is the header + body + forged signature:
String forged = compact + encodedSignature;
// Assert that the parser does not recognized the forged token:
try {
Jwts.parser().setSigningKey(publicKey).parse(forged)
fail("Forged token must not be successfully parsed.")
} catch (UnsupportedJwtException expected) {
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
}
}
static void testRsa(SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) {
KeyPair kp = Keys.keyPairFor(alg)
PublicKey publicKey = kp.getPublic()
PrivateKey privateKey = kp.getPrivate()
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).signWith(privateKey, alg).compact()
def key = publicKey
if (verifyWithPrivateKey) {
key = privateKey
}
def token = Jwts.parser().setSigningKey(key).parse(jwt)
assert [alg: alg.name()] == token.header
//noinspection GrEqualsBetweenInconvertibleTypes
assert token.body == claims
}
static void testHmac(SignatureAlgorithm alg) {
//create random signing key for testing:
byte[] key = Keys.secretKeyFor(alg).encoded
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).signWith(alg, key).compact()
def token = Jwts.parser().setSigningKey(key).parse(jwt)
assert token.header == [alg: alg.name()]
//noinspection GrEqualsBetweenInconvertibleTypes
assert token.body == claims
}
static void testEC(SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) {
KeyPair pair = Keys.keyPairFor(alg)
PublicKey publicKey = pair.getPublic()
PrivateKey privateKey = pair.getPrivate()
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).signWith(privateKey, alg).compact()
def key = publicKey
if (verifyWithPrivateKey) {
key = privateKey
}
def token = Jwts.parser().setSigningKey(key).parse(jwt)
assert token.header == [alg: alg.name()]
//noinspection GrEqualsBetweenInconvertibleTypes
assert token.body == claims
}
}

View File

@ -55,7 +55,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload('Hello World!').signWith(SignatureAlgorithm.HS256, keyBytes).compact()
try {
Jwts.parser().setSigningKey(keyBytes).setSigningKey(key).parse(compact)
Jwts.parserBuilder().setSigningKey(keyBytes).setSigningKey(key).build().parse(compact)
fail()
} catch (IllegalStateException ise) {
assertEquals ise.getMessage(), 'A key object and key bytes cannot both be specified. Choose either.'
@ -64,12 +64,12 @@ class JwtParserTest {
@Test
void testIsSignedWithNullArgument() {
assertFalse Jwts.parser().isSigned(null)
assertFalse Jwts.parserBuilder().build().isSigned(null)
}
@Test
void testIsSignedWithJunkArgument() {
assertFalse Jwts.parser().isSigned('hello')
assertFalse Jwts.parserBuilder().build().isSigned('hello')
}
@Test
@ -80,7 +80,7 @@ class JwtParserTest {
String bad = base64Url('{"alg":"none"}') + '.' + base64Url(junkPayload) + '.'
try {
Jwts.parser().parse(bad)
Jwts.parserBuilder().build().parse(bad)
fail()
} catch (MalformedJwtException expected) {
assertEquals expected.getMessage(), 'Unable to read JSON value: ' + junkPayload
@ -101,7 +101,7 @@ class JwtParserTest {
String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig)
try {
Jwts.parser().setSigningKey(randomKey()).parse(bad)
Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad)
fail()
} catch (SignatureException se) {
assertEquals se.getMessage(), "Unsupported signature algorithm '$badAlgorithmName'".toString()
@ -120,7 +120,7 @@ class JwtParserTest {
String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig)
try {
Jwts.parser().setSigningKey(randomKey()).parse(bad)
Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad)
fail()
} catch (SignatureException se) {
assertEquals se.getMessage(), 'JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.'
@ -140,7 +140,7 @@ class JwtParserTest {
String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig)
try {
Jwts.parser().setSigningKey(randomKey()).parse(bad)
Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad)
fail()
} catch (MalformedJwtException se) {
assertEquals se.getMessage(), 'JWT string has a digest/signature, but the header does not reference a valid signature algorithm.'
@ -160,9 +160,9 @@ class JwtParserTest {
//noinspection GrDeprecatedAPIUsage
String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, base64Encodedkey).compact()
assertTrue Jwts.parser().isSigned(compact)
assertTrue Jwts.parserBuilder().build().isSigned(compact)
Jwt<Header, String> jwt = Jwts.parser().setSigningKey(base64Encodedkey).parse(compact)
Jwt<Header, String> jwt = Jwts.parserBuilder().setSigningKey(base64Encodedkey).build().parse(compact)
assertEquals jwt.body, payload
}
@ -175,7 +175,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact()
try {
Jwts.parser().parse(compact)
Jwts.parserBuilder().build().parse(compact)
fail()
} catch (ExpiredJwtException e) {
assertTrue e.getMessage().startsWith('JWT expired at ')
@ -193,7 +193,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact()
try {
Jwts.parser().parse(compact)
Jwts.parserBuilder().build().parse(compact)
fail()
} catch (PrematureJwtException e) {
assertTrue e.getMessage().startsWith('JWT must not be accepted before ')
@ -210,7 +210,7 @@ class JwtParserTest {
String subject = 'Joe'
String compact = Jwts.builder().setSubject(subject).setExpiration(exp).compact()
Jwt<Header, Claims> jwt = Jwts.parser().setAllowedClockSkewSeconds(10).parse(compact)
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setAllowedClockSkewSeconds(10).build().parse(compact)
assertEquals jwt.getBody().getSubject(), subject
}
@ -222,7 +222,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact()
try {
Jwts.parser().setAllowedClockSkewSeconds(1).parse(compact)
Jwts.parserBuilder().setAllowedClockSkewSeconds(1).build().parse(compact)
fail()
} catch (ExpiredJwtException e) {
assertTrue e.getMessage().startsWith('JWT expired at ')
@ -236,7 +236,7 @@ class JwtParserTest {
String subject = 'Joe'
String compact = Jwts.builder().setSubject(subject).setNotBefore(exp).compact()
Jwt<Header, Claims> jwt = Jwts.parser().setAllowedClockSkewSeconds(10).parse(compact)
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setAllowedClockSkewSeconds(10).build().parse(compact)
assertEquals jwt.getBody().getSubject(), subject
}
@ -248,7 +248,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setNotBefore(exp).compact()
try {
Jwts.parser().setAllowedClockSkewSeconds(1).parse(compact)
Jwts.parserBuilder().setAllowedClockSkewSeconds(1).build().parse(compact)
fail()
} catch (PrematureJwtException e) {
assertTrue e.getMessage().startsWith('JWT must not be accepted before ')
@ -266,7 +266,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).compact()
Jwt<Header, String> jwt = Jwts.parser().parsePlaintextJwt(compact)
Jwt<Header, String> jwt = Jwts.parserBuilder().build().parsePlaintextJwt(compact)
assertEquals jwt.getBody(), payload
}
@ -277,7 +277,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').compact()
try {
Jwts.parser().parsePlaintextJwt(compact)
Jwts.parserBuilder().build().parsePlaintextJwt(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Unsigned Claims JWTs are not supported.'
@ -292,7 +292,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, randomKey()).compact()
try {
Jwts.parser().parsePlaintextJws(compact)
Jwts.parserBuilder().build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Signed JWSs are not supported.'
@ -305,7 +305,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, randomKey()).compact()
try {
Jwts.parser().parsePlaintextJws(compact)
Jwts.parserBuilder().build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Signed JWSs are not supported.'
@ -323,7 +323,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(subject).compact()
Jwt<Header, Claims> jwt = Jwts.parser().parseClaimsJwt(compact)
Jwt<Header, Claims> jwt = Jwts.parserBuilder().build().parseClaimsJwt(compact)
assertEquals jwt.getBody().getSubject(), subject
}
@ -336,7 +336,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).compact()
try {
Jwts.parser().parseClaimsJwt(compact)
Jwts.parserBuilder().build().parseClaimsJwt(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Unsigned plaintext JWTs are not supported.'
@ -351,7 +351,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, randomKey()).compact()
try {
Jwts.parser().parseClaimsJwt(compact)
Jwts.parserBuilder().build().parseClaimsJwt(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Signed JWSs are not supported.'
@ -364,7 +364,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, randomKey()).compact()
try {
Jwts.parser().parseClaimsJwt(compact)
Jwts.parserBuilder().build().parseClaimsJwt(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Signed JWSs are not supported.'
@ -381,7 +381,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact()
try {
Jwts.parser().parseClaimsJwt(compact)
Jwts.parserBuilder().build().parseClaimsJwt(compact)
fail()
} catch (ExpiredJwtException e) {
assertTrue e.getMessage().startsWith('JWT expired at ')
@ -396,7 +396,9 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact()
try {
Jwts.parser().parseClaimsJwt(compact)
Jwts.parserBuilder().
build().
parseClaimsJwt(compact)
fail()
} catch (PrematureJwtException e) {
assertTrue e.getMessage().startsWith('JWT must not be accepted before ')
@ -416,7 +418,10 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, key).compact()
Jwt<Header, String> jwt = Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
Jwt<Header, String> jwt = Jwts.parserBuilder().
setSigningKey(key).
build().
parsePlaintextJws(compact)
assertEquals jwt.getBody(), payload
}
@ -431,7 +436,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).compact()
try {
Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Unsigned plaintext JWTs are not supported.'
@ -448,7 +453,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(subject).compact()
try {
Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Unsigned Claims JWTs are not supported.'
@ -465,7 +470,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact()
try {
Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Signed Claims JWSs are not supported.'
@ -485,7 +490,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(sub).signWith(SignatureAlgorithm.HS256, key).compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
assertEquals jwt.getBody().getSubject(), sub
}
@ -504,7 +509,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(sub).signWith(SignatureAlgorithm.HS256, key).setExpiration(exp).compact()
try {
Jwts.parser().setSigningKey(key).parseClaimsJwt(compact)
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJwt(compact)
fail()
} catch (ExpiredJwtException e) {
assertTrue e.getMessage().startsWith('JWT expired at ')
@ -525,7 +530,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(sub).setNotBefore(nbf).signWith(SignatureAlgorithm.HS256, key).compact()
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
fail()
} catch (PrematureJwtException e) {
assertTrue e.getMessage().startsWith('JWT must not be accepted before ')
@ -544,7 +549,7 @@ class JwtParserTest {
String compact = Jwts.builder().setPayload(payload).compact()
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Unsigned plaintext JWTs are not supported.'
@ -561,7 +566,9 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(subject).compact()
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).
build().
parseClaimsJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Unsigned Claims JWTs are not supported.'
@ -578,7 +585,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact()
try {
Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException e) {
assertEquals e.getMessage(), 'Signed Claims JWSs are not supported.'
@ -605,7 +612,7 @@ class JwtParserTest {
}
}
Jws jws = Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact)
Jws jws = Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact)
assertEquals jws.getBody().getSubject(), subject
}
@ -627,7 +634,7 @@ class JwtParserTest {
}
try {
Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact)
fail()
} catch (SignatureException se) {
assertEquals se.getMessage(), 'JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.'
@ -651,7 +658,7 @@ class JwtParserTest {
}
try {
Jwts.parser().setSigningKey(key).setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact)
fail()
} catch (IllegalStateException ise) {
assertEquals ise.getMessage(), 'A signing key resolver and a key object cannot both be specified. Choose either.'
@ -675,7 +682,7 @@ class JwtParserTest {
}
try {
Jwts.parser().setSigningKey(key).setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact)
fail()
} catch (IllegalStateException ise) {
assertEquals ise.getMessage(), 'A signing key resolver and key bytes cannot both be specified. Choose either.'
@ -692,7 +699,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact()
try {
Jwts.parser().setSigningKeyResolver(null).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKeyResolver(null).build().parseClaimsJws(compact)
fail()
} catch (IllegalArgumentException iae) {
assertEquals iae.getMessage(), 'SigningKeyResolver cannot be null.'
@ -711,7 +718,7 @@ class JwtParserTest {
def signingKeyResolver = new SigningKeyResolverAdapter()
try {
Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact)
fail()
} catch (UnsupportedJwtException ex) {
assertEquals ex.getMessage(), 'The specified SigningKeyResolver implementation does not support ' +
@ -739,7 +746,7 @@ class JwtParserTest {
claim("long_big", bigLong).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
Claims claims = jwt.getBody()
@ -770,7 +777,7 @@ class JwtParserTest {
}
}
Jws<String> jws = Jwts.parser().setSigningKeyResolver(signingKeyResolver).parsePlaintextJws(compact)
Jws<String> jws = Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parsePlaintextJws(compact)
assertEquals jws.getBody(), inputPayload
}
@ -792,7 +799,7 @@ class JwtParserTest {
}
try {
Jwts.parser().setSigningKeyResolver(signingKeyResolver).parsePlaintextJws(compact)
Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parsePlaintextJws(compact)
fail()
} catch (SignatureException se) {
assertEquals se.getMessage(), 'JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.'
@ -811,7 +818,7 @@ class JwtParserTest {
def signingKeyResolver = new SigningKeyResolverAdapter()
try {
Jwts.parser().setSigningKeyResolver(signingKeyResolver).parsePlaintextJws(compact)
Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parsePlaintextJws(compact)
fail()
} catch (UnsupportedJwtException ex) {
assertEquals ex.getMessage(), 'The specified SigningKeyResolver implementation does not support plaintext ' +
@ -831,7 +838,7 @@ class JwtParserTest {
try {
// expecting null claim name, but with value
Jwts.parser().setSigningKey(key).require(null, expectedClaimValue).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).require(null, expectedClaimValue).build().parseClaimsJws(compact)
fail()
} catch (IllegalArgumentException e) {
assertEquals(
@ -854,8 +861,9 @@ class JwtParserTest {
try {
// expecting null claim name, but with value
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
require("", expectedClaimValue).
build().
parseClaimsJws(compact)
fail()
} catch (IllegalArgumentException e) {
@ -877,8 +885,9 @@ class JwtParserTest {
try {
// expecting claim name, but with null value
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
require(expectedClaimName, null).
build().
parseClaimsJws(compact)
fail()
} catch (IllegalArgumentException e) {
@ -900,8 +909,9 @@ class JwtParserTest {
claim(expectedClaimName, expectedClaimValue).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
require(expectedClaimName, expectedClaimValue).
build().
parseClaimsJws(compact)
assertEquals jwt.getBody().get(expectedClaimName), expectedClaimValue
@ -921,8 +931,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
require(goodClaimName, goodClaimValue).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -945,8 +956,9 @@ class JwtParserTest {
compact()
try {
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
require(claimName, claimValue).
build().
parseClaimsJws(compact)
fail()
} catch (MissingClaimException e) {
@ -968,8 +980,9 @@ class JwtParserTest {
setIssuedAt(issuedAt).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireIssuedAt(issuedAt).
build().
parseClaimsJws(compact)
// system converts to seconds (lopping off millis precision), then returns millis
@ -989,8 +1002,9 @@ class JwtParserTest {
setIssuedAt(badIssuedAt).
compact()
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireIssuedAt(goodIssuedAt).
build().
parseClaimsJws(compact)
}
@ -1004,8 +1018,9 @@ class JwtParserTest {
setSubject("Dummy").
compact()
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireIssuedAt(issuedAt).
build().
parseClaimsJws(compact)
}
@ -1019,8 +1034,9 @@ class JwtParserTest {
setIssuer(issuer).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireIssuer(issuer).
build().
parseClaimsJws(compact)
assertEquals jwt.getBody().getIssuer(), issuer
@ -1038,8 +1054,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireIssuer(goodIssuer).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -1061,8 +1078,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireIssuer(issuer).
build().
parseClaimsJws(compact)
fail()
} catch (MissingClaimException e) {
@ -1083,8 +1101,9 @@ class JwtParserTest {
setAudience(audience).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireAudience(audience).
build().
parseClaimsJws(compact)
assertEquals jwt.getBody().getAudience(), audience
@ -1102,8 +1121,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireAudience(goodAudience).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -1125,8 +1145,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireAudience(audience).
build().
parseClaimsJws(compact)
fail()
} catch (MissingClaimException e) {
@ -1147,8 +1168,9 @@ class JwtParserTest {
setSubject(subject).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireSubject(subject).
build().
parseClaimsJws(compact)
assertEquals jwt.getBody().getSubject(), subject
@ -1166,8 +1188,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireSubject(goodSubject).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -1189,8 +1212,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireSubject(subject).
build().
parseClaimsJws(compact)
fail()
} catch (MissingClaimException e) {
@ -1211,8 +1235,9 @@ class JwtParserTest {
setId(id).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireId(id).
build().
parseClaimsJws(compact)
assertEquals jwt.getBody().getId(), id
@ -1230,8 +1255,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireId(goodId).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -1253,8 +1279,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireId(id).
build().
parseClaimsJws(compact)
fail()
} catch (MissingClaimException e) {
@ -1276,8 +1303,9 @@ class JwtParserTest {
setExpiration(expiration).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireExpiration(expiration).
build().
parseClaimsJws(compact)
// system converts to seconds (lopping off millis precision), then returns millis
@ -1297,8 +1325,9 @@ class JwtParserTest {
setExpiration(badExpiration).
compact()
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireExpiration(goodExpiration).
build().
parseClaimsJws(compact)
}
@ -1312,8 +1341,9 @@ class JwtParserTest {
setSubject("Dummy").
compact()
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireExpiration(expiration).
build().
parseClaimsJws(compact)
}
@ -1328,8 +1358,9 @@ class JwtParserTest {
setNotBefore(notBefore).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
requireNotBefore(notBefore).
build().
parseClaimsJws(compact)
// system converts to seconds (lopping off millis precision), then returns millis
@ -1349,8 +1380,9 @@ class JwtParserTest {
setNotBefore(badNotBefore).
compact()
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireNotBefore(goodNotBefore).
build().
parseClaimsJws(compact)
}
@ -1364,8 +1396,9 @@ class JwtParserTest {
setSubject("Dummy").
compact()
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
requireNotBefore(notBefore).
build().
parseClaimsJws(compact)
}
@ -1380,8 +1413,9 @@ class JwtParserTest {
claim("aDate", aDate).
compact()
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
Jwt<Header, Claims> jwt = Jwts.parserBuilder().setSigningKey(key).
require("aDate", aDate).
build().
parseClaimsJws(compact)
assertEquals jwt.getBody().get("aDate", Date.class), aDate
@ -1401,8 +1435,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
require("aDate", goodDate).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -1425,8 +1460,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
require("aDate", goodDate).
build().
parseClaimsJws(compact)
fail()
} catch (IncorrectClaimException e) {
@ -1448,8 +1484,9 @@ class JwtParserTest {
compact()
try {
Jwts.parser().setSigningKey(key).
Jwts.parserBuilder().setSigningKey(key).
require("aDate", aDate).
build().
parseClaimsJws(compact)
fail()
} catch (MissingClaimException e) {
@ -1468,12 +1505,12 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact()
Jwts.parser().setClock(new FixedClock(beforeExpiry)).parse(compact)
Jwts.parserBuilder().setClock(new FixedClock(beforeExpiry)).build().parse(compact)
}
@Test
void testParseClockManipulationWithNullClock() {
JwtParser parser = Jwts.parser();
JwtParserBuilder parser = Jwts.parserBuilder();
try {
parser.setClock(null)
fail()
@ -1488,7 +1525,7 @@ class JwtParserTest {
String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact()
try {
Jwts.parser().setClock(new DefaultClock()).parse(compact)
Jwts.parserBuilder().setClock(new DefaultClock()).build().parse(compact)
fail()
} catch (ExpiredJwtException e) {
assertTrue e.getMessage().startsWith('JWT expired at ')
@ -1509,7 +1546,7 @@ class JwtParserTest {
String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) + '.' + base64Url(bogus)
try {
Jwts.parser().setSigningKey(randomKey()).parse(bad)
Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad)
fail()
} catch (MalformedJwtException se) {
assertEquals 'JWT strings must contain exactly 2 period characters. Found: 3', se.message
@ -1523,7 +1560,7 @@ class JwtParserTest {
String jwtStr = '.' + base64Url(payload) + '.'
Jwt jwt = Jwts.parser().parse(jwtStr)
Jwt jwt = Jwts.parserBuilder().build().parse(jwtStr)
assertTrue jwt.header == null
assertEquals 'Joe', jwt.body.get('subject')
@ -1539,7 +1576,7 @@ class JwtParserTest {
String jwtStr = '.' + base64Url(payload) + '.' + base64Url(sig)
try {
Jwts.parser().parse(jwtStr)
Jwts.parserBuilder().build().parse(jwtStr)
fail()
} catch (MalformedJwtException se) {
assertEquals 'JWT string has a digest/signature, but the header does not reference a valid signature algorithm.', se.message
@ -1558,7 +1595,7 @@ class JwtParserTest {
String jwtStr = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(sig)
try {
Jwts.parser().parse(jwtStr)
Jwts.parserBuilder().build().parse(jwtStr)
fail()
} catch (MalformedJwtException se) {
assertEquals 'JWT string has a digest/signature, but the header does not reference a valid signature algorithm.', se.message

View File

@ -119,7 +119,7 @@ class JwtsTest {
String jwt = Jwts.builder().setClaims(claims).compact();
def token = Jwts.parser().parse(jwt);
def token = Jwts.parserBuilder().build().parse(jwt);
//noinspection GrEqualsBetweenInconvertibleTypes
assert token.body == claims
@ -127,23 +127,23 @@ class JwtsTest {
@Test(expected = IllegalArgumentException)
void testParseNull() {
Jwts.parser().parse(null)
Jwts.parserBuilder().build().parse(null)
}
@Test(expected = IllegalArgumentException)
void testParseEmptyString() {
Jwts.parser().parse('')
Jwts.parserBuilder().build().parse('')
}
@Test(expected = IllegalArgumentException)
void testParseWhitespaceString() {
Jwts.parser().parse(' ')
Jwts.parserBuilder().build().parse(' ')
}
@Test
void testParseWithNoPeriods() {
try {
Jwts.parser().parse('foo')
Jwts.parserBuilder().build().parse('foo')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT strings must contain exactly 2 period characters. Found: 0"
@ -153,7 +153,7 @@ class JwtsTest {
@Test
void testParseWithOnePeriodOnly() {
try {
Jwts.parser().parse('.')
Jwts.parserBuilder().build().parse('.')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT strings must contain exactly 2 period characters. Found: 1"
@ -163,7 +163,7 @@ class JwtsTest {
@Test
void testParseWithTwoPeriodsOnly() {
try {
Jwts.parser().parse('..')
Jwts.parserBuilder().build().parse('..')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string '..' is missing a body/payload."
@ -173,7 +173,7 @@ class JwtsTest {
@Test
void testParseWithHeaderOnly() {
try {
Jwts.parser().parse('foo..')
Jwts.parserBuilder().build().parse('foo..')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string 'foo..' is missing a body/payload."
@ -183,7 +183,7 @@ class JwtsTest {
@Test
void testParseWithSignatureOnly() {
try {
Jwts.parser().parse('..bar')
Jwts.parserBuilder().build().parse('..bar')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string '..bar' is missing a body/payload."
@ -193,7 +193,7 @@ class JwtsTest {
@Test
void testParseWithHeaderAndSignatureOnly() {
try {
Jwts.parser().parse('foo..bar')
Jwts.parserBuilder().build().parse('foo..bar')
fail()
} catch (MalformedJwtException e) {
assertEquals e.message, "JWT string 'foo..bar' is missing a body/payload."
@ -213,7 +213,7 @@ class JwtsTest {
@Test
void testConvenienceIssuer() {
String compact = Jwts.builder().setIssuer("Me").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertEquals claims.getIssuer(), "Me"
compact = Jwts.builder().setSubject("Joe")
@ -221,14 +221,14 @@ class JwtsTest {
.setIssuer(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getIssuer()
}
@Test
void testConvenienceSubject() {
String compact = Jwts.builder().setSubject("Joe").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertEquals claims.getSubject(), "Joe"
compact = Jwts.builder().setIssuer("Me")
@ -236,14 +236,14 @@ class JwtsTest {
.setSubject(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getSubject()
}
@Test
void testConvenienceAudience() {
String compact = Jwts.builder().setAudience("You").compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertEquals claims.getAudience(), "You"
compact = Jwts.builder().setIssuer("Me")
@ -251,7 +251,7 @@ class JwtsTest {
.setAudience(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getAudience()
}
@ -281,7 +281,7 @@ class JwtsTest {
void testConvenienceExpiration() {
Date then = laterDate();
String compact = Jwts.builder().setExpiration(then).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
def claimedDate = claims.getExpiration()
assertEquals claimedDate, then
@ -290,7 +290,7 @@ class JwtsTest {
.setExpiration(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getExpiration()
}
@ -298,7 +298,7 @@ class JwtsTest {
void testConvenienceNotBefore() {
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
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
def claimedDate = claims.getNotBefore()
assertEquals claimedDate, now
@ -307,7 +307,7 @@ class JwtsTest {
.setNotBefore(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getNotBefore()
}
@ -315,7 +315,7 @@ class JwtsTest {
void testConvenienceIssuedAt() {
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
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
def claimedDate = claims.getIssuedAt()
assertEquals claimedDate, now
@ -324,7 +324,7 @@ class JwtsTest {
.setIssuedAt(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getIssuedAt()
}
@ -332,7 +332,7 @@ class JwtsTest {
void testConvenienceId() {
String id = UUID.randomUUID().toString();
String compact = Jwts.builder().setId(id).compact();
Claims claims = Jwts.parser().parse(compact).body as Claims
Claims claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertEquals claims.getId(), id
compact = Jwts.builder().setIssuer("Me")
@ -340,7 +340,7 @@ class JwtsTest {
.setId(null) //null should remove it
.compact();
claims = Jwts.parser().parse(compact).body as Claims
claims = Jwts.parserBuilder().build().parse(compact).body as Claims
assertNull claims.getId()
}
@ -355,7 +355,7 @@ class JwtsTest {
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compact()
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
Claims claims = jws.body
@ -377,7 +377,7 @@ class JwtsTest {
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compressWith(CompressionCodecs.DEFLATE).compact()
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
Claims claims = jws.body
@ -399,7 +399,7 @@ class JwtsTest {
String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(alg, key)
.claim("state", "hello this is an amazing jwt").compressWith(CompressionCodecs.GZIP).compact()
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
Claims claims = jws.body
@ -426,7 +426,7 @@ class JwtsTest {
}
}).compact()
def jws = Jwts.parser().setSigningKey(key).setCompressionCodecResolver(new DefaultCompressionCodecResolver() {
def jws = Jwts.parserBuilder().setSigningKey(key).setCompressionCodecResolver(new DefaultCompressionCodecResolver() {
@Override
CompressionCodec resolveCompressionCodec(Header header) {
String algorithm = header.getCompressionAlgorithm()
@ -436,7 +436,7 @@ class JwtsTest {
return null
}
}
}).parseClaimsJws(compact)
}).build().parseClaimsJws(compact)
Claims claims = jws.body
@ -464,7 +464,7 @@ class JwtsTest {
}
}).compact()
Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
}
@Test
@ -478,7 +478,7 @@ class JwtsTest {
String compact = Jwts.builder().setPayload(payload).signWith(alg, key)
.compressWith(CompressionCodecs.DEFLATE).compact()
def jws = Jwts.parser().setSigningKey(key).parsePlaintextJws(compact)
def jws = Jwts.parserBuilder().setSigningKey(key).build().parsePlaintextJws(compact)
String parsed = jws.body
@ -582,7 +582,7 @@ class JwtsTest {
String jws = Jwts.builder().setSubject("Foo").signWith(key, alg).compact()
try {
Jwts.parser().setSigningKey(weakKey).parseClaimsJws(jws)
Jwts.parserBuilder().setSigningKey(weakKey).build().parseClaimsJws(jws)
fail('parseClaimsJws must fail for weak keys')
} catch (WeakKeyException expected) {
}
@ -599,7 +599,7 @@ class JwtsTest {
String notSigned = Jwts.builder().setSubject("Foo").compact()
try {
Jwts.parser().setSigningKey(key).parseClaimsJws(notSigned)
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(notSigned)
fail('parseClaimsJws must fail for unsigned JWTs')
} catch (UnsupportedJwtException expected) {
assertEquals expected.message, 'Unsigned Claims JWTs are not supported.'
@ -625,14 +625,14 @@ class JwtsTest {
String forged = Jwts.builder().setSubject("Not Joe").compact()
//assert that our forged header has a 'NONE' algorithm:
assertEquals Jwts.parser().parseClaimsJwt(forged).getHeader().get('alg'), 'none'
assertEquals Jwts.parserBuilder().build().parseClaimsJwt(forged).getHeader().get('alg'), 'none'
//now let's forge it by appending the signature the server expects:
forged += signature
//now assert that, when the server tries to parse the forged token, parsing fails:
try {
Jwts.parser().setSigningKey(key).parse(forged)
Jwts.parserBuilder().setSigningKey(key).build().parse(forged)
fail("Parsing must fail for a forged token.")
} catch (MalformedJwtException expected) {
assertEquals expected.message, 'JWT string has a digest/signature, but the header does not reference a valid signature algorithm.'
@ -664,7 +664,7 @@ class JwtsTest {
// Assert that the server (that should always use the private key) does not recognized the forged token:
try {
Jwts.parser().setSigningKey(privateKey).parse(forged);
Jwts.parserBuilder().setSigningKey(privateKey).build().parse(forged);
fail("Forged token must not be successfully parsed.")
} catch (UnsupportedJwtException expected) {
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
@ -696,7 +696,7 @@ class JwtsTest {
// Assert that the parser does not recognized the forged token:
try {
Jwts.parser().setSigningKey(publicKey).parse(forged);
Jwts.parserBuilder().setSigningKey(publicKey).build().parse(forged);
fail("Forged token must not be successfully parsed.")
} catch (UnsupportedJwtException expected) {
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
@ -728,7 +728,7 @@ class JwtsTest {
// Assert that the parser does not recognized the forged token:
try {
Jwts.parser().setSigningKey(publicKey).parse(forged)
Jwts.parserBuilder().setSigningKey(publicKey).build().parse(forged)
fail("Forged token must not be successfully parsed.")
} catch (UnsupportedJwtException expected) {
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
@ -750,7 +750,7 @@ class JwtsTest {
key = privateKey
}
def token = Jwts.parser().setSigningKey(key).parse(jwt)
def token = Jwts.parserBuilder().setSigningKey(key).build().parse(jwt)
assert [alg: alg.name()] == token.header
//noinspection GrEqualsBetweenInconvertibleTypes
@ -766,7 +766,7 @@ class JwtsTest {
String jwt = Jwts.builder().setClaims(claims).signWith(alg, key).compact()
def token = Jwts.parser().setSigningKey(key).parse(jwt)
def token = Jwts.parserBuilder().setSigningKey(key).build().parse(jwt)
assert token.header == [alg: alg.name()]
//noinspection GrEqualsBetweenInconvertibleTypes
@ -788,7 +788,7 @@ class JwtsTest {
key = privateKey
}
def token = Jwts.parser().setSigningKey(key).parse(jwt)
def token = Jwts.parserBuilder().setSigningKey(key).build().parse(jwt)
assert token.header == [alg: alg.name()]
//noinspection GrEqualsBetweenInconvertibleTypes

View File

@ -32,7 +32,7 @@ class RsaSigningKeyResolverAdapterTest {
def compact = Jwts.builder().claim('foo', 'bar').signWith(pair.private, alg).compact()
Jws<Claims> jws = Jwts.parser().setSigningKey(pair.public).parseClaimsJws(compact)
Jws<Claims> jws = Jwts.parserBuilder().setSigningKey(pair.public).build().parseClaimsJws(compact)
try {
new SigningKeyResolverAdapter().resolveSigningKey(jws.header, jws.body)

View File

@ -45,7 +45,7 @@ class DefaultJwsTest {
String compact = Jwts.builder().claim('foo', 'bar').signWith(alg, key).compact();
int i = compact.lastIndexOf('.')
String signature = compact.substring(i + 1)
def jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact)
def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact)
assertEquals 'header={alg=HS256},body={foo=bar},signature=' + signature, jws.toString()
}
}

View File

@ -379,7 +379,7 @@ class DefaultJwtBuilderTest {
.claim('foo', 'bar')
.compact()
assertEquals 'bar', Jwts.parser().setSigningKey(key).parseClaimsJws(jws).getBody().get('foo')
assertEquals 'bar', Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jws).getBody().get('foo')
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2019 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.impl
import com.fasterxml.jackson.databind.ObjectMapper
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.io.Decoder
import io.jsonwebtoken.io.DecodingException
import io.jsonwebtoken.io.DeserializationException
import io.jsonwebtoken.io.Deserializer
import io.jsonwebtoken.security.Keys
import org.junit.Test
import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertSame
// NOTE to the casual reader: even though this test class appears mostly empty, the DefaultJwtParserBuilder
// implementation is tested to 100% coverage. The vast majority of its tests are in the JwtsTest class. This class
// just fills in any remaining test gaps.
class DefaultJwtParserBuilderTest {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
@Test(expected = IllegalArgumentException)
void testBase64UrlDecodeWithNullArgument() {
new DefaultJwtParserBuilder().base64UrlDecodeWith(null)
}
@Test
void testBase64UrlEncodeWithCustomDecoder() {
def decoder = new Decoder() {
@Override
Object decode(Object o) throws DecodingException {
return null
}
}
def b = new DefaultJwtParserBuilder().base64UrlDecodeWith(decoder)
assertSame decoder, b.base64UrlDecoder
}
@Test(expected = IllegalArgumentException)
void testDeserializeJsonWithNullArgument() {
new DefaultJwtParserBuilder().deserializeJsonWith(null)
}
@Test
void testDesrializeJsonWithCustomSerializer() {
def deserializer = new Deserializer() {
@Override
Object deserialize(byte[] bytes) throws DeserializationException {
return OBJECT_MAPPER.readValue(bytes, Map.class)
}
}
def p = new DefaultJwtParserBuilder().deserializeJsonWith(deserializer)
assertSame deserializer, p.deserializer
def key = Keys.secretKeyFor(SignatureAlgorithm.HS256)
String jws = Jwts.builder().claim('foo', 'bar').signWith(key, SignatureAlgorithm.HS256).compact()
assertEquals 'bar', p.setSigningKey(key).build().parseClaimsJws(jws).getBody().get('foo')
}
}

View File

@ -26,7 +26,7 @@ class DefaultJwtTest {
@Test
void testToString() {
String compact = Jwts.builder().setHeaderParam('foo', 'bar').setAudience('jsmith').compact();
Jwt jwt = Jwts.parser().parseClaimsJwt(compact);
Jwt jwt = Jwts.parserBuilder().build().parseClaimsJwt(compact);
assertEquals 'header={foo=bar, alg=none},body={aud=jsmith}', jwt.toString()
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2019 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.impl
import io.jsonwebtoken.Clock
import io.jsonwebtoken.CompressionCodecResolver
import io.jsonwebtoken.JwtHandler
import io.jsonwebtoken.JwtParser
import io.jsonwebtoken.SigningKeyResolver
import io.jsonwebtoken.io.Decoder
import io.jsonwebtoken.io.Deserializer
import org.junit.Test
import java.security.Key
import static org.easymock.EasyMock.expect
import static org.easymock.EasyMock.mock
import static org.easymock.EasyMock.replay
import static org.easymock.EasyMock.verify
import static org.hamcrest.MatcherAssert.assertThat
import static org.hamcrest.CoreMatchers.is
/**
* TODO: These mutable methods will be removed pre 1.0, and ImmutableJwtParser will be replaced with the default
* JwtParser impl.
*
* @since 0.11.0
*/
class ImmutableJwtParserTest {
@Test
void parseWithHandlerTest() {
def jwtString = "j.w.t"
JwtHandler jwtHandler = mock(JwtHandler)
JwtParser jwtParser = mock(JwtParser)
Object returnValue = new Object()
expect(jwtParser.parse(jwtString, jwtHandler)).andReturn(returnValue)
replay(jwtParser)
assertThat new ImmutableJwtParser(jwtParser).parse(jwtString, jwtHandler), is(returnValue)
verify(jwtParser)
}
private ImmutableJwtParser jwtParser() {
return new ImmutableJwtParser(mock(JwtParser))
}
@Test(expected=IllegalStateException)
void requireIdTest() {
jwtParser().requireId("id")
}
@Test(expected=IllegalStateException)
void requireSubjectTest() {
jwtParser().requireSubject("subject")
}
@Test(expected=IllegalStateException)
void requireAudienceTest() {
jwtParser().requireAudience("aud")
}
@Test(expected=IllegalStateException)
void requireIssuerTest() {
jwtParser().requireIssuer("issuer")
}
@Test(expected=IllegalStateException)
void requireIssuedAtTest() {
jwtParser().requireIssuedAt(new Date())
}
@Test(expected=IllegalStateException)
void requireExpirationTest() {
jwtParser().requireExpiration(new Date())
}
@Test(expected=IllegalStateException)
void requireNotBeforeTest() {
jwtParser().requireNotBefore(new Date())
}
@Test(expected=IllegalStateException)
void requireTest() {
jwtParser().require("key", "value")
}
@Test(expected=IllegalStateException)
void setClockTest() {
jwtParser().setClock(mock((Clock)))
}
@Test(expected=IllegalStateException)
void setAllowedClockSkewSecondsTest() {
jwtParser().setAllowedClockSkewSeconds(1L)
}
@Test(expected=IllegalStateException)
void setSigningKeyBytesTest() {
jwtParser().setSigningKey("foo".getBytes())
}
@Test(expected=IllegalStateException)
void setSigningKeyStringTest() {
jwtParser().setSigningKey("foo")
}
@Test(expected=IllegalStateException)
void setSigningKey() {
jwtParser().setSigningKey(mock(Key))
}
@Test(expected=IllegalStateException)
void setSigningKeyResolverTest() {
jwtParser().setSigningKeyResolver(mock(SigningKeyResolver))
}
@Test(expected=IllegalStateException)
void setCompressionCodecResolverTest() {
jwtParser().setCompressionCodecResolver(mock(CompressionCodecResolver))
}
@Test(expected=IllegalStateException)
void base64UrlDecodeWithTest() {
jwtParser().base64UrlDecodeWith(mock(Decoder))
}
@Test(expected=IllegalStateException)
void deserializeJsonWithTest() {
jwtParser().deserializeJsonWith(mock(Deserializer))
}
}