From e09f041cf2afbf68b41be99ac4da100595d20781 Mon Sep 17 00:00:00 2001
From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com>
Date: Fri, 4 Aug 2023 16:16:08 -0700
Subject: [PATCH 1/2] - JwtParser is now immutable (no mutation methods,
`final` internal state, etc). - Jwts.parser() has been changed to return a
`JwtParserBuilder`, Jwts.parserBuilder() has been removed since it's now
superfluous. - LegacyServices.java has been deleted since DefaultJwtParser is
no longer mutable (it was used in the parse() method. This logic is now only
performed via the Services.java implementation used by the JwtParserBuilder).
- ImmutableJwtParser.java has been deleted since it was a wrapper around a
mutable DefaultJwtParser implementation. Now that DefaultJwtParser is
immutable, ImmutableJwtParser.java is no longer necessary.
---
CHANGELOG.md | 12 +-
README.md | 84 +-
.../CompressionCodecResolver.java | 2 +-
.../main/java/io/jsonwebtoken/JwtParser.java | 378 +---
.../io/jsonwebtoken/JwtParserBuilder.java | 13 +-
api/src/main/java/io/jsonwebtoken/Jwts.java | 28 +-
.../io/jsonwebtoken/SigningKeyResolver.java | 2 +-
.../jsonwebtoken/impl/DefaultJwtParser.java | 215 +--
.../impl/DefaultJwtParserBuilder.java | 31 +-
.../jsonwebtoken/impl/ImmutableJwtParser.java | 188 --
.../impl/lang/LegacyServices.java | 44 -
.../impl/security/ConstantKeyLocator.java | 15 +-
.../CustomObjectDeserializationTest.groovy | 4 +-
.../DeprecatedJwtParserTest.groovy | 1520 -----------------
.../io/jsonwebtoken/DeprecatedJwtsTest.groovy | 767 ---------
.../io/jsonwebtoken/JwtParserTest.groovy | 172 +-
.../groovy/io/jsonwebtoken/JwtsTest.groovy | 146 +-
.../RsaSigningKeyResolverAdapterTest.groovy | 2 +-
.../jsonwebtoken/impl/DefaultJweTest.groovy | 4 +-
.../jsonwebtoken/impl/DefaultJwsTest.groovy | 4 +-
.../impl/DefaultJwtBuilderTest.groovy | 6 +-
.../impl/DefaultJwtParserBuilderTest.groovy | 39 +-
.../impl/DefaultJwtParserTest.groovy | 60 +-
.../jsonwebtoken/impl/DefaultJwtTest.groovy | 8 +-
.../impl/ImmutableJwtParserTest.groovy | 141 --
.../DeflateCompressionCodecTest.groovy | 2 +-
.../impl/lang/LegacyServicesTest.groovy | 28 -
.../security/EdSignatureAlgorithmTest.groovy | 2 +-
.../impl/security/Issue542Test.groovy | 2 +-
.../security/RFC7516AppendixA1Test.groovy | 2 +-
.../security/RFC7516AppendixA2Test.groovy | 2 +-
.../security/RFC7516AppendixA3Test.groovy | 2 +-
.../impl/security/RFC7517AppendixCTest.groovy | 2 +-
.../impl/security/RFC7518AppendixCTest.groovy | 2 +-
.../impl/security/RFC7520Section4Test.groovy | 10 +-
.../impl/security/RFC7520Section5Test.groovy | 8 +-
.../impl/security/RFC8037AppendixATest.groovy | 6 +-
.../io/jsonwebtoken/all/BasicTest.groovy | 2 +-
.../io/jsonwebtoken/all/JavaReadmeTest.java | 16 +-
39 files changed, 348 insertions(+), 3623 deletions(-)
delete mode 100644 impl/src/main/java/io/jsonwebtoken/impl/ImmutableJwtParser.java
delete mode 100644 impl/src/main/java/io/jsonwebtoken/impl/lang/LegacyServices.java
delete mode 100644 impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtParserTest.groovy
delete mode 100644 impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtsTest.groovy
delete mode 100644 impl/src/test/groovy/io/jsonwebtoken/impl/ImmutableJwtParserTest.groovy
delete mode 100644 impl/src/test/groovy/io/jsonwebtoken/impl/lang/LegacyServicesTest.groovy
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7992227c0..621f4cd37 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,7 +44,7 @@ AeadAlgorithm enc = Jwts.ENC.A256GCM;
SecretKey key = enc.keyBuilder().build();
String compact = Jwts.builder().setSubject("Joe").encryptWith(key, enc).compact();
-Jwe jwe = Jwts.parserBuilder().decryptWith(key).build().parseClaimsJwe(compact);
+Jwe jwe = Jwts.parser().decryptWith(key).build().parseClaimsJwe(compact);
```
Many other RSA and Elliptic Curve examples are in the full README documentation.
@@ -179,8 +179,14 @@ deprecate some concepts, or in some cases, completely break backwards compatibil
automatically based on builder state.
-* `io.jsonwebtoken.Jwts`'s `parser()` method deprecated 4 years ago has been changed to now return a
- `JwtParserBuilder` instead of a direct `JwtParser` instance.
+* `io.jsonwebtoken.JwtParser` is now immutable. All mutation/modification methods (setters, etc) deprecated 4 years
+ ago have been removed. All parser configuration requires using the `JwtParserBuilder` (i.e.
+ `Jwts.parser()`).
+
+
+* Similarly, `io.jsonwebtoken.Jwts`'s `parser()` method deprecated 4 years ago has been changed to now return a
+ `JwtParserBuilder` instead of a direct `JwtParser` instance. The previous `Jwts.parserBuilder()` method has been
+ removed as it is now redundant.
* `io.jsonwebtoken.CompressionCodec` implementations are no longer discoverable via `java.util.ServiceLoader` due to
diff --git a/README.md b/README.md
index 70d2e1c75..1a08a672b 100644
--- a/README.md
+++ b/README.md
@@ -719,7 +719,7 @@ eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60A
Now let's verify the JWT (you should always discard JWTs that don't match an expected signature):
```java
-assert Jwts.parserBuilder().verifyWith(key).build().parseClaimsJws(jws).getPayload().getSubject().equals("Joe");
+assert Jwts.parser().verifyWith(key).build().parseClaimsJws(jws).getPayload().getSubject().equals("Joe");
```
There are two things going on here. The `key` from before is being used to verify the signature of the JWT. If it
@@ -737,7 +737,7 @@ But what if parsing or signature validation failed? You can catch `JwtException
```java
try {
- Jwts.parserBuilder().verifyWith(key).build().parseClaimsJws(compactJws);
+ Jwts.parser().verifyWith(key).build().parseClaimsJws(compactJws);
//OK, we can trust this JWT
@@ -957,7 +957,7 @@ String jws = Jwts.builder()
.setExpiration(expiration) //a java.util.Date
.setNotBefore(notBefore) //a java.util.Date
.setIssuedAt(new Date()) // for example, now
- .setId(UUID.randomUUID()) //just an example id
+ .setId(UUID.randomUUID().toString()) //just an example id
/// ... etc ...
```
@@ -1047,7 +1047,7 @@ Please see the main [Compression](#compression) section to see how to compress a
You read (parse) a JWT as follows:
-1. Use the `Jwts.parserBuilder()` method to create a `JwtParserBuilder` instance.
+1. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance.
2. Optionally call `setKeyLocator`, `verifyWith` or `decryptWith` methods if you expect to parse [signed](#jws) or [encrypted](#jwe) JWTs.
3. Call the `build()` method on the `JwtParserBuilder` to create and return a thread-safe `JwtParser`.
4. Call one of the various `parse*` methods with your compact JWT string, depending on the type of JWT you expect.
@@ -1059,7 +1059,7 @@ For example:
Jwt,?> jwt;
try {
- jwt = Jwts.parserBuilder() // (1)
+ jwt = Jwts.parser() // (1)
.setKeyLocator(keyLocator) // (2) dynamically locate signing or encryption keys
//.verifyWith(key) // or a static key used to verify all signed JWTs
@@ -1099,7 +1099,7 @@ So which key do we use?
`JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.verifyWith(secretKey) // <----
@@ -1110,7 +1110,7 @@ So which key do we use?
`PrivateKey`) should be specified on the `JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.verifyWith(publicKey) // <---- publicKey, not privateKey
@@ -1121,7 +1121,7 @@ So which key do we use?
specified on the `JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.decryptWith(secretKey) // <----
@@ -1132,7 +1132,7 @@ So which key do we use?
`PrivateKey` (not the `PublicKey`) should be specified on the `JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.decryptWith(privateKey) // <---- privateKey, not publicKey
@@ -1172,7 +1172,7 @@ example:
```java
Locator keyLocator = getMyKeyLocator();
-Jwts.parserBuilder()
+Jwts.parser()
.setKeyLocator(keyLocator) // <----
@@ -1214,10 +1214,10 @@ String keyId = getKeyId(key); //any mechanism you have to associate a key with a
String jws = Jwts.builder()
- .setHeader(Jwts.headerBuilder().setKeyId(keyId)) // <--- add `kid` header
+ .header().setKeyId(keyId).and() // <--- add `kid` header
- .signWith(key) // for JWS
- //.encryptWith(key, keyAlg, encryptionAlg) // for JWE
+ .signWith(key) // for JWS
+ //.encryptWith(key, keyAlg, encryptionAlg) // for JWE
.compact();
```
@@ -1300,7 +1300,7 @@ otherwise you may not trust the token. You can do that by using one of the vari
```java
try {
- Jwts.parserBuilder().requireSubject("jsmith")/* etc... */.build().parse(s);
+ Jwts.parser().requireSubject("jsmith")/* etc... */.build().parse(s);
} catch (InvalidClaimException ice) {
// the sub field was missing or did not have a 'jsmith' value
}
@@ -1311,7 +1311,7 @@ you can catch either `MissingClaimException` or `IncorrectClaimException`:
```java
try {
- Jwts.parserBuilder().requireSubject("jsmith")/* etc... */.build().parse(s);
+ Jwts.parser().requireSubject("jsmith")/* etc... */.build().parse(s);
} catch(MissingClaimException mce) {
// the parsed JWT did not have the sub field
} catch(IncorrectClaimException ice) {
@@ -1323,7 +1323,7 @@ You can also require custom fields by using the `require(fieldName, requiredFiel
```java
try {
- Jwts.parserBuilder().require("myfield", "myRequiredValue")/* etc... */.build().parse(s);
+ Jwts.parser().require("myfield", "myRequiredValue")/* etc... */.build().parse(s);
} catch(InvalidClaimException ice) {
// the 'myfield' field was missing or did not have a 'myRequiredValue' value
}
@@ -1347,7 +1347,7 @@ You can account for these differences (usually no more than a few minutes) when
```java
long seconds = 3 * 60; //3 minutes
-Jwts.parserBuilder()
+Jwts.parser()
.setAllowedClockSkewSeconds(seconds) // <----
@@ -1369,7 +1369,7 @@ during parsing for timestamp comparisons can be obtained via a custom time sourc
```java
Clock clock = new MyClock();
-Jwts.parserBuilder().setClock(myClock) //... etc ...
+Jwts.parser().setClock(myClock) //... etc ...
```
The `JwtParser`'s default `Clock` implementation simply returns `new Date()` to reflect the time when parsing occurs,
@@ -1692,7 +1692,7 @@ Please see the main [Compression](#compression) section to see how to compress a
You read (parse) a JWS as follows:
-1. Use the `Jwts.parserBuilder()` method to create a `JwtParserBuilder` instance.
+1. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance.
2. Call either [setKeyLocator](#key-locator) or `verifyWith` methods to determine the key used to verify the JWS signature.
3. Call the `build()` method on the `JwtParserBuilder` to return a thread-safe `JwtParser`.
4. Finally, call the `parseClaimsJws(String)` method with your jws `String`, producing the original JWS.
@@ -1705,7 +1705,7 @@ For example:
Jws jws;
try {
- jws = Jwts.parserBuilder() // (1)
+ jws = Jwts.parser() // (1)
.setKeyLocator(keyLocator) // (2) dynamically lookup verification keys based on each JWS
//.verifyWith(key) // or a static key used to verify all encountered JWSs
@@ -1740,7 +1740,7 @@ So which key do we use for verification?
For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.verifyWith(secretKey) // <----
@@ -1751,7 +1751,7 @@ For example:
specified on the `JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.verifyWith(publicKey) // <---- publicKey, not privateKey
@@ -2166,7 +2166,7 @@ its size. Please see the main [Compression](#compression) section to see how to
You read (parse) a JWE as follows:
-1. Use the `Jwts.parserBuilder()` method to create a `JwtParserBuilder` instance.
+1. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance.
2. Call either [setKeyLocator](#key-locator) or `decryptWith` methods to determine the key used to decrypt the JWE.
4. Call the `JwtParserBuilder`'s `build()` method to create a thread-safe `JwtParser`.
5. Parse the jwe string with the `JwtParser`'s `parseClaimsJwe` or `parseContentJwe` method.
@@ -2178,7 +2178,7 @@ For example:
Jwe jwe;
try {
- jwe = Jwts.parserBuilder() // (1)
+ jwe = Jwts.parser() // (1)
.setKeyLocator(keyLocator) // (2) dynamically lookup decryption keys based on each JWE
//.decryptWith(key) // or a static key used to decrypt all encountered JWEs
@@ -2212,7 +2212,7 @@ So which key do we use for decryption?
`JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.decryptWith(secretKey) // <----
@@ -2223,7 +2223,7 @@ So which key do we use for decryption?
`Password` must be specified on the `JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.decryptWith(password) // <---- an `io.jsonwebtoken.security.Password` instance
@@ -2234,7 +2234,7 @@ So which key do we use for decryption?
the `PublicKey`) must be specified on the `JwtParserBuilder`. For example:
```java
- Jwts.parserBuilder()
+ Jwts.parser()
.decryptWith(privateKey) // <---- a `PrivateKey`, not a `PublicKey`
@@ -2583,7 +2583,7 @@ by calling the `JwtParserBuilder`'s `addCompressionCodecs` method. For example:
```java
CompressionCodec myCodec = new MyCompressionCodec();
-Jwts.parserBuilder()
+Jwts.parser()
.addCompressionCodecs(Collections.of(myCodec)) // <----
@@ -2629,7 +2629,7 @@ You then provide your custom `Locator` to the `JwtParserBuilde
```java
Locator myCodecLocator = new MyCompressionCodecLocator();
-Jwts.parserBuilder()
+Jwts.parser()
.setCompressionCodecLocator(myCodecLocator) // <----
@@ -2694,7 +2694,7 @@ When reading a JWT:
```java
Deserializer
*
* @see JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver)
* @see JwtParserBuilder#addCompressionAlgorithms(Collection)
diff --git a/api/src/main/java/io/jsonwebtoken/JwtParser.java b/api/src/main/java/io/jsonwebtoken/JwtParser.java
index 5499701ae..3efc658ba 100644
--- a/api/src/main/java/io/jsonwebtoken/JwtParser.java
+++ b/api/src/main/java/io/jsonwebtoken/JwtParser.java
@@ -15,392 +15,16 @@
*/
package io.jsonwebtoken;
-import io.jsonwebtoken.io.Decoder;
-import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.security.SecurityException;
import io.jsonwebtoken.security.SignatureException;
-import java.security.Key;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Map;
-
/**
* A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
*
* @since 0.1
*/
-@SuppressWarnings("DeprecatedIsStillUsed")
public interface JwtParser {
- /**
- * Deprecated - this was an implementation detail accidentally added to the public interface. This
- * will be removed in a future release.
- *
- * @deprecated since JJWT_RELEASE_VERSION, to be removed in a future relase.
- */
- @Deprecated
- char SEPARATOR_CHAR = '.';
-
- /**
- * 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 the {@code jti} value that must exist in the parsed JWT.
- * @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.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the {@code sub} value that must exist in the parsed JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the {@code aud} value that must exist in the parsed JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the {@code iss} value that must exist in the parsed JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the {@code iat} value that must exist in the parsed JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the {@code exp} value that must exist in the parsed JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the {@code nbf} value that must exist in the parsed JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 the name of a claim that must exist in the parsed JWT.
- * @param value the value that must exist for the specified {@code claimName} in the JWT.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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 for method chaining.
- * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as
- * any such value would cause numeric overflow when multiplying by 1000 to obtain a millisecond value.
- * @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.
- *
NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
-
- /**
- * Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
- * a JWS (no signature), this key is not used.
- *
- *
Note that this key MUST be a valid key for the signature algorithm found in the JWT header
- * (as the {@code alg} header parameter).
- *
- * This method overwrites any previously set key.
- *
- * @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
- * signature.
- * @return the parser for method chaining.
- * @deprecated in favor of {@link JwtParserBuilder#verifyWith(Key)}.
- * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
- * immutable JwtParser.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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.
- *
- *
Note that this key MUST be a valid key for the signature algorithm found in the JWT header
- * (as the {@code alg} header parameter).
- *
- * This method overwrites any previously set key.
- *
- * 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[])}.
- *
- * Deprecation Notice: Deprecated as of 0.10.0, will be removed in 1.0.0
- *
- * 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.
- *
- * This method always expected a String argument that was effectively the same as the result of the following
- * (pseudocode):
- *
- * {@code String base64EncodedSecretKey = base64Encode(secretKeyBytes);}
- *
- * 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.
- *
- * See this
- *
- * StackOverflow answer explaining why raw (non-base64-encoded) strings are almost always incorrect for
- * signature operations.
- *
- * 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.
- *
- * @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 in favor of {@link JwtParserBuilder#verifyWith(Key)}.
- * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
- * immutable JwtParser.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser 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.
- *
- *
Note that this key MUST be a valid key for the signature algorithm found in the JWT header
- * (as the {@code alg} header parameter).
- *
- * This method overwrites any previously set key.
- *
- * @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
- * signature.
- * @return the parser for method chaining.
- * @deprecated in favor of {@link JwtParserBuilder#verifyWith(Key)}.
- * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
- * immutable JwtParser.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser setSigningKey(Key key);
-
- /**
- * Sets the {@link SigningKeyResolver} used to acquire the signing key
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.
- *
- *
Specifying a {@code SigningKeyResolver} is necessary when the signing key is not already known before parsing
- * the JWT and the JWT header or payload (content byte array 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:
- *
- *
- * 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);
- *
- *
- * A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.
- *
- * This method should only be used if a signing key is not provided by the other {@code setSigningKey*} builder
- * methods.
- *
- * @param signingKeyResolver the signing key resolver used to retrieve the signing key.
- * @return the parser for method chaining.
- * @since 0.4
- * @deprecated in favor of {@link JwtParserBuilder#setKeyLocator(Locator)}.
- * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
- * immutable JwtParser.
- * NOTE: this method will be removed before version 1.0
- */
- @SuppressWarnings("DeprecatedIsStillUsed")
- @Deprecated
- // TODO: remove for 1.0
- JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
-
- /**
- * Sets the {@link CompressionCodecResolver} used to acquire the {@link CompressionCodec} that should be used to
- * decompress the JWT payload. If the parsed JWT is not compressed, this resolver is not used.
- *
- *
NOTE: Compression is not defined by the JWS Specification - only the JWE Specification - and it is
- * not expected that other libraries (including JJWT versions < 0.6.0) are able to consume a compressed JWS
- * payload 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.
- *
- * Default Support
- *
- * JJWT's default {@link JwtParser} implementation supports both the {@link Jwts.ZIP#DEF DEFLATE}
- * and {@link Jwts.ZIP#GZIP GZIP} algorithms by default - you do not need to
- * specify a {@code CompressionCodecResolver} in these cases.
- * However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you may implement
- * your own {@link CompressionCodecResolver} and specify that via this method and also when
- * {@link io.jsonwebtoken.JwtBuilder#compressWith(io.jsonwebtoken.io.CompressionAlgorithm) building} JWTs.
- *
- * @param compressionCodecResolver the compression codec resolver used to decompress the JWT payload.
- * @return the parser for method chaining.
- * @since 0.6.0
- * @deprecated since JJWT_RELEASE_VERSION in favor of {@link JwtParserBuilder#addCompressionAlgorithms(Collection)}.
- * To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
- * immutable JwtParser.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
-
- /**
- * Perform Base64Url decoding with the specified Decoder
- *
- *
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.
- *
- * @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.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser base64UrlDecodeWith(Decoder 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.
- *
- * 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.
- *
- * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
- * @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.
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- JwtParser deserializeJsonWith(Deserializer
*
*
- * Jws<Claims> jws = Jwts.parserBuilder().setKeyLocator(new Locator<Key>() {
+ * Jws<Claims> jws = Jwts.parser().setKeyLocator(new Locator<Key>() {
* @Override
* public Key locate(Header<?> header) {
* if (header instanceof JwsHeader) {
@@ -412,7 +413,7 @@ public interface JwtParserBuilder extends Builder {
* //inspect the header or claims, lookup and return the signing key
* return getSigningKey(header, claims); //implement me
* }})
- * .parseClaimsJws(compact);
+ * .build().parseClaimsJws(compact);
*
*
* A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.
diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java
index 5d4c3e244..8c1ca43ac 100644
--- a/api/src/main/java/io/jsonwebtoken/Jwts.java
+++ b/api/src/main/java/io/jsonwebtoken/Jwts.java
@@ -1056,38 +1056,12 @@ public static Claims claims(Map claims) {
return claims().set(claims).build();
}
- /**
- * 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.
- * Migration to new method structure is minimal, for example:
- *
Old code:
- *
{@code
- * Jwts.parser()
- * .requireAudience("string")
- * .parse(jwtString)
- * }
- * New code:
- *
{@code
- * Jwts.parserBuilder()
- * .requireAudience("string")
- * .build()
- * .parse(jwtString)
- * }
- * NOTE: this method will be removed before version 1.0
- */
- @Deprecated
- public static JwtParser parser() {
- return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParser");
- }
-
/**
* Returns a new {@link JwtParserBuilder} instance that can be configured to create an immutable/thread-safe {@link JwtParser}.
*
* @return a new {@link JwtParser} instance that can be configured create an immutable/thread-safe {@link JwtParser}.
*/
- public static JwtParserBuilder parserBuilder() {
+ public static JwtParserBuilder parser() {
return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder");
}
diff --git a/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java b/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java
index 33f642be1..eb78e008d 100644
--- a/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java
+++ b/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java
@@ -33,7 +33,7 @@
* //inspect the header or claims, lookup and return the signing key
* return getSigningKeyBytes(header, claims); //implement me
* }})
- * .parseClaimsJws(compact);
+ * .build().parseClaimsJws(compact);
*
*
*
A {@code SigningKeyResolver} is invoked once during parsing before the signature is verified.
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
index 1a256cdfd..50c6ea6b9 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
@@ -40,21 +40,17 @@
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.impl.lang.Function;
-import io.jsonwebtoken.impl.lang.LegacyServices;
-import io.jsonwebtoken.impl.security.ConstantKeyLocator;
import io.jsonwebtoken.impl.security.DefaultAeadResult;
import io.jsonwebtoken.impl.security.DefaultDecryptionKeyRequest;
import io.jsonwebtoken.impl.security.DefaultVerifySecureDigestRequest;
import io.jsonwebtoken.impl.security.LocatingKeyResolver;
import io.jsonwebtoken.io.CompressionAlgorithm;
import io.jsonwebtoken.io.Decoder;
-import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.DecodingException;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Arrays;
import io.jsonwebtoken.lang.Assert;
-import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.DateFormats;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.AeadAlgorithm;
@@ -62,7 +58,6 @@
import io.jsonwebtoken.security.DecryptionKeyRequest;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeyAlgorithm;
-import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.Message;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import io.jsonwebtoken.security.SignatureException;
@@ -82,8 +77,6 @@ public class DefaultJwtParser implements JwtParser {
static final char SEPARATOR_CHAR = '.';
- private static final int MILLISECONDS_PER_SECOND = 1000;
-
private static final JwtTokenizer jwtTokenizer = new JwtTokenizer();
public static final String INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was: %s.";
@@ -131,68 +124,34 @@ public class DefaultJwtParser implements JwtParser {
"enableUnsecuredDecompression() method (but please read the security considerations covered in that " +
"method's JavaDoc before doing so).";
- private static Function> sigFn(Collection> extras) {
- return new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.SIG.get(), extras, MISSING_JWS_ALG_MSG);
- }
-
- private static Function encFn(Collection extras) {
- return new IdLocator<>(DefaultJweHeader.ENCRYPTION_ALGORITHM, Jwts.ENC.get(), extras, MISSING_ENC_MSG);
- }
-
- private static Function> keyFn(Collection> extras) {
- return new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.KEY.get(), extras, MISSING_JWE_ALG_MSG);
- }
-
- private static IdLocator zipFn(Collection extras) {
- return new IdLocator<>(DefaultHeader.COMPRESSION_ALGORITHM, Jwts.ZIP.get(), extras, null);
- }
-
- // TODO: make the following fields final for v1.0
- private Provider provider;
+ private final Provider provider;
- @SuppressWarnings("deprecation") // will remove for 1.0
- private SigningKeyResolver signingKeyResolver;
+ @SuppressWarnings("deprecation")
+ private final SigningKeyResolver signingKeyResolver;
private final boolean enableUnsecuredJws;
private final boolean enableUnsecuredDecompression;
- private final Function> signatureAlgorithmLocator;
+ private final Function> sigAlgFn;
- private final Function encryptionAlgorithmLocator;
+ private final Function encAlgFn;
- private final Function> keyAlgorithmLocator;
+ private final Function> keyAlgFn;
- private Function compressionAlgorithmLocator;
+ private final Function zipAlgFn;
private final Locator extends Key> keyLocator;
- private Decoder base64UrlDecoder = Decoders.BASE64URL;
+ private final Decoder base64UrlDecoder;
- private Deserializer