mirror of https://github.com/jwtk/jjwt.git
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:
parent
a236656c00
commit
94d151129d
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -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.
|
||||
|
|
17
api/pom.xml
17
api/pom.xml
|
@ -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>
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<Claims> jws = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
|
||||
* @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 < 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 >= 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();
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue