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> deserializer = getMyDeserializer(); //implement me -Jwts.parserBuilder() +Jwts.parser() .deserializeJsonWith(deserializer) @@ -2754,7 +2754,7 @@ and the `JacksonDeserializer` using your `ObjectMapper` on the `JwtParserBuilder ```java ObjectMapper objectMapper = getMyObjectMapper(); //implement me -Jwts.parserBuilder() +Jwts.parser() .deserializeJsonWith(new JacksonDeserializer(objectMapper)) @@ -2786,7 +2786,7 @@ payload of: The `User` object could be retrieved from the `user` claim with the following code: ```java -Jwts.parserBuilder() +Jwts.parser() .deserializeJsonWith(new JacksonDeserializer(Maps.of("user", User.class).build())) // <----- @@ -3027,7 +3027,7 @@ and the `JwtParserBuilder`'s `base64UrlDecodeWith` method to set the decoder: ```java Decoder base64UrlDecoder = getMyBase64UrlDecoder(); //implement me -Jwts.parserBuilder() +Jwts.parser() .base64UrlDecodeWith(base64UrlEncoder) @@ -3078,7 +3078,7 @@ byte[] content = message.getBytes(StandardCharsets.UTF_8); String jws = Jwts.builder().setContent(content, "text/plain").signWith(key, alg).compact(); // Parse the compact JWS: -content = Jwts.parserBuilder().verifyWith(key).build().parseContentJws(jws).getPayload(); +content = Jwts.parser().verifyWith(key).build().parseContentJws(jws).getPayload(); assert message.equals(new String(content, StandardCharsets.UTF_8)); ``` @@ -3104,7 +3104,7 @@ String jws = Jwts.builder().setSubject("Alice") .compact(); // Alice receives and verifies the compact JWS came from Bob: -String subject = Jwts.parserBuilder() +String subject = Jwts.parser() .verifyWith(pair.getPublic()) // <-- Bob's RSA public key .build().parseClaimsJws(jws).getPayload().getSubject(); @@ -3135,7 +3135,7 @@ String jws = Jwts.builder().setSubject("Alice") .compact(); // Alice receives and verifies the compact JWS came from Bob: -String subject = Jwts.parserBuilder() +String subject = Jwts.parser() .verifyWith(pair.getPublic()) // <-- Bob's EC public key .build().parseClaimsJws(jws).getPayload().getSubject(); @@ -3179,7 +3179,7 @@ String jws = Jwts.builder().setSubject("Alice") .compact(); // Alice receives and verifies the compact JWS came from Bob: -String subject = Jwts.parserBuilder() +String subject = Jwts.parser() .verifyWith(pair.getPublic()) // <-- Bob's Edwards Curve public key .build().parseClaimsJws(jws).getPayload().getSubject(); @@ -3220,7 +3220,7 @@ byte[] content = message.getBytes(StandardCharsets.UTF_8); String jwe = Jwts.builder().setContent(content, "text/plain").encryptWith(key, enc).compact(); // Parse the compact JWE: -content = Jwts.parserBuilder().decryptWith(key).build().parseContentJwe(jwe).getPayload(); +content = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe).getPayload(); assert message.equals(new String(content, StandardCharsets.UTF_8)); ``` @@ -3252,7 +3252,7 @@ String jwe = Jwts.builder().setAudience("Alice") .compact(); // Alice receives and decrypts the compact JWE: -String audience = Jwts.parserBuilder() +String audience = Jwts.parser() .decryptWith(pair.getPrivate()) // <-- Alice's RSA private key .build().parseClaimsJwe(jwe).getPayload().getAudience(); @@ -3285,7 +3285,7 @@ AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc. String jwe = Jwts.builder().setIssuer("me").encryptWith(key, alg, enc).compact(); // Parse the compact JWE: -String issuer = Jwts.parserBuilder().decryptWith(key).build() +String issuer = Jwts.parser().decryptWith(key).build() .parseClaimsJwe(jwe).getPayload().getIssuer(); assert "me".equals(issuer); @@ -3320,7 +3320,7 @@ String jwe = Jwts.builder().setAudience("Alice") .compact(); // Alice receives and decrypts the compact JWE: -String audience = Jwts.parserBuilder() +String audience = Jwts.parser() .decryptWith(pair.getPrivate()) // <-- Alice's EC private key .build().parseClaimsJwe(jwe).getPayload().getAudience(); @@ -3367,7 +3367,7 @@ String jwe = Jwts.builder().setIssuer("me") .compact(); // Parse the compact JWE: -String issuer = Jwts.parserBuilder().decryptWith(password) +String issuer = Jwts.parser().decryptWith(password) .build().parseClaimsJwe(jwe).getPayload().getIssuer(); assert "me".equals(issuer); diff --git a/api/src/main/java/io/jsonwebtoken/CompressionCodecResolver.java b/api/src/main/java/io/jsonwebtoken/CompressionCodecResolver.java index ce9fb5160..07d6f1983 100644 --- a/api/src/main/java/io/jsonwebtoken/CompressionCodecResolver.java +++ b/api/src/main/java/io/jsonwebtoken/CompressionCodecResolver.java @@ -28,7 +28,7 @@ *

However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you can implement * your own {@link CompressionCodecResolver} and specify that when * {@link io.jsonwebtoken.JwtBuilder#compressWith(io.jsonwebtoken.io.CompressionAlgorithm) building} and - * {@link io.jsonwebtoken.JwtParser#setCompressionCodecResolver(CompressionCodecResolver) parsing} JWTs.

+ * {@link io.jsonwebtoken.JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver) parsing} JWTs.

* * @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> deserializer); - /** * Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false} * otherwise. @@ -455,7 +79,7 @@ public interface JwtParser { *

      * String compactJwt = request.getParameter("jwt"); //we are confident this is a signed JWS
      *
-     * String subject = Jwts.parser().setSigningKey(key).parse(compactJwt, new JwtHandlerAdapter<String>() {
+     * String subject = Jwts.parser().verifyWith(key).build().parse(compactJwt, new JwtHandlerAdapter<String>() {
      *     @Override
      *     public String onClaimsJws(Jws<Claims> jws) {
      *         return jws.getBody().getSubject();
diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java
index b2b8de3b6..eadf800ea 100644
--- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java
@@ -32,7 +32,7 @@
 /**
  * A builder to construct a {@link JwtParser}. Example usage:
  * 
{@code
- *     Jwts.parserBuilder()
+ *     Jwts.parser()
  *         .requireIssuer("https://issuer.example.com")
  *         .verifyWith(...)
  *         .build()
@@ -331,8 +331,9 @@ public interface JwtParserBuilder extends Builder {
     JwtParserBuilder verifyWith(Key key);
 
     /**
-     * Sets the decryption key to be used to decrypt all encountered JWEs.  If the encountered JWT string is not a
-     * JWE (e.g. a JWS), this key is not used.
+     * Sets the decryption key used to decrypt all encountered JWEs, overwriting any previously configured
+     * {@link #setKeyLocator(Locator) keyLocator}. If the encountered JWT string is not a JWE (e.g. a JWS),
+     * this key is not used.
      *
      * 

This is a convenience method to use in specific circumstances: when the parser will only ever encounter * JWEs that can always be decrypted by a single key. This also implies that this key MUST be a valid @@ -342,7 +343,7 @@ public interface JwtParserBuilder extends Builder { *

If there is any chance that the parser will encounter JWEs that need different decryption keys based on the * JWE being parsed, or JWSs, it is strongly recommended to configure * your own {@link Locator Locator} via the {@link #setKeyLocator(Locator) setKeyLocator} method instead of - * using this one.

+ * using {@code decryptWith}.

* *

Calling this method overrides any previously set decryption key.

* @@ -366,7 +367,7 @@ public interface JwtParserBuilder extends Builder { * verify the JWS signature or decrypt the JWE payload with the returned key. For example:

* *
-     * 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 keyLocator; - private Decoder base64UrlDecoder = Decoders.BASE64URL; + private final Decoder base64UrlDecoder; - private Deserializer> deserializer; + private final Deserializer> deserializer; - private ClaimsBuilder expectedClaims = Jwts.claims(); + private final ClaimsBuilder expectedClaims; - private Clock clock = DefaultClock.INSTANCE; + private final Clock clock; - private long allowedClockSkewMillis = 0; - - /** - * TODO: remove this constructor before 1.0 - * - * @deprecated for backward compatibility only, see other constructors. - */ - @SuppressWarnings("DeprecatedIsStillUsed") // will remove before 1.0 - @Deprecated - public DefaultJwtParser() { - this.keyLocator = new ConstantKeyLocator(null, null); - this.signatureAlgorithmLocator = sigFn(Collections.>emptyList()); - this.keyAlgorithmLocator = keyFn(Collections.>emptyList()); - this.encryptionAlgorithmLocator = encFn(Collections.emptyList()); - this.compressionAlgorithmLocator = zipFn(Collections.emptyList()); - this.enableUnsecuredJws = false; - this.enableUnsecuredDecompression = false; - } + private final long allowedClockSkewMillis; //SigningKeyResolver will be removed for 1.0: @SuppressWarnings("deprecation") @@ -216,134 +175,17 @@ public DefaultJwtParser() { this.enableUnsecuredDecompression = enableUnsecuredDecompression; this.signingKeyResolver = signingKeyResolver; this.keyLocator = Assert.notNull(keyLocator, "Key Locator cannot be null."); - this.clock = clock; + this.clock = Assert.notNull(clock, "Clock cannot be null."); this.allowedClockSkewMillis = allowedClockSkewMillis; this.expectedClaims = Jwts.claims().set(expectedClaims); - this.base64UrlDecoder = base64UrlDecoder; - this.deserializer = deserializer; - this.signatureAlgorithmLocator = sigFn(extraSigAlgs); - this.keyAlgorithmLocator = keyFn(extraKeyAlgs); - this.encryptionAlgorithmLocator = encFn(extraEncAlgs); - - if (compressionCodecResolver != null) { - this.compressionAlgorithmLocator = new CompressionCodecLocator(compressionCodecResolver); - } else { - this.compressionAlgorithmLocator = zipFn(extraZipAlgs); - } - } + this.base64UrlDecoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); + this.deserializer = Assert.notNull(deserializer, "Deserializer cannot be null."); - @Override - public JwtParser deserializeJsonWith(Deserializer> deserializer) { - Assert.notNull(deserializer, "deserializer cannot be null."); - this.deserializer = new JwtDeserializer<>(deserializer); - return this; - } - - @Override - public JwtParser base64UrlDecodeWith(Decoder base64UrlDecoder) { - Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); - this.base64UrlDecoder = base64UrlDecoder; - return this; - } - - @Override - public JwtParser requireIssuedAt(Date issuedAt) { - expectedClaims.setIssuedAt(issuedAt); - return this; - } - - @Override - public JwtParser requireIssuer(String issuer) { - expectedClaims.setIssuer(issuer); - return this; - } - - @Override - public JwtParser requireAudience(String audience) { - expectedClaims.setAudience(audience); - return this; - } - - @Override - public JwtParser requireSubject(String subject) { - expectedClaims.setSubject(subject); - return this; - } - - @Override - public JwtParser requireId(String id) { - expectedClaims.setId(id); - return this; - } - - @Override - public JwtParser requireExpiration(Date expiration) { - expectedClaims.setExpiration(expiration); - return this; - } - - @Override - public JwtParser requireNotBefore(Date notBefore) { - expectedClaims.setNotBefore(notBefore); - return this; - } - - @Override - public JwtParser 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.set(claimName, value); - return this; - } - - @Override - public JwtParser setClock(Clock clock) { - Assert.notNull(clock, "Clock instance cannot be null."); - this.clock = clock; - return this; - } - - @Override - public JwtParser setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException { - Assert.isTrue(seconds <= DefaultJwtParserBuilder.MAX_CLOCK_SKEW_MILLIS, DefaultJwtParserBuilder.MAX_CLOCK_SKEW_ILLEGAL_MSG); - this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND); - return this; - } - - @Override - public JwtParser setSigningKey(byte[] key) { - Assert.notEmpty(key, "signing key cannot be null or empty."); - return setSigningKey(Keys.hmacShaKeyFor(key)); - } - - @Override - public JwtParser setSigningKey(String base64EncodedSecretKey) { - Assert.hasText(base64EncodedSecretKey, "signing key cannot be null or empty."); - byte[] bytes = Decoders.BASE64.decode(base64EncodedSecretKey); - return setSigningKey(bytes); - } - - @Override - public JwtParser setSigningKey(final Key key) { - Assert.notNull(key, "signing key cannot be null."); - setSigningKeyResolver(new ConstantKeyLocator(key, null)); - return this; - } - - @SuppressWarnings("deprecation") // required until 1.0 - @Override - public JwtParser setSigningKeyResolver(SigningKeyResolver signingKeyResolver) { - Assert.notNull(signingKeyResolver, "SigningKeyResolver cannot be null."); - this.signingKeyResolver = signingKeyResolver; - return this; - } - - @SuppressWarnings("deprecation") - @Override - public JwtParser setCompressionCodecResolver(CompressionCodecResolver resolver) { - Assert.notNull(resolver, "CompressionCodecResolver cannot be null."); - this.compressionAlgorithmLocator = new CompressionCodecLocator(resolver); - return this; + this.sigAlgFn = new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.SIG.get(), extraSigAlgs, MISSING_JWS_ALG_MSG); + this.keyAlgFn = new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.KEY.get(), extraKeyAlgs, MISSING_JWE_ALG_MSG); + this.encAlgFn = new IdLocator<>(DefaultJweHeader.ENCRYPTION_ALGORITHM, Jwts.ENC.get(), extraEncAlgs, MISSING_ENC_MSG); + this.zipAlgFn = compressionCodecResolver != null ? new CompressionCodecLocator(compressionCodecResolver) : + new IdLocator<>(DefaultHeader.COMPRESSION_ALGORITHM, Jwts.ZIP.get(), extraZipAlgs, null); } @Override @@ -442,7 +284,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe SecureDigestAlgorithm algorithm; try { - algorithm = (SecureDigestAlgorithm) signatureAlgorithmLocator.apply(jwsHeader); + algorithm = (SecureDigestAlgorithm) sigAlgFn.apply(jwsHeader); } catch (UnsupportedJwtException e) { //For backwards compatibility. TODO: remove this try/catch block for 1.0 and let UnsupportedJwtException propagate String msg = "Unsupported signature algorithm '" + alg + "'"; @@ -494,15 +336,6 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe @Override public Jwt parse(String compact) throws ExpiredJwtException, MalformedJwtException, SignatureException { - // TODO, this logic is only need for a now deprecated code path - // remove this block in v1.0 (the equivalent is already in DefaultJwtParserBuilder) - if (this.deserializer == null) { - // try to find one based on the services available - // TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0 - //noinspection deprecation - this.deserializer = LegacyServices.loadFirst(Deserializer.class); - } - Assert.hasText(compact, "JWT String cannot be null or empty."); final TokenizedJwt tokenized = jwtTokenizer.tokenize(compact); @@ -607,10 +440,10 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe if (!Strings.hasText(enc)) { throw new MalformedJwtException(MISSING_ENC_MSG); } - final AeadAlgorithm encAlg = this.encryptionAlgorithmLocator.apply(jweHeader); + final AeadAlgorithm encAlg = this.encAlgFn.apply(jweHeader); Assert.stateNotNull(encAlg, "JWE Encryption Algorithm cannot be null."); - @SuppressWarnings("rawtypes") final KeyAlgorithm keyAlg = this.keyAlgorithmLocator.apply(jweHeader); + @SuppressWarnings("rawtypes") final KeyAlgorithm keyAlg = this.keyAlgFn.apply(jweHeader); Assert.stateNotNull(keyAlg, "JWE Key Algorithm cannot be null."); final Key key = this.keyLocator.locate(jweHeader); @@ -639,7 +472,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe verifySignature(tokenized, ((JwsHeader) header), alg, new LocatingKeyResolver(this.keyLocator), null, null); } - CompressionAlgorithm compressionAlgorithm = compressionAlgorithmLocator.apply(header); + CompressionAlgorithm compressionAlgorithm = zipAlgFn.apply(header); if (compressionAlgorithm != null) { if (unsecured && !enableUnsecuredDecompression) { String msg = String.format(UNPROTECTED_DECOMPRESSION_MSG, compressionAlgorithm.getId()); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index eda46473e..0b797bad3 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -282,16 +282,26 @@ public JwtParser build() { } if (this.signingKeyResolver != null && this.signatureVerificationKey != null) { - String msg = "Both 'signingKeyResolver and 'verifyWith/signWith' key cannot be configured. " + + String msg = "Both a 'signingKeyResolver and a 'verifyWith' key cannot be configured. " + "Choose either, or prefer `keyLocator` when possible."; throw new IllegalStateException(msg); } - if (this.keyLocator != null && this.decryptionKey != null) { - String msg = "Both 'keyLocator' and 'decryptWith' key cannot be configured. Prefer 'keyLocator' if possible."; - throw new IllegalStateException(msg); + if (this.keyLocator != null) { + if (this.signatureVerificationKey != null) { + String msg = "Both 'keyLocator' and a 'verifyWith' key cannot be configured. " + + "Prefer 'keyLocator' if possible."; + throw new IllegalStateException(msg); + } + if (this.decryptionKey != null) { + String msg = "Both 'keyLocator' and a 'decryptWith' key cannot be configured. " + + "Prefer 'keyLocator' if possible."; + throw new IllegalStateException(msg); + } } - if (this.keyLocator == null) { - this.keyLocator = new ConstantKeyLocator(this.signatureVerificationKey, this.decryptionKey); + + Locator keyLocator = this.keyLocator; // user configured default, don't overwrite to ensure further build() calls work as expected + if (keyLocator == null) { + keyLocator = new ConstantKeyLocator(this.signatureVerificationKey, this.decryptionKey); } if (!enableUnsecuredJws && enableUnsecuredDecompression) { @@ -306,13 +316,12 @@ public JwtParser build() { throw new IllegalStateException(msg); } - // Invariants. If these are ever violated, it's an error in this class implementation - // (we default to non-null instances, and the setters should never allow null): - Assert.stateNotNull(this.keyLocator, "Key locator should never be null."); + // Invariants. If these are ever violated, it's an error in this class implementation: + Assert.stateNotNull(keyLocator, "Key locator should never be null."); final DefaultClaims expClaims = (DefaultClaims) this.expectedClaims.build(); - return new ImmutableJwtParser(new DefaultJwtParser( + return new DefaultJwtParser( provider, signingKeyResolver, enableUnsecuredJws, @@ -328,6 +337,6 @@ public JwtParser build() { extraSigAlgs, extraKeyAlgs, extraEncAlgs - )); + ); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/ImmutableJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/ImmutableJwtParser.java deleted file mode 100644 index c48fcbe17..000000000 --- a/impl/src/main/java/io/jsonwebtoken/impl/ImmutableJwtParser.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.Jwe; -import io.jsonwebtoken.Jws; -import io.jsonwebtoken.Jwt; -import io.jsonwebtoken.JwtException; -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 base64UrlDecoder) { - throw doNotMutate(); - } - - @Override - public JwtParser deserializeJsonWith(Deserializer> deserializer) { - throw doNotMutate(); - } - - @Override - public boolean isSigned(String compact) { - return this.jwtParser.isSigned(compact); - } - - @Override - public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { - return this.jwtParser.parse(jwt); - } - - @Override - public T parse(String jwt, JwtHandler handler) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { - return this.jwtParser.parse(jwt, handler); - } - - @Override - public Jwt parseContentJwt(String jwt) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { - return this.jwtParser.parseContentJwt(jwt); - } - - @Override - public Jwt parseClaimsJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { - return this.jwtParser.parseClaimsJwt(jwt); - } - - @Override - public Jws parseContentJws(String jws) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { - return this.jwtParser.parseContentJws(jws); - } - - @Override - public Jws parseClaimsJws(String jws) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { - return this.jwtParser.parseClaimsJws(jws); - } - - @Override - public Jwe parseContentJwe(String jwe) throws JwtException { - return this.jwtParser.parseContentJwe(jwe); - } - - @Override - public Jwe parseClaimsJwe(String jwe) throws JwtException { - return this.jwtParser.parseClaimsJwe(jwe); - } -} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/lang/LegacyServices.java b/impl/src/main/java/io/jsonwebtoken/impl/lang/LegacyServices.java deleted file mode 100644 index ec0e10486..000000000 --- a/impl/src/main/java/io/jsonwebtoken/impl/lang/LegacyServices.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright © 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.lang; - -import io.jsonwebtoken.lang.Classes; -import io.jsonwebtoken.lang.UnknownClassException; - -/** - * A backward compatibility {@link Services} utility to help migrate away from {@link Classes#newInstance(String)}. - * TODO: remove before v1.0 - * @deprecated use {@link Services} directly - */ -@Deprecated -public final class LegacyServices { - - /** - * Wraps {@code Services.loadFirst} and throws a {@link UnknownClassException} instead of a - * {@link UnavailableImplementationException} to retain the previous behavior. This method should be used when - * to retain the previous behavior of methods that throw an unchecked UnknownClassException. - * @param the type of object to return - * @param spi the class for which to find the first instance - * @return the first instance of type {@code T} found from a call to {@link Services#loadFirst(Class)} - */ - public static T loadFirst(Class spi) { - try { - return Services.loadFirst(spi); - } catch (UnavailableImplementationException e) { - throw new UnknownClassException(e.getMessage(), e); - } - } -} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/ConstantKeyLocator.java b/impl/src/main/java/io/jsonwebtoken/impl/security/ConstantKeyLocator.java index 0189aa270..f97ccd50e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/ConstantKeyLocator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/ConstantKeyLocator.java @@ -15,18 +15,15 @@ */ package io.jsonwebtoken.impl.security; -import io.jsonwebtoken.Claims; import io.jsonwebtoken.Header; import io.jsonwebtoken.JweHeader; import io.jsonwebtoken.JwsHeader; import io.jsonwebtoken.LocatorAdapter; -import io.jsonwebtoken.SigningKeyResolver; import io.jsonwebtoken.impl.lang.Function; import java.security.Key; -@SuppressWarnings("deprecation") -public class ConstantKeyLocator extends LocatorAdapter implements SigningKeyResolver, Function { +public class ConstantKeyLocator extends LocatorAdapter implements Function { private final Key jwsKey; private final Key jweKey; @@ -36,16 +33,6 @@ public ConstantKeyLocator(Key jwsKey, Key jweKey) { this.jweKey = jweKey; } - @Override - public Key resolveSigningKey(JwsHeader header, Claims claims) { - return locate(header); - } - - @Override - public Key resolveSigningKey(JwsHeader header, byte[] content) { - return locate(header); - } - @Override protected Key locate(JwsHeader header) { return this.jwsKey; diff --git a/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy index 62069823b..e5de114a0 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy @@ -37,13 +37,13 @@ class CustomObjectDeserializationTest { String jwtString = Jwts.builder().claim("cust", customBean).compact() // no custom deserialization, object is a map - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(jwtString) + Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(jwtString) assertNotNull jwt assertEquals jwt.getPayload().get('cust'), [key1: 'value1', key2: 42] // custom type for 'cust' claim Deserializer deserializer = new JacksonDeserializer([cust: CustomBean]) - jwt = Jwts.parserBuilder().enableUnsecuredJws().deserializeJsonWith(deserializer).build().parseClaimsJwt(jwtString) + jwt = Jwts.parser().enableUnsecuredJws().deserializeJsonWith(deserializer).build().parseClaimsJwt(jwtString) assertNotNull jwt CustomBean result = jwt.getPayload().get("cust", CustomBean) assertEquals customBean, result diff --git a/impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtParserTest.groovy deleted file mode 100644 index 0b5fbea7f..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtParserTest.groovy +++ /dev/null @@ -1,1520 +0,0 @@ -/* - * 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.DefaultClock -import io.jsonwebtoken.impl.FixedClock -import io.jsonwebtoken.impl.JwtTokenizer -import io.jsonwebtoken.impl.security.TestKeys -import io.jsonwebtoken.io.Encoders -import io.jsonwebtoken.lang.Strings -import io.jsonwebtoken.security.SignatureException -import org.junit.Test - -import java.nio.charset.StandardCharsets -import java.security.SecureRandom - -import static io.jsonwebtoken.impl.DefaultJwtParser.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE -import static io.jsonwebtoken.impl.DefaultJwtParser.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE -import static org.junit.Assert.* - -class DeprecatedJwtParserTest { - - private static final SecureRandom random = new SecureRandom() //doesn't need to be seeded - just testing - - protected static byte[] randomKey() { - //create random signing key for testing: - byte[] key = new byte[64] - random.nextBytes(key) - return key - } - - protected static String base64Url(String s) { - byte[] bytes = s.getBytes(Strings.UTF_8) - return Encoders.BASE64URL.encode(bytes) - } - - @Test - void testIsSignedWithNullArgument() { - assertFalse Jwts.parser().isSigned(null) - } - - @Test - void testIsSignedWithJunkArgument() { - assertFalse Jwts.parser().isSigned('hello') - } - - @Test - void testParseWithJunkArgument() { - - String junkPayload = '{;aklsjd;fkajsd;fkjasd;lfkj}' - - String bad = base64Url('{"alg":"none"}') + '.' + base64Url(junkPayload) + '.' - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(bad) - fail() - } catch (MalformedJwtException expected) { - assertEquals 'Unable to read claims JSON: ' + junkPayload, expected.getMessage() - } - } - - @Test - void testParseJwsWithBadAlgHeader() { - - String badAlgorithmName = 'whatever' - - String header = "{\"alg\":\"$badAlgorithmName\"}" - - String payload = '{"subject":"Joe"}' - - String badSig = ";aklsjdf;kajsd;fkjas;dklfj" - - String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) - - try { - Jwts.parser().setSigningKey(randomKey()).parse(bad) - fail() - } catch (SignatureException se) { - assertEquals se.getMessage(), "Unsupported signature algorithm '$badAlgorithmName'".toString() - } - } - - @Test - void testParseWithInvalidSignature() { - - String header = '{"alg":"HS256"}' - - String payload = '{"subject":"Joe"}' - - String badSig = ";aklsjdf;kajsd;fkjas;dklfj" - - String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) - - try { - 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.' - } - - } - - @Test - void testParseContentJwsWithIncorrectAlg() { - - def header = '{"alg":"none"}' - - def payload = '{"subject":"Joe"}' - - def badSig = ";aklsjdf;kajsd;fkjas;dklfj" - - String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) - - try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(randomKey()).build().parse(bad) - fail() - } catch (MalformedJwtException se) { - assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', se.getMessage() - } - - } - - @Test - void testParseWithBase64EncodedSigningKey() { - - byte[] key = randomKey() - - String base64Encodedkey = Encoders.BASE64.encode(key) - - String payload = 'Hello world!' - - //noinspection GrDeprecatedAPIUsage - String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, base64Encodedkey).compact() - - assertTrue Jwts.parser().isSigned(compact) - - def jwt = Jwts.parser().setSigningKey(base64Encodedkey).parse(compact) - - assertEquals payload, new String(jwt.body as byte[], StandardCharsets.UTF_8) - } - - @Test - void testParseWithExpiredJwt() { - - Date exp = new Date(System.currentTimeMillis() - 1000) - - String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact) - fail() - } catch (ExpiredJwtException e) { - assertTrue e.getMessage().startsWith('JWT expired at ') - - //https://github.com/jwtk/jjwt/issues/107 (the Z designator at the end of the timestamp): - assertTrue e.getMessage().contains('Z, a difference of ') - } - } - - @Test - void testParseWithPrematureJwt() { - - Date nbf = new Date(System.currentTimeMillis() + 100000) - - String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact) - fail() - } catch (PrematureJwtException e) { - assertTrue e.getMessage().startsWith('JWT must not be accepted before ') - - //https://github.com/jwtk/jjwt/issues/107 (the Z designator at the end of the timestamp): - assertTrue e.getMessage().contains('Z, a difference of ') - } - } - - @Test - void testParseWithExpiredJwtWithinAllowedClockSkew() { - Date exp = new Date(System.currentTimeMillis() - 3000) - - String subject = 'Joe' - String compact = Jwts.builder().setSubject(subject).setExpiration(exp).compact() - - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) - - assertEquals jwt.getBody().getSubject(), subject - } - - @Test - void testParseWithExpiredJwtNotWithinAllowedClockSkew() { - Date exp = new Date(System.currentTimeMillis() - 3000) - - String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) - fail() - } catch (ExpiredJwtException e) { - assertTrue e.getMessage().startsWith('JWT expired at ') - } - } - - @Test - void testParseWithPrematureJwtWithinAllowedClockSkew() { - Date exp = new Date(System.currentTimeMillis() + 3000) - - String subject = 'Joe' - String compact = Jwts.builder().setSubject(subject).setNotBefore(exp).compact() - - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) - - assertEquals jwt.getBody().getSubject(), subject - } - - @Test - void testParseWithPrematureJwtNotWithinAllowedClockSkew() { - Date exp = new Date(System.currentTimeMillis() + 3000) - - String compact = Jwts.builder().setSubject('Joe').setNotBefore(exp).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) - fail() - } catch (PrematureJwtException e) { - assertTrue e.getMessage().startsWith('JWT must not be accepted before ') - } - } - - // ======================================================================== - // parseContentJwt tests - // ======================================================================== - - @Test - void testParseContentJwt() { - - String payload = 'Hello world!' - - String compact = Jwts.builder().setPayload(payload).compact() - - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) - - assertEquals payload, new String(jwt.body, StandardCharsets.UTF_8) - } - - @Test - void testParseContentJwtWithClaimsJwt() { - - String compact = Jwts.builder().setSubject('Joe').compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals e.getMessage(), 'Unprotected Claims JWTs are not supported.' - } - } - - @Test - void testParseContentJwtWithContentJws() { - - String payload = 'Hello world!' - - String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, randomKey()).compact() - - try { - Jwts.parser().parseContentJwt(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS256}', e.getMessage() - } - } - - @Test - void testParseContentJwtWithClaimsJws() { - - String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, randomKey()).compact() - - try { - Jwts.parser().parseContentJwt(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS256}', e.getMessage() - } - } - - // ======================================================================== - // parseClaimsJwt tests - // ======================================================================== - - @Test - void testParseClaimsJwt() { - - String subject = 'Joe' - - String compact = Jwts.builder().setSubject(subject).compact() - - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) - - assertEquals jwt.getBody().getSubject(), subject - } - - @Test - void testParseClaimsJwtWithContentJwt() { - - String payload = 'Hello world!' - - String compact = Jwts.builder().setPayload(payload).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() - } - } - - @Test - void testParseClaimsJwtWithContentJws() { - - String payload = 'Hello world!' - - String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, randomKey()).compact() - - try { - Jwts.parser().parseClaimsJwt(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS256}', e.getMessage() - } - } - - @Test - void testParseClaimsJwtWithClaimsJws() { - - String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, randomKey()).compact() - - try { - Jwts.parser().parseClaimsJwt(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS256}', e.getMessage() - } - } - - @Test - void testParseClaimsJwtWithExpiredJwt() { - - long nowMillis = System.currentTimeMillis() - //some time in the past: - Date exp = new Date(nowMillis - 1000) - - String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) - fail() - } catch (ExpiredJwtException e) { - assertTrue e.getMessage().startsWith('JWT expired at ') - } - } - - @Test - void testParseClaimsJwtWithPrematureJwt() { - - Date nbf = new Date(System.currentTimeMillis() + 100000) - - String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) - fail() - } catch (PrematureJwtException e) { - assertTrue e.getMessage().startsWith('JWT must not be accepted before ') - } - } - - // ======================================================================== - // parseContentJws tests - // ======================================================================== - - @Test - void testParseContentJws() { - - String payload = 'Hello world!' - - byte[] key = randomKey() - - String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, key).compact() - - def jwt = Jwts.parser().setSigningKey(key).parseContentJws(compact) - - assertEquals payload, new String(jwt.body, StandardCharsets.UTF_8) - } - - @Test - void testParseContentJwsWithContentJwt() { - - String payload = 'Hello world!' - - byte[] key = randomKey() - - String compact = Jwts.builder().setPayload(payload).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() - } - } - - @Test - void testParseContentJwsWithClaimsJwt() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Unprotected Claims JWTs are not supported.', e.getMessage() - } - } - - @Test - void testParseContentJwsWithClaimsJws() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() - - try { - Jwts.parser().setSigningKey(key).parseContentJws(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Signed Claims JWTs are not supported.', e.getMessage() - } - } - - // ======================================================================== - // parseClaimsJws tests - // ======================================================================== - - @Test - void testParseClaimsJws() { - - String sub = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(sub).signWith(SignatureAlgorithm.HS256, key).compact() - - Jwt jwt = Jwts.parser().setSigningKey(key).parseClaimsJws(compact) - - assertEquals jwt.getBody().getSubject(), sub - } - - @Test - void testParseClaimsJwsWithExpiredJws() { - - String sub = 'Joe' - - byte[] key = randomKey() - - long nowMillis = System.currentTimeMillis() - //some time in the past: - Date exp = new Date(nowMillis - 1000) - - String compact = Jwts.builder().setSubject(sub).signWith(SignatureAlgorithm.HS256, key).setExpiration(exp).compact() - - try { - Jwts.parser().setSigningKey(key).parseClaimsJwt(compact) - fail() - } catch (ExpiredJwtException e) { - assertTrue e.getMessage().startsWith('JWT expired at ') - assertEquals e.getClaims().getSubject(), sub - assertEquals e.getHeader().getAlgorithm(), "HS256" - } - } - - @Test - void testParseClaimsJwsWithPrematureJws() { - - String sub = 'Joe' - - byte[] key = randomKey() - - Date nbf = new Date(System.currentTimeMillis() + 100000) - - String compact = Jwts.builder().setSubject(sub).setNotBefore(nbf).signWith(SignatureAlgorithm.HS256, key).compact() - - try { - Jwts.parser().setSigningKey(key).parseClaimsJws(compact) - fail() - } catch (PrematureJwtException e) { - assertTrue e.getMessage().startsWith('JWT must not be accepted before ') - assertEquals e.getClaims().getSubject(), sub - assertEquals e.getHeader().getAlgorithm(), "HS256" - } - } - - @Test - void testParseClaimsJwsWithContentJwt() { - - String payload = 'Hello world!' - - byte[] key = randomKey() - - String compact = Jwts.builder().setPayload(payload).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() - } - } - - @Test - void testParseClaimsJwsWithClaimsJwt() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Unprotected Claims JWTs are not supported.', e.getMessage() - } - } - - @Test - void testParseClaimsJwsWithContentJws() { - - String payload = 'Hello world' - - byte[] key = randomKey() - - String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, key).compact() - - try { - Jwts.parser().setSigningKey(key).parseClaimsJws(compact) - fail() - } catch (UnsupportedJwtException e) { - assertEquals 'Signed content JWTs are not supported.', e.getMessage() - } - } - - // ======================================================================== - // parseClaimsJws with signingKey resolver. - // ======================================================================== - - @Test - void testParseClaimsWithSigningKeyResolver() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() - - def signingKeyResolver = new SigningKeyResolverAdapter() { - @Override - byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) { - return key - } - } - - Jws jws = Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact) - - assertEquals jws.getBody().getSubject(), subject - } - - @Test - void testParseClaimsWithSigningKeyResolverInvalidKey() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() - - def signingKeyResolver = new SigningKeyResolverAdapter() { - @Override - byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) { - return randomKey() - } - } - - try { - Jwts.parser().setSigningKeyResolver(signingKeyResolver).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.' - } - } - - @Test - void testParseClaimsWithNullSigningKeyResolver() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() - - try { - Jwts.parser().setSigningKeyResolver(null).parseClaimsJws(compact) - fail() - } catch (IllegalArgumentException iae) { - assertEquals iae.getMessage(), 'SigningKeyResolver cannot be null.' - } - } - - @Test - void testParseClaimsWithInvalidSigningKeyResolverAdapter() { - - String subject = 'Joe' - - byte[] key = randomKey() - - String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() - - def signingKeyResolver = new SigningKeyResolverAdapter() - - try { - Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseClaimsJws(compact) - fail() - } catch (UnsupportedJwtException ex) { - assertEquals ex.getMessage(), 'The specified SigningKeyResolver implementation does not support ' + - 'Claims JWS signing key resolution. Consider overriding either the resolveSigningKey(JwsHeader, Claims) method ' + - 'or, for HMAC algorithms, the resolveSigningKeyBytes(JwsHeader, Claims) method.' - } - } - - @Test - void testParseClaimsJwsWithNumericTypes() { - byte[] key = randomKey() - - def b = (byte) 42 - def s = (short) 42 - def i = 42 - - def smallLong = (long) 42 - def bigLong = ((long) Integer.MAX_VALUE) + 42 - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - claim("byte", b). - claim("short", s). - claim("int", i). - claim("long_small", smallLong). - claim("long_big", bigLong). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key).parseClaimsJws(compact) - - Claims claims = jwt.getBody() - - assertEquals(b, claims.get("byte", Byte.class)) - assertEquals(s, claims.get("short", Short.class)) - assertEquals(i, claims.get("int", Integer.class)) - assertEquals(smallLong, claims.get("long_small", Long.class)) - assertEquals(bigLong, claims.get("long_big", Long.class)) - } - - // ======================================================================== - // parseContentJws with signingKey resolver. - // ======================================================================== - - @Test - void testParseContentJwsWithSigningKeyResolverAdapter() { - - String inputPayload = 'Hello world!' - - byte[] key = randomKey() - - String compact = Jwts.builder().setPayload(inputPayload).signWith(SignatureAlgorithm.HS256, key).compact() - - def signingKeyResolver = new SigningKeyResolverAdapter() { - @Override - byte[] resolveSigningKeyBytes(JwsHeader header, byte[] payload) { - return key - } - } - - Jws jws = Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseContentJws(compact) - - assertEquals inputPayload, new String(jws.body, StandardCharsets.UTF_8) - } - - @Test - void testParseContentJwsWithSigningKeyResolverInvalidKey() { - - byte[] inputPayload = 'Hello world!'.getBytes(StandardCharsets.UTF_8) - - byte[] key = randomKey() - - String compact = Jwts.builder().setContent(inputPayload).signWith(SignatureAlgorithm.HS256, key).compact() - - def signingKeyResolver = new SigningKeyResolverAdapter() { - @Override - byte[] resolveSigningKeyBytes(JwsHeader header, byte[] payload) { - return randomKey() - } - } - - try { - Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseContentJws(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.' - } - } - - @Test - void testParseContentJwsWithInvalidSigningKeyResolverAdapter() { - - String payload = 'Hello world!' - - byte[] key = randomKey() - - String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, key).compact() - - def signingKeyResolver = new SigningKeyResolverAdapter() - - try { - Jwts.parser().setSigningKeyResolver(signingKeyResolver).parseContentJws(compact) - fail() - } catch (UnsupportedJwtException ex) { - assertEquals ex.getMessage(), 'The specified SigningKeyResolver implementation does not support content ' + - 'JWS signing key resolution. Consider overriding either the resolveSigningKey(JwsHeader, byte[]) ' + - 'method or, for HMAC algorithms, the resolveSigningKeyBytes(JwsHeader, byte[]) method.' - } - } - - @Test - void testParseRequireDontAllowNullClaimName() { - def expectedClaimValue = 'A Most Awesome Claim Value' - - byte[] key = randomKey() - - // not setting expected claim name in JWT - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).setIssuer('Dummy').compact() - - try { - // expecting null claim name, but with value - Jwts.parser().setSigningKey(key).require(null, expectedClaimValue).parseClaimsJws(compact) - fail() - } catch (IllegalArgumentException e) { - assertEquals( - "claim name cannot be null or empty.", - e.getMessage() - ) - } - } - - @Test - void testParseRequireDontAllowEmptyClaimName() { - def expectedClaimValue = 'A Most Awesome Claim Value' - - byte[] key = randomKey() - - // not setting expected claim name in JWT - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuer('Dummy'). - compact() - - try { - // expecting null claim name, but with value - Jwt jwt = Jwts.parser().setSigningKey(key). - require("", expectedClaimValue). - parseClaimsJws(compact) - fail() - } catch (IllegalArgumentException e) { - assertEquals( - "claim name cannot be null or empty.", - e.getMessage() - ) - } - } - - @Test - void testParseRequireDontAllowNullClaimValue() { - def expectedClaimName = 'A Most Awesome Claim Name' - - byte[] key = randomKey() - - // not setting expected claim name in JWT - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).setIssuer('Dummy').compact() - - try { - // expecting claim name, but with null value - Jwt jwt = Jwts.parser().setSigningKey(key). - require(expectedClaimName, null). - parseClaimsJws(compact) - fail() - } catch (IllegalArgumentException e) { - assertEquals( - "The value cannot be null for claim name: " + expectedClaimName, - e.getMessage() - ) - } - } - - @Test - void testParseRequireGeneric_Success() { - def expectedClaimName = 'A Most Awesome Claim Name' - def expectedClaimValue = 'A Most Awesome Claim Value' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - claim(expectedClaimName, expectedClaimValue). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - require(expectedClaimName, expectedClaimValue). - parseClaimsJws(compact) - - assertEquals jwt.getBody().get(expectedClaimName), expectedClaimValue - } - - @Test - void testParseRequireGeneric_Incorrect_Fail() { - def goodClaimName = 'A Most Awesome Claim Name' - def goodClaimValue = 'A Most Awesome Claim Value' - - def badClaimValue = 'A Most Bogus Claim Value' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - claim(goodClaimName, badClaimValue). - compact() - - try { - Jwts.parser().setSigningKey(key). - require(goodClaimName, goodClaimValue). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - assertEquals( - String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, goodClaimName, goodClaimValue, badClaimValue), - e.getMessage() - ) - } - } - - @Test - void testParseRequireedGeneric_Missing_Fail() { - def claimName = 'A Most Awesome Claim Name' - def claimValue = 'A Most Awesome Claim Value' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuer('Dummy'). - compact() - - try { - Jwt jwt = Jwts.parser().setSigningKey(key). - require(claimName, claimValue). - parseClaimsJws(compact) - fail() - } catch (MissingClaimException e) { - assertEquals( - String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, claimName, claimValue), - e.getMessage() - ) - } - } - - @Test - void testParseRequireIssuedAt_Success() { - - def issuedAt = new Date(System.currentTimeMillis()) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuedAt(issuedAt). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireIssuedAt(issuedAt). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getIssuedAt().getTime(), truncateMillis(issuedAt) - } - - @Test(expected = IncorrectClaimException) - void testParseRequireIssuedAt_Incorrect_Fail() { - def goodIssuedAt = new Date(System.currentTimeMillis()) - def badIssuedAt = new Date(System.currentTimeMillis() - 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuedAt(badIssuedAt). - compact() - - Jwts.parser().setSigningKey(key). - requireIssuedAt(goodIssuedAt). - parseClaimsJws(compact) - } - - @Test(expected = MissingClaimException) - void testParseRequireIssuedAt_Missing_Fail() { - def issuedAt = new Date(System.currentTimeMillis() - 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setSubject("Dummy"). - compact() - - Jwts.parser().setSigningKey(key). - requireIssuedAt(issuedAt). - parseClaimsJws(compact) - } - - @Test - void testParseRequireIssuer_Success() { - def issuer = 'A Most Awesome Issuer' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuer(issuer). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireIssuer(issuer). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getIssuer(), issuer - } - - @Test - void testParseRequireIssuer_Incorrect_Fail() { - def goodIssuer = 'A Most Awesome Issuer' - def badIssuer = 'A Most Bogus Issuer' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuer(badIssuer). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireIssuer(goodIssuer). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - assertEquals( - String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUER, goodIssuer, badIssuer), - e.getMessage() - ) - } - } - - @Test - void testParseRequireIssuer_Missing_Fail() { - def issuer = 'A Most Awesome Issuer' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setId('id'). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireIssuer(issuer). - parseClaimsJws(compact) - fail() - } catch (MissingClaimException e) { - assertEquals( - String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUER, issuer), - e.getMessage() - ) - } - } - - @Test - void testParseRequireAudience_Success() { - def audience = 'A Most Awesome Audience' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setAudience(audience). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireAudience(audience). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getAudience(), audience - } - - @Test - void testParseRequireAudience_Incorrect_Fail() { - def goodAudience = 'A Most Awesome Audience' - def badAudience = 'A Most Bogus Audience' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setAudience(badAudience). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireAudience(goodAudience). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - assertEquals( - String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.AUDIENCE, goodAudience, badAudience), - e.getMessage() - ) - } - } - - @Test - void testParseRequireAudience_Missing_Fail() { - def audience = 'A Most Awesome audience' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setId('id'). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireAudience(audience). - parseClaimsJws(compact) - fail() - } catch (MissingClaimException e) { - assertEquals( - String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.AUDIENCE, audience), - e.getMessage() - ) - } - } - - @Test - void testParseRequireSubject_Success() { - def subject = 'A Most Awesome Subject' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setSubject(subject). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireSubject(subject). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getSubject(), subject - } - - @Test - void testParseRequireSubject_Incorrect_Fail() { - def goodSubject = 'A Most Awesome Subject' - def badSubject = 'A Most Bogus Subject' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setSubject(badSubject). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireSubject(goodSubject). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - assertEquals( - String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.SUBJECT, goodSubject, badSubject), - e.getMessage() - ) - } - } - - @Test - void testParseRequireSubject_Missing_Fail() { - def subject = 'A Most Awesome Subject' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setId('id'). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireSubject(subject). - parseClaimsJws(compact) - fail() - } catch (MissingClaimException e) { - assertEquals( - String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.SUBJECT, subject), - e.getMessage() - ) - } - } - - @Test - void testParseRequireId_Success() { - def id = 'A Most Awesome id' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setId(id). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireId(id). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getId(), id - } - - @Test - void testParseRequireId_Incorrect_Fail() { - def goodId = 'A Most Awesome Id' - def badId = 'A Most Bogus Id' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setId(badId). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireId(goodId). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - assertEquals( - String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ID, goodId, badId), - e.getMessage() - ) - } - } - - @Test - void testParseRequireId_Missing_Fail() { - def id = 'A Most Awesome Id' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setIssuer('me'). - compact() - - try { - Jwts.parser().setSigningKey(key). - requireId(id). - parseClaimsJws(compact) - fail() - } catch (MissingClaimException e) { - assertEquals( - String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ID, id), - e.getMessage() - ) - } - } - - @Test - void testParseRequireExpiration_Success() { - // expire in the future - def expiration = new Date(System.currentTimeMillis() + 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setExpiration(expiration). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireExpiration(expiration). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getExpiration().getTime(), truncateMillis(expiration) - } - - @Test(expected = IncorrectClaimException) - void testParseRequireExpirationAt_Incorrect_Fail() { - def goodExpiration = new Date(System.currentTimeMillis() + 20000) - def badExpiration = new Date(System.currentTimeMillis() + 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setExpiration(badExpiration). - compact() - - Jwts.parser().setSigningKey(key). - requireExpiration(goodExpiration). - parseClaimsJws(compact) - } - - @Test(expected = MissingClaimException) - void testParseRequireExpiration_Missing_Fail() { - def expiration = new Date(System.currentTimeMillis() + 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setSubject("Dummy"). - compact() - - Jwts.parser().setSigningKey(key). - requireExpiration(expiration). - parseClaimsJws(compact) - } - - @Test - void testParseRequireNotBefore_Success() { - // expire in the future - def notBefore = new Date(System.currentTimeMillis() - 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setNotBefore(notBefore). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - requireNotBefore(notBefore). - parseClaimsJws(compact) - - assertEquals jwt.getBody().getNotBefore().getTime(), truncateMillis(notBefore) - } - - @Test(expected = IncorrectClaimException) - void testParseRequireNotBefore_Incorrect_Fail() { - def goodNotBefore = new Date(System.currentTimeMillis() - 20000) - def badNotBefore = new Date(System.currentTimeMillis() - 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setNotBefore(badNotBefore). - compact() - - Jwts.parser().setSigningKey(key). - requireNotBefore(goodNotBefore). - parseClaimsJws(compact) - } - - @Test(expected = MissingClaimException) - void testParseRequireNotBefore_Missing_Fail() { - def notBefore = new Date(System.currentTimeMillis() - 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setSubject("Dummy"). - compact() - - Jwts.parser().setSigningKey(key). - requireNotBefore(notBefore). - parseClaimsJws(compact) - } - - @Test - void testParseRequireCustomDate_Success() { - - def aDate = new Date(System.currentTimeMillis()) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - claim("aDate", aDate). - compact() - - Jwt jwt = Jwts.parser().setSigningKey(key). - require("aDate", aDate). - parseClaimsJws(compact) - - assertEquals jwt.getBody().get("aDate", Date.class), aDate - } - - @Test - //since 0.10.0 - void testParseRequireCustomDateWhenClaimIsNotADate() { - - def goodDate = new Date(System.currentTimeMillis()) - def badDate = 'hello' - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - claim("aDate", badDate). - compact() - - try { - Jwts.parser().setSigningKey(key). - require("aDate", goodDate). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - String expected = 'JWT Claim \'aDate\' was expected to be a Date, but its value cannot be converted to a ' + - 'Date using current heuristics. Value: hello' - assertEquals expected, e.getMessage() - } - } - - @Test - void testParseRequireCustomDate_Incorrect_Fail() { - - def goodDate = new Date(System.currentTimeMillis()) - def badDate = new Date(System.currentTimeMillis() - 10000) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - claim("aDate", badDate). - compact() - - try { - Jwts.parser().setSigningKey(key). - require("aDate", goodDate). - parseClaimsJws(compact) - fail() - } catch (IncorrectClaimException e) { - assertEquals( - String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, "aDate", goodDate, badDate), - e.getMessage() - ) - } - } - - @Test - void testParseRequireCustomDate_Missing_Fail() { - def aDate = new Date(System.currentTimeMillis()) - - byte[] key = randomKey() - - String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key). - setSubject("Dummy"). - compact() - - try { - Jwts.parser().setSigningKey(key). - require("aDate", aDate). - parseClaimsJws(compact) - fail() - } catch (MissingClaimException e) { - assertEquals( - String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, "aDate", aDate), - e.getMessage() - ) - } - } - - @Test - void testParseClockManipulationWithFixedClock() { - def then = System.currentTimeMillis() - 1000 - Date expiry = new Date(then) - Date beforeExpiry = new Date(then - 1000) - - String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() - - Jwts.parserBuilder().enableUnsecuredJws().setClock(new FixedClock(beforeExpiry)).build().parse(compact) - } - - @Test - void testParseClockManipulationWithNullClock() { - JwtParser parser = Jwts.parser(); - try { - parser.setClock(null) - fail() - } catch (IllegalArgumentException expected) { - } - } - - @Test - void testSetClock() { - def clock = new DefaultClock(); - def parser = Jwts.parser().setClock(clock) - assertSame clock, parser.@clock - assertFalse DefaultClock.INSTANCE.is(parser.@clock) - } - - @Test - void testParseClockManipulationWithDefaultClock() { - Date expiry = new Date(System.currentTimeMillis() - 1000) - - def key = TestKeys.HS256 - - String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry) - .signWith(key).compact() - - try { - def clock = new DefaultClock() - def parser = Jwts.parser().setSigningKey(key).setClock(clock) - parser.parseClaimsJws(compact) - fail() - } catch (ExpiredJwtException e) { - assertTrue e.getMessage().startsWith('JWT expired at ') - } - } - - @Test - void testBuilderParseClockManipulationWithDefaultClock() { - Date expiry = new Date(System.currentTimeMillis() - 1000) - - String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() - - try { - Jwts.parserBuilder().enableUnsecuredJws().setClock(new DefaultClock()).build().parse(compact) - fail() - } catch (ExpiredJwtException e) { - assertTrue e.getMessage().startsWith('JWT expired at ') - } - } - - @Test - void testParseMalformedJwt() { - - String header = '{"alg":"none"}' - - String payload = '{"subject":"Joe"}' - - String badSig = ";aklsjdf;kajsd;fkjas;dklfj" - - String bogus = 'bogus' - - String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) + '.' + base64Url(bogus) - - try { - Jwts.parser().setSigningKey(randomKey()).parse(bad) - fail() - } catch (MalformedJwtException se) { - String expected = JwtTokenizer.DELIM_ERR_MSG_PREFIX + '3' - assertEquals expected, se.message - } - } - - @Test - void testNoProtectedHeader() { - - String payload = '{"sub":"Joe"}' - - String jwtStr = '.' + base64Url(payload) + '.' - - try { - Jwts.parserBuilder().build().parse(jwtStr) - fail() - } catch (MalformedJwtException e) { - assertEquals 'Compact JWT strings MUST always have a Base64Url protected header per https://tools.ietf.org/html/rfc7519#section-7.2 (steps 2-4).', e.getMessage() - } - } - - @Test - void testBadHeaderSig() { - - String header = '{"alg":"none"}' - - String payload = '{"subject":"Joe"}' - - String sig = ";aklsjdf;kajsd;fkjas;dklfj" - - String jwtStr = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(sig) - - try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(jwtStr) - fail() - } catch (MalformedJwtException se) { - assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', se.message - } - } - - /** - * Date util method for lopping truncate the millis from a date. - * @param date input date - * @return The date time in millis with the precision of seconds - */ - private long truncateMillis(Date date) { - Calendar cal = Calendar.getInstance() - cal.setTime(date) - cal.set(Calendar.MILLISECOND, 0) - return cal.getTimeInMillis() - } -} diff --git a/impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtsTest.groovy deleted file mode 100644 index 93f81801d..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/DeprecatedJwtsTest.groovy +++ /dev/null @@ -1,767 +0,0 @@ -/* - * 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.JwtTokenizer -import io.jsonwebtoken.impl.compression.GzipCompressionAlgorithm -import io.jsonwebtoken.impl.lang.Services -import io.jsonwebtoken.impl.security.TestKeys -import io.jsonwebtoken.io.Encoders -import io.jsonwebtoken.io.Serializer -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.* - -@SuppressWarnings(['GrDeprecatedAPIUsage', 'GrUnnecessarySemicolon']) -class DeprecatedJwtsTest { - - private static Date now() { - return dateWithOnlySecondPrecision(System.currentTimeMillis()); - } - - private static int later() { - def date = laterDate(10000) - def seconds = date.getTime() / 1000 - return seconds as int - } - - private static Date laterDate(int seconds) { - def millis = seconds * 1000L - def time = System.currentTimeMillis() + millis - return dateWithOnlySecondPrecision(time) - } - - private static Date dateWithOnlySecondPrecision(long millis) { - long seconds = (millis / 1000) as long - long secondOnlyPrecisionMillis = seconds * 1000 - return new Date(secondOnlyPrecisionMillis) - } - - 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 = Services.loadFirst(Serializer) - byte[] bytes = serializer.serialize(o) - return new String(bytes, Strings.UTF_8) - } - - @Test - void testSubclass() { - new Jwts() - } - - @Test - void testHeaderWithNoArgs() { - def header = Jwts.header().build() - assertTrue header instanceof DefaultHeader - } - - @Test - void testHeaderWithMapArg() { - def header = Jwts.header().set([alg: "HS256"]).build() - assertTrue header instanceof DefaultJwsHeader - assertEquals 'HS256', header.getAlgorithm() - assertEquals 'HS256', header.alg - } - - @Test - void testClaims() { - Claims claims = Jwts.claims().build() - assertNotNull claims - } - - @Test - void testClaimsWithMapArg() { - Claims claims = Jwts.claims([sub: 'Joe']) - assertNotNull claims - assertEquals claims.getSubject(), 'Joe' - } - - @Test - void testContentJwtString() { - - // 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: - - //noinspection HttpUrlsUsage - 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 testParseContentToken() { - - def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true] - - String jwt = Jwts.builder().setClaims(claims).compact(); - - def token = Jwts.parserBuilder().enableUnsecuredJws().build().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) { - String expected = JwtTokenizer.DELIM_ERR_MSG_PREFIX + '0' - assertEquals expected, e.message - } - } - - @Test - void testParseWithOnePeriodOnly() { - try { - Jwts.parser().parse('.') - fail() - } catch (MalformedJwtException e) { - String expected = JwtTokenizer.DELIM_ERR_MSG_PREFIX + '1' - assertEquals expected, e.message - } - } - - @Test(expected = MalformedJwtException) - void testParseWithTwoPeriodsOnly() { - Jwts.parser().parse('..') - } - - @Test - void testParseWithHeaderOnly() { - String unsecuredJwt = base64Url("{\"alg\":\"none\"}") + ".." - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parse(unsecuredJwt) - assertEquals("none", jwt.getHeader().get("alg")) - } - - @Test(expected = MalformedJwtException) - void testParseWithSignatureOnly() { - Jwts.parser().parse('..bar') - } - - @Test - void testConvenienceIssuer() { - String compact = Jwts.builder().setIssuer("Me").compact(); - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().parse(compact).body as Claims - assertNull claims.getIssuer() - } - - @Test - void testConvenienceSubject() { - String compact = Jwts.builder().setSubject("Joe").compact(); - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().parse(compact).body as Claims - assertNull claims.getSubject() - } - - @Test - void testConvenienceAudience() { - String compact = Jwts.builder().setAudience("You").compact(); - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().parse(compact).body as Claims - assertNull claims.getAudience() - } - - @Test - void testConvenienceExpiration() { - Date then = laterDate(10000) - String compact = Jwts.builder().setExpiration(then).compact(); - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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.parserBuilder().enableUnsecuredJws().build().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(Jwts.ZIP.DEF).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(Jwts.ZIP.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 GzipCompressionAlgorithm() { - @Override - String getId() { - return "CUSTOM" - } - }).compact() - - def jws = Jwts.parser().setSigningKey(key).setCompressionCodecResolver(new CompressionCodecResolver() { - @Override - CompressionCodec resolveCompressionCodec(Header header) throws CompressionException { - String algorithm = header.getCompressionAlgorithm() - //noinspection ChangeToOperator - if ("CUSTOM".equals(algorithm)) { - return Jwts.ZIP.GZIP as CompressionCodec - } 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 = UnsupportedJwtException.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 GzipCompressionAlgorithm() { - @Override - String getId() { - 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(Jwts.ZIP.DEF).compact() - - def jws = Jwts.parser().setSigningKey(key).parseContentJws(compact) - - byte[] parsed = jws.body - - assertEquals "DEF", jws.header.getCompressionAlgorithm() - - assertEquals "this is my test for a payload", Strings.utf8(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() { - def alg = SignatureAlgorithm.ES256; - try { - testEC(alg, true) - fail("EC private keys cannot be used to validate EC signatures.") - } catch (UnsupportedJwtException e) { - String msg = "${alg.name()} verification keys must be PublicKeys (implement java.security.PublicKey). " + - "Provided key type: sun.security.ec.ECPrivateKeyImpl." - assertEquals msg, e.cause.message - } - } - - @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() - - //noinspection GroovyUnusedCatchParameter - 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.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(notSigned) - fail('parseClaimsJws must fail for unsigned JWTs') - } catch (UnsupportedJwtException expected) { - assertEquals 'Unprotected Claims JWTs are not supported.', expected.message - } - } - - //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 'none', Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(forged).getHeader().get('alg') - - //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.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parse(forged) - fail("Parsing must fail for a forged token.") - } catch (MalformedJwtException expected) { - assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', expected.message - } - } - - //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 = TestKeys.RS256.pair - 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 = TestKeys.RS256.pair - 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 = TestKeys.ES256.pair - 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) - - //noinspection GrEqualsBetweenInconvertibleTypes - 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) - - //noinspection GrEqualsBetweenInconvertibleTypes - 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) - - //noinspection GrEqualsBetweenInconvertibleTypes - assert token.header == [alg: alg.name()] - //noinspection GrEqualsBetweenInconvertibleTypes - assert token.body == claims - } -} - diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy index 06b97c02f..90d7e3965 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy @@ -53,12 +53,12 @@ class JwtParserTest { @Test void testIsSignedWithNullArgument() { - assertFalse Jwts.parserBuilder().build().isSigned(null) + assertFalse Jwts.parser().build().isSigned(null) } @Test void testIsSignedWithJunkArgument() { - assertFalse Jwts.parserBuilder().build().isSigned('hello') + assertFalse Jwts.parser().build().isSigned('hello') } @Test @@ -69,7 +69,7 @@ class JwtParserTest { String bad = base64Url('{"alg":"none"}') + '.' + base64Url(junkPayload) + '.' try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(bad) + Jwts.parser().enableUnsecuredJws().build().parse(bad) fail() } catch (MalformedJwtException expected) { assertEquals 'Unable to read claims JSON: ' + junkPayload, expected.getMessage() @@ -90,7 +90,7 @@ class JwtParserTest { String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) try { - Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad) + Jwts.parser().setSigningKey(randomKey()).build().parse(bad) fail() } catch (SignatureException se) { assertEquals se.getMessage(), "Unsupported signature algorithm '$badAlgorithmName'".toString() @@ -109,7 +109,7 @@ class JwtParserTest { String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) try { - Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad) + Jwts.parser().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.' @@ -129,7 +129,7 @@ class JwtParserTest { String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(randomKey()).build().parse(bad) + Jwts.parser().enableUnsecuredJws().setSigningKey(randomKey()).build().parse(bad) fail() } catch (MalformedJwtException se) { assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', se.getMessage() @@ -147,7 +147,7 @@ class JwtParserTest { def payload = '{"subject":"Joe"}' String unsecured = base64Url(header) + '.' + base64Url(payload) + '.' try { - Jwts.parserBuilder().build().parse(unsecured) + Jwts.parser().build().parse(unsecured) fail() } catch (UnsupportedJwtException expected) { String msg = DefaultJwtParser.UNSECURED_DISABLED_MSG_PREFIX + '{alg=none}' @@ -167,9 +167,9 @@ class JwtParserTest { //noinspection GrDeprecatedAPIUsage String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, base64Encodedkey).compact() - assertTrue Jwts.parserBuilder().build().isSigned(compact) + assertTrue Jwts.parser().build().isSigned(compact) - def jwt = Jwts.parserBuilder().setSigningKey(base64Encodedkey).build().parse(compact) + def jwt = Jwts.parser().setSigningKey(base64Encodedkey).build().parse(compact) assertEquals payload, new String(jwt.payload as byte[], StandardCharsets.UTF_8) } @@ -182,9 +182,9 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).signWith(key).compact() - assertTrue Jwts.parserBuilder().build().isSigned(compact) + assertTrue Jwts.parser().build().isSigned(compact) - def jwt = Jwts.parserBuilder().setSigningKey(key).build().parse(compact) + def jwt = Jwts.parser().setSigningKey(key).build().parse(compact) assertEquals payload, new String(jwt.payload as byte[], StandardCharsets.UTF_8) } @@ -193,16 +193,16 @@ class JwtParserTest { void testParseNullPayload() { SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256) String compact = Jwts.builder().signWith(key).compact() - assertTrue Jwts.parserBuilder().build().isSigned(compact) + assertTrue Jwts.parser().build().isSigned(compact) - def jwt = Jwts.parserBuilder().setSigningKey(key).build().parse(compact) + def jwt = Jwts.parser().setSigningKey(key).build().parse(compact) assertEquals '', new String(jwt.payload as byte[], StandardCharsets.UTF_8) } @Test void testParseNullPayloadWithoutKey() { String compact = Jwts.builder().compact() - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact) + def jwt = Jwts.parser().enableUnsecuredJws().build().parse(compact) assertEquals 'none', jwt.header.alg assertEquals '', new String(jwt.payload as byte[], StandardCharsets.UTF_8) } @@ -219,7 +219,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setClock(fixedClock).build().parse(compact) + Jwts.parser().enableUnsecuredJws().setClock(fixedClock).build().parse(compact) fail() } catch (ExpiredJwtException e) { // https://github.com/jwtk/jjwt/issues/107 (the Z designator at the end of the timestamp): @@ -237,7 +237,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact) + Jwts.parser().enableUnsecuredJws().build().parse(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -254,7 +254,7 @@ class JwtParserTest { String subject = 'Joe' String compact = Jwts.builder().setSubject(subject).setExpiration(exp).compact() - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) + Jwt jwt = Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -266,7 +266,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) + Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -280,7 +280,7 @@ class JwtParserTest { String subject = 'Joe' String compact = Jwts.builder().setSubject(subject).setNotBefore(exp).compact() - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) + Jwt jwt = Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -292,7 +292,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setNotBefore(exp).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) + Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -310,7 +310,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals payload, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -321,7 +321,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').compact() try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) + Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals e.getMessage(), 'Unprotected Claims JWTs are not supported.' @@ -336,7 +336,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, randomKey()).compact() try { - Jwts.parserBuilder().build().parseContentJwt(compact) + Jwts.parser().build().parseContentJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS256}', e.getMessage() @@ -350,7 +350,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, key).compact() try { - Jwts.parserBuilder().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Signed Claims JWTs are not supported.', e.getMessage() @@ -368,7 +368,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -381,7 +381,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -396,7 +396,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, randomKey()).compact() try { - Jwts.parserBuilder().build().parseClaimsJwt(compact) + Jwts.parser().build().parseClaimsJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Cannot verify JWS signature: unable to locate signature verification key for JWS with header: {alg=HS256}', e.getMessage() @@ -410,7 +410,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').signWith(SignatureAlgorithm.HS256, key).compact() try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJwt(compact) + Jwts.parser().setSigningKey(key).build().parseClaimsJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Signed Claims JWTs are not supported.', e.getMessage() @@ -427,7 +427,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -442,7 +442,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setNotBefore(nbf).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -462,7 +462,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).signWith(SignatureAlgorithm.HS256, key).compact() - def jwt = Jwts.parserBuilder(). + def jwt = Jwts.parser(). setSigningKey(key). build(). parseContentJws(compact) @@ -480,7 +480,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -497,7 +497,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected Claims JWTs are not supported.', e.getMessage() @@ -514,7 +514,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() try { - Jwts.parserBuilder().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Signed Claims JWTs are not supported.', e.getMessage() @@ -534,7 +534,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(sub).signWith(SignatureAlgorithm.HS256, key).compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + Jwt jwt = Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) assertEquals jwt.getPayload().getSubject(), sub } @@ -553,7 +553,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(sub).signWith(SignatureAlgorithm.HS256, key).setExpiration(exp).compact() try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJwt(compact) + Jwts.parser().setSigningKey(key).build().parseClaimsJwt(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -574,7 +574,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(sub).setNotBefore(nbf).signWith(SignatureAlgorithm.HS256, key).compact() try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -593,7 +593,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(compact) + Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -610,7 +610,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key). + Jwts.parser().enableUnsecuredJws().setSigningKey(key). build(). parseClaimsJws(compact) fail() @@ -629,7 +629,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() try { - Jwts.parserBuilder().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Signed Claims JWTs are not supported.', e.getMessage() @@ -656,7 +656,7 @@ class JwtParserTest { } } - Jws jws = Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact) + Jws jws = Jwts.parser().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact) assertEquals jws.getPayload().getSubject(), subject } @@ -678,7 +678,7 @@ class JwtParserTest { } try { - Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact) + Jwts.parser().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact) fail() } catch (SignatureException se) { assertEquals 'JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.', se.getMessage() @@ -695,7 +695,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).signWith(SignatureAlgorithm.HS256, key).compact() try { - Jwts.parserBuilder().setSigningKeyResolver(null).build().parseClaimsJws(compact) + Jwts.parser().setSigningKeyResolver(null).build().parseClaimsJws(compact) fail() } catch (IllegalArgumentException iae) { assertEquals 'SigningKeyResolver cannot be null.', iae.getMessage() @@ -714,7 +714,7 @@ class JwtParserTest { def signingKeyResolver = new SigningKeyResolverAdapter() try { - Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact) + Jwts.parser().setSigningKeyResolver(signingKeyResolver).build().parseClaimsJws(compact) fail() } catch (UnsupportedJwtException ex) { assertEquals 'The specified SigningKeyResolver implementation does not support ' + @@ -742,7 +742,7 @@ class JwtParserTest { claim("long_big", bigLong). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + Jwt jwt = Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) Claims claims = jwt.getPayload() @@ -773,7 +773,7 @@ class JwtParserTest { } } - def jws = Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseContentJws(compact) + def jws = Jwts.parser().setSigningKeyResolver(signingKeyResolver).build().parseContentJws(compact) assertEquals inputPayload, new String(jws.payload, StandardCharsets.UTF_8) } @@ -795,7 +795,7 @@ class JwtParserTest { } try { - Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseContentJws(compact) + Jwts.parser().setSigningKeyResolver(signingKeyResolver).build().parseContentJws(compact) fail() } catch (SignatureException se) { assertEquals 'JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.', se.getMessage() @@ -814,7 +814,7 @@ class JwtParserTest { def signingKeyResolver = new SigningKeyResolverAdapter() try { - Jwts.parserBuilder().setSigningKeyResolver(signingKeyResolver).build().parseContentJws(compact) + Jwts.parser().setSigningKeyResolver(signingKeyResolver).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException ex) { assertEquals ex.getMessage(), 'The specified SigningKeyResolver implementation does not support content ' + @@ -834,7 +834,7 @@ class JwtParserTest { try { // expecting null claim name, but with value - Jwts.parserBuilder().setSigningKey(key).require(null, expectedClaimValue).build().parseClaimsJws(compact) + Jwts.parser().setSigningKey(key).require(null, expectedClaimValue).build().parseClaimsJws(compact) fail() } catch (IllegalArgumentException e) { assertEquals( @@ -857,7 +857,7 @@ class JwtParserTest { try { // expecting null claim name, but with value - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). require("", expectedClaimValue). build(). parseClaimsJws(compact) @@ -881,7 +881,7 @@ class JwtParserTest { try { // expecting claim name, but with null value - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). require(expectedClaimName, null). build(). parseClaimsJws(compact) @@ -905,7 +905,7 @@ class JwtParserTest { claim(expectedClaimName, expectedClaimValue). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). require(expectedClaimName, expectedClaimValue). build(). parseClaimsJws(compact) @@ -927,7 +927,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). require(goodClaimName, goodClaimValue). build(). parseClaimsJws(compact) @@ -952,7 +952,7 @@ class JwtParserTest { compact() try { - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). require(claimName, claimValue). build(). parseClaimsJws(compact) @@ -976,7 +976,7 @@ class JwtParserTest { setIssuedAt(issuedAt). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireIssuedAt(issuedAt). build(). parseClaimsJws(compact) @@ -995,7 +995,7 @@ class JwtParserTest { setIssuedAt(badIssuedAt). compact() - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireIssuedAt(goodIssuedAt). build(). parseClaimsJws(compact) @@ -1011,7 +1011,7 @@ class JwtParserTest { setSubject("Dummy"). compact() - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireIssuedAt(issuedAt). build(). parseClaimsJws(compact) @@ -1027,7 +1027,7 @@ class JwtParserTest { setIssuer(issuer). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireIssuer(issuer). build(). parseClaimsJws(compact) @@ -1047,7 +1047,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireIssuer(goodIssuer). build(). parseClaimsJws(compact) @@ -1071,7 +1071,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireIssuer(issuer). build(). parseClaimsJws(compact) @@ -1094,7 +1094,7 @@ class JwtParserTest { setAudience(audience). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireAudience(audience). build(). parseClaimsJws(compact) @@ -1114,7 +1114,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireAudience(goodAudience). build(). parseClaimsJws(compact) @@ -1138,7 +1138,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireAudience(audience). build(). parseClaimsJws(compact) @@ -1161,7 +1161,7 @@ class JwtParserTest { setSubject(subject). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireSubject(subject). build(). parseClaimsJws(compact) @@ -1181,7 +1181,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireSubject(goodSubject). build(). parseClaimsJws(compact) @@ -1205,7 +1205,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireSubject(subject). build(). parseClaimsJws(compact) @@ -1228,7 +1228,7 @@ class JwtParserTest { setId(id). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireId(id). build(). parseClaimsJws(compact) @@ -1248,7 +1248,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireId(goodId). build(). parseClaimsJws(compact) @@ -1272,7 +1272,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireId(id). build(). parseClaimsJws(compact) @@ -1296,7 +1296,7 @@ class JwtParserTest { setExpiration(expiration). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireExpiration(expiration). build(). parseClaimsJws(compact) @@ -1315,7 +1315,7 @@ class JwtParserTest { setExpiration(badExpiration). compact() - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireExpiration(goodExpiration). build(). parseClaimsJws(compact) @@ -1331,7 +1331,7 @@ class JwtParserTest { setSubject("Dummy"). compact() - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireExpiration(expiration). build(). parseClaimsJws(compact) @@ -1348,7 +1348,7 @@ class JwtParserTest { setNotBefore(notBefore). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). requireNotBefore(notBefore). build(). parseClaimsJws(compact) @@ -1367,7 +1367,7 @@ class JwtParserTest { setNotBefore(badNotBefore). compact() - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireNotBefore(goodNotBefore). build(). parseClaimsJws(compact) @@ -1383,7 +1383,7 @@ class JwtParserTest { setSubject("Dummy"). compact() - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). requireNotBefore(notBefore). build(). parseClaimsJws(compact) @@ -1400,7 +1400,7 @@ class JwtParserTest { claim("aDate", aDate). compact() - Jwt jwt = Jwts.parserBuilder().setSigningKey(key). + Jwt jwt = Jwts.parser().setSigningKey(key). require("aDate", aDate). build(). parseClaimsJws(compact) @@ -1422,7 +1422,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). require("aDate", goodDate). build(). parseClaimsJws(compact) @@ -1447,7 +1447,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). require("aDate", goodDate). build(). parseClaimsJws(compact) @@ -1471,7 +1471,7 @@ class JwtParserTest { compact() try { - Jwts.parserBuilder().setSigningKey(key). + Jwts.parser().setSigningKey(key). require("aDate", aDate). build(). parseClaimsJws(compact) @@ -1492,12 +1492,12 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() - Jwts.parserBuilder().enableUnsecuredJws().setClock(new FixedClock(beforeExpiry)).build().parse(compact) + Jwts.parser().enableUnsecuredJws().setClock(new FixedClock(beforeExpiry)).build().parse(compact) } @Test void testParseClockManipulationWithNullClock() { - JwtParserBuilder parser = Jwts.parserBuilder(); + JwtParserBuilder parser = Jwts.parser(); try { parser.setClock(null) fail() @@ -1512,7 +1512,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setClock(new DefaultClock()).build().parse(compact) + Jwts.parser().enableUnsecuredJws().setClock(new DefaultClock()).build().parse(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -1533,7 +1533,7 @@ class JwtParserTest { String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) + '.' + base64Url(bogus) try { - Jwts.parserBuilder().setSigningKey(randomKey()).build().parse(bad) + Jwts.parser().setSigningKey(randomKey()).build().parse(bad) fail() } catch (MalformedJwtException se) { String expected = JwtTokenizer.DELIM_ERR_MSG_PREFIX + '3' @@ -1549,7 +1549,7 @@ class JwtParserTest { String jwtStr = '.' + base64Url(payload) + '.' try { - Jwts.parserBuilder().build().parse(jwtStr) + Jwts.parser().build().parse(jwtStr) fail() } catch (MalformedJwtException e) { assertEquals 'Compact JWT strings MUST always have a Base64Url protected header per https://tools.ietf.org/html/rfc7519#section-7.2 (steps 2-4).', e.getMessage() @@ -1566,7 +1566,7 @@ class JwtParserTest { String jwtStr = '.' + base64Url(payload) + '.' + base64Url(sig) try { - Jwts.parserBuilder().build().parse(jwtStr) + Jwts.parser().build().parse(jwtStr) fail() } catch (MalformedJwtException se) { assertEquals 'Compact JWT strings MUST always have a Base64Url protected header per https://tools.ietf.org/html/rfc7519#section-7.2 (steps 2-4).', se.message @@ -1585,7 +1585,7 @@ class JwtParserTest { String jwtStr = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(sig) try { - Jwts.parserBuilder().enableUnsecuredJws().build().parse(jwtStr) + Jwts.parser().enableUnsecuredJws().build().parse(jwtStr) fail() } catch (MalformedJwtException se) { assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', se.message diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index 54045f4b3..c4dee7712 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -118,7 +118,7 @@ class JwtsTest { def encodedClaims = base64Url(claimsString) def compact = encodedHeader + '.' + encodedClaims + '.AAD=' try { - Jwts.parserBuilder().build().parseClaimsJws(compact) + Jwts.parser().build().parseClaimsJws(compact) fail() } catch (MalformedJwtException e) { String expected = 'Invalid protected header: Invalid JWS header \'jku\' (JWK Set URL) value: 42. ' + @@ -141,7 +141,7 @@ class JwtsTest { def sig = Encoders.BASE64URL.encode(result) def compact = "$h.$c.$sig" as String try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) fail() } catch (MalformedJwtException e) { String expected = 'Invalid claims: Invalid JWT Claim \'exp\' (Expiration Time) value: -42-. ' + @@ -166,7 +166,7 @@ class JwtsTest { String s = 'Hello JJWT' String cty = 'text/plain' String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals cty, jwt.header.getContentType() assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -177,7 +177,7 @@ class JwtsTest { String subtype = 'foo' String cty = "application/$subtype" String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals subtype, jwt.header.getContentType() // assert that the compact form was used assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -188,7 +188,7 @@ class JwtsTest { String subtype = 'foo' String cty = "application/$subtype;part=1/2" String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals cty, jwt.header.getContentType() // two slashes, can't compact assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) } @@ -200,7 +200,7 @@ class JwtsTest { String jwt = Jwts.builder().setClaims(claims).compact() - def token = Jwts.parserBuilder().enableUnsecuredJws().build().parse(jwt) + def token = Jwts.parser().enableUnsecuredJws().build().parse(jwt) //noinspection GrEqualsBetweenInconvertibleTypes assert token.payload == claims @@ -208,17 +208,17 @@ class JwtsTest { @Test(expected = IllegalArgumentException) void testParseNull() { - Jwts.parserBuilder().build().parse(null) + Jwts.parser().build().parse(null) } @Test(expected = IllegalArgumentException) void testParseEmptyString() { - Jwts.parserBuilder().build().parse('') + Jwts.parser().build().parse('') } @Test(expected = IllegalArgumentException) void testParseWhitespaceString() { - Jwts.parserBuilder().build().parse(' ') + Jwts.parser().build().parse(' ') } @Test @@ -230,7 +230,7 @@ class JwtsTest { String claims = Encoders.BASE64URL.encode(claimsJson.getBytes(StandardCharsets.UTF_8)) String compact = header + '.' + claims + '.' - def jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) + def jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) assertEquals 'none', jwt.header.getAlgorithm() assertEquals 'joe', jwt.payload.getSubject() } @@ -238,7 +238,7 @@ class JwtsTest { @Test void testParseWithNoPeriods() { try { - Jwts.parserBuilder().build().parse('foo') + Jwts.parser().build().parse('foo') fail() } catch (MalformedJwtException e) { //noinspection GroovyAccessibility @@ -250,7 +250,7 @@ class JwtsTest { @Test void testParseWithOnePeriodOnly() { try { - Jwts.parserBuilder().build().parse('.') + Jwts.parser().build().parse('.') fail() } catch (MalformedJwtException e) { //noinspection GroovyAccessibility @@ -262,7 +262,7 @@ class JwtsTest { @Test void testParseWithTwoPeriodsOnly() { try { - Jwts.parserBuilder().build().parse('..') + Jwts.parser().build().parse('..') fail() } catch (MalformedJwtException e) { String msg = 'Compact JWT strings MUST always have a Base64Url protected header per ' + @@ -274,14 +274,14 @@ class JwtsTest { @Test void testParseWithHeaderOnly() { String unsecuredJwt = base64Url("{\"alg\":\"none\"}") + ".." - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parse(unsecuredJwt) + Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parse(unsecuredJwt) assertEquals "none", jwt.getHeader().get("alg") } @Test void testParseWithSignatureOnly() { try { - Jwts.parserBuilder().build().parse('..bar') + Jwts.parser().build().parse('..bar') fail() } catch (MalformedJwtException e) { assertEquals 'Compact JWT strings MUST always have a Base64Url protected header per https://tools.ietf.org/html/rfc7519#section-7.2 (steps 2-4).', e.message @@ -295,7 +295,7 @@ class JwtsTest { int i = compact.lastIndexOf('.') String missingSig = compact.substring(0, i + 1) try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(missingSig) + Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(missingSig) fail() } catch (MalformedJwtException expected) { String s = String.format(DefaultJwtParser.MISSING_JWS_DIGEST_MSG_FMT, 'HS256') @@ -315,7 +315,7 @@ class JwtsTest { @Test void testConvenienceIssuer() { String compact = Jwts.builder().setIssuer("Me").compact() - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertEquals 'Me', claims.getIssuer() compact = Jwts.builder().setSubject("Joe") @@ -323,14 +323,14 @@ class JwtsTest { .setIssuer(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getIssuer() } @Test void testConvenienceSubject() { String compact = Jwts.builder().setSubject("Joe").compact() - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertEquals 'Joe', claims.getSubject() compact = Jwts.builder().setIssuer("Me") @@ -338,14 +338,14 @@ class JwtsTest { .setSubject(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getSubject() } @Test void testConvenienceAudience() { String compact = Jwts.builder().setAudience("You").compact() - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertEquals 'You', claims.getAudience() compact = Jwts.builder().setIssuer("Me") @@ -353,7 +353,7 @@ class JwtsTest { .setAudience(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getAudience() } @@ -361,7 +361,7 @@ class JwtsTest { void testConvenienceExpiration() { Date then = laterDate(10000) String compact = Jwts.builder().setExpiration(then).compact() - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims def claimedDate = claims.getExpiration() assertEquals then, claimedDate @@ -370,7 +370,7 @@ class JwtsTest { .setExpiration(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getExpiration() } @@ -378,7 +378,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.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims def claimedDate = claims.getNotBefore() assertEquals now, claimedDate @@ -387,7 +387,7 @@ class JwtsTest { .setNotBefore(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getNotBefore() } @@ -395,7 +395,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.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims def claimedDate = claims.getIssuedAt() assertEquals now, claimedDate @@ -404,7 +404,7 @@ class JwtsTest { .setIssuedAt(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getIssuedAt() } @@ -412,7 +412,7 @@ class JwtsTest { void testConvenienceId() { String id = UUID.randomUUID().toString() String compact = Jwts.builder().setId(id).compact() - Claims claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertEquals id, claims.getId() compact = Jwts.builder().setIssuer("Me") @@ -420,7 +420,7 @@ class JwtsTest { .setId(null) //null should remove it .compact() - claims = Jwts.parserBuilder().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims assertNull claims.getId() } @@ -435,7 +435,7 @@ class JwtsTest { String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(key, alg) .claim("state", "hello this is an amazing jwt").compact() - def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + def jws = Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) Claims claims = jws.payload @@ -457,7 +457,7 @@ class JwtsTest { String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(key, alg) .claim("state", "hello this is an amazing jwt").compressWith(Jwts.ZIP.DEF).compact() - def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + def jws = Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) Claims claims = jws.payload @@ -479,7 +479,7 @@ class JwtsTest { String compact = Jwts.builder().setId(id).setAudience("an audience").signWith(key, alg) .claim("state", "hello this is an amazing jwt").compressWith(Jwts.ZIP.GZIP).compact() - def jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + def jws = Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) Claims claims = jws.payload @@ -506,7 +506,7 @@ class JwtsTest { } }).compact() - def jws = Jwts.parserBuilder().setSigningKey(key).setCompressionCodecResolver(new CompressionCodecResolver() { + def jws = Jwts.parser().setSigningKey(key).setCompressionCodecResolver(new CompressionCodecResolver() { @Override CompressionCodec resolveCompressionCodec(Header header) throws CompressionException { String algorithm = header.getCompressionAlgorithm() @@ -545,7 +545,7 @@ class JwtsTest { } }).compact() - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact) + Jwts.parser().setSigningKey(key).build().parseClaimsJws(compact) } @Test @@ -559,7 +559,7 @@ class JwtsTest { String compact = Jwts.builder().setPayload(payload).signWith(key, alg) .compressWith(Jwts.ZIP.DEF).compact() - def jws = Jwts.parserBuilder().setSigningKey(key).build().parseContentJws(compact) + def jws = Jwts.parser().setSigningKey(key).build().parseContentJws(compact) assertEquals "DEF", jws.header.getCompressionAlgorithm() @@ -678,7 +678,7 @@ class JwtsTest { String jws = Jwts.builder().setSubject("Foo").signWith(key, alg).compact() - Jwts.parserBuilder().setSigningKey(weakKey).build().parseClaimsJws(jws) + Jwts.parser().setSigningKey(weakKey).build().parseClaimsJws(jws) fail('parseClaimsJws must fail for weak keys') } @@ -722,7 +722,7 @@ class JwtsTest { void testParserWithMismatchedEllipticCurveKeyAndAlgorithm() { def pair = TestKeys.ES256.pair def jws = Jwts.builder().setSubject('foo').signWith(pair.private).compact() - def parser = Jwts.parserBuilder().setSigningKey(TestKeys.ES384.pair.public).build() + def parser = Jwts.parser().setSigningKey(TestKeys.ES384.pair.public).build() try { parser.parseClaimsJws(jws) } catch (UnsupportedJwtException expected) { @@ -745,7 +745,7 @@ class JwtsTest { def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ" String jws = withoutSignature + '.' + invalidEncodedSignature def keypair = Jwts.SIG.ES256.keyPairBuilder().build() - Jwts.parserBuilder().setSigningKey(keypair.public).build().parseClaimsJws(jws) + Jwts.parser().setSigningKey(keypair.public).build().parseClaimsJws(jws) } //Asserts correct/expected behavior discussed in https://github.com/jwtk/jjwt/issues/20 @@ -759,7 +759,7 @@ class JwtsTest { String notSigned = Jwts.builder().setSubject("Foo").compact() try { - Jwts.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(notSigned) + Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(notSigned) fail('parseClaimsJws must fail for unsigned JWTs') } catch (UnsupportedJwtException expected) { assertEquals 'Unprotected Claims JWTs are not supported.', expected.message @@ -775,7 +775,7 @@ class JwtsTest { def c = base64Url('{"sub":"joe"}') def compact = h + '.ecek.iv.' + c + '.tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { assertEquals DefaultJwtParser.MISSING_JWE_ALG_MSG, e.getMessage() @@ -791,7 +791,7 @@ class JwtsTest { def c = base64Url('{"sub":"joe"}') def compact = h + '.ecek.iv.' + c + '.tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { assertEquals DefaultJwtParser.MISSING_JWE_ALG_MSG, e.getMessage() @@ -807,7 +807,7 @@ class JwtsTest { def c = base64Url('{"sub":"joe"}') def compact = h + '.ecek.iv.' + c + '.tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { assertEquals DefaultJwtParser.MISSING_JWE_ALG_MSG, e.getMessage() @@ -823,7 +823,7 @@ class JwtsTest { def c = base64Url('{"sub":"joe"}') def compact = h + '.ecek.iv.' + c + '.tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { assertEquals DefaultJwtParser.JWE_NONE_MSG, e.getMessage() @@ -839,7 +839,7 @@ class JwtsTest { def c = base64Url('{"sub":"joe"}') def compact = h + '.ecek.iv.' + c + '.' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { String expected = String.format(DefaultJwtParser.MISSING_JWE_DIGEST_MSG_FMT, 'dir') @@ -858,7 +858,7 @@ class JwtsTest { def tag = '&' def compact = h + '.IA==.IA==.' + c + '.' + tag try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { String expected = 'Compact JWE strings must always contain an AAD Authentication Tag.' @@ -874,7 +874,7 @@ class JwtsTest { def h = base64Url('{"alg":"dir","enc":"A128GCM"}') def compact = h + '.ecek.iv..tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { String expected = 'Compact JWE strings MUST always contain a payload (ciphertext).' @@ -893,7 +893,7 @@ class JwtsTest { def encodedKey = '&' def compact = h + '.' + encodedKey + '.iv.' + c + '.tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { String expected = 'Compact JWE string represents an encrypted key, but the key is empty.' @@ -910,7 +910,7 @@ class JwtsTest { def c = base64Url('{"sub":"joe"}') def compact = h + '.IA==..' + c + '.tag' try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { String expected = 'Compact JWE strings must always contain an Initialization Vector.' @@ -930,7 +930,7 @@ class JwtsTest { def tag = 'IA==' def compact = "$h.$ekey.$iv.$c.$tag" as String try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (MalformedJwtException e) { assertEquals DefaultJwtParser.MISSING_ENC_MSG, e.getMessage() @@ -949,7 +949,7 @@ class JwtsTest { def tag = 'IA==' def compact = "$h.$ekey.$iv.$c.$tag" as String try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (UnsupportedJwtException e) { String expected = "Unrecognized JWE 'enc' (Encryption Algorithm) header value: foo" @@ -969,7 +969,7 @@ class JwtsTest { def tag = 'IA==' def compact = "$h.$ekey.$iv.$c.$tag" as String try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (UnsupportedJwtException e) { String expected = "Unrecognized JWE 'alg' (Algorithm) header value: bar" @@ -987,7 +987,7 @@ class JwtsTest { def sig = 'IA==' def compact = "$h.$c.$sig" as String try { - Jwts.parserBuilder().build().parseClaimsJws(compact) + Jwts.parser().build().parseClaimsJws(compact) fail() } catch (io.jsonwebtoken.security.SignatureException e) { String expected = "Unsupported signature algorithm 'bar'" @@ -1007,7 +1007,7 @@ class JwtsTest { def tag = 'IA==' def compact = "$h.$ekey.$iv.$c.$tag" as String try { - Jwts.parserBuilder().build().parseClaimsJwe(compact) + Jwts.parser().build().parseClaimsJwe(compact) fail() } catch (UnsupportedJwtException e) { String expected = "Cannot decrypt JWE payload: unable to locate key for JWE with header: {alg=dir, enc=A128GCM}" @@ -1052,7 +1052,7 @@ class JwtsTest { def jws = Jwts.builder().setSubject("joe").signWith(key, alg).compact() - assertEquals 'joe', Jwts.parserBuilder() + assertEquals 'joe', Jwts.parser() .addSignatureAlgorithms([alg]) .setSigningKey(key) .build() @@ -1096,7 +1096,7 @@ class JwtsTest { def jwe = Jwts.builder().setSubject("joe").encryptWith(key, encAlg).compact() - assertEquals 'joe', Jwts.parserBuilder() + assertEquals 'joe', Jwts.parser() .addEncryptionAlgorithms([encAlg]) .decryptWith(key) .build() @@ -1134,7 +1134,7 @@ class JwtsTest { } try { - Jwts.parserBuilder() + Jwts.parser() .setKeyLocator(new ConstantKeyLocator(TestKeys.HS256, TestKeys.A128GCM)) .addKeyAlgorithms([badKeyAlg]) // <-- add bad alg here .build() @@ -1154,7 +1154,7 @@ class JwtsTest { void testParseRequiredInt() { def key = TestKeys.HS256 def jws = Jwts.builder().signWith(key).claim("foo", 42).compact() - Jwts.parserBuilder().setSigningKey(key) + Jwts.parser().setSigningKey(key) .require("foo", 42L) //require a long, but jws contains int, should still work .build().parseClaimsJws(jws) } @@ -1178,14 +1178,14 @@ class JwtsTest { String forged = Jwts.builder().setSubject("Not Joe").compact() //assert that our forged header has a 'NONE' algorithm: - assertEquals 'none', Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(forged).getHeader().get('alg') + assertEquals 'none', Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(forged).getHeader().get('alg') //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.parserBuilder().enableUnsecuredJws().setSigningKey(key).build().parse(forged) + Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parse(forged) fail("Parsing must fail for a forged token.") } catch (MalformedJwtException expected) { assertEquals 'The JWS header references signature algorithm \'none\' yet the compact JWS string contains a signature. This is not permitted per https://tools.ietf.org/html/rfc7518#section-3.6.', expected.message @@ -1217,7 +1217,7 @@ class JwtsTest { // Assert that the server (that should always use the private key) does not recognized the forged token: try { - Jwts.parserBuilder().setSigningKey(privateKey).build().parse(forged) + Jwts.parser().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') @@ -1249,7 +1249,7 @@ class JwtsTest { // Assert that the parser does not recognized the forged token: try { - Jwts.parserBuilder().setSigningKey(publicKey).build().parse(forged) + Jwts.parser().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') @@ -1281,7 +1281,7 @@ class JwtsTest { // Assert that the parser does not recognized the forged token: try { - Jwts.parserBuilder().setSigningKey(publicKey).build().parse(forged) + Jwts.parser().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') @@ -1310,7 +1310,7 @@ class JwtsTest { .compact() //decrypt: - def jwt = Jwts.parserBuilder() + def jwt = Jwts.parser() .decryptWith(key) .build() .parseClaimsJwe(jwe) @@ -1338,7 +1338,7 @@ class JwtsTest { .compact() //decompress and decrypt: - def jwt = Jwts.parserBuilder() + def jwt = Jwts.parser() .decryptWith(key) .build() .parseClaimsJwe(jwe) @@ -1367,7 +1367,7 @@ class JwtsTest { .compact() //decrypt: - def jwt = Jwts.parserBuilder() + def jwt = Jwts.parser() .decryptWith(key) .build() .parseClaimsJwe(jwe) @@ -1388,7 +1388,7 @@ class JwtsTest { .compact() //decrypt: - def jwt = Jwts.parserBuilder() + def jwt = Jwts.parser() .decryptWith(key) .build() .parseClaimsJwe(jwe) @@ -1421,7 +1421,7 @@ class JwtsTest { .compact() //decrypt: - def jwt = Jwts.parserBuilder() + def jwt = Jwts.parser() .decryptWith(privKey) .build() .parseClaimsJwe(jwe) @@ -1456,7 +1456,7 @@ class JwtsTest { .compact() //decrypt: - def jwt = Jwts.parserBuilder() + def jwt = Jwts.parser() .decryptWith(privKey) .build() .parseClaimsJwe(jwe) @@ -1560,7 +1560,7 @@ class JwtsTest { } static Jwe decrypt(String jwe, PrivateKey key) { - return Jwts.parserBuilder().decryptWith(key).build().parseClaimsJwe(jwe) + return Jwts.parser().decryptWith(key).build().parseClaimsJwe(jwe) } static void testRsa(io.jsonwebtoken.security.SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) { @@ -1578,7 +1578,7 @@ class JwtsTest { key = privateKey } - def token = Jwts.parserBuilder().verifyWith(key).build().parse(jwt) + def token = Jwts.parser().verifyWith(key).build().parse(jwt) assertEquals([alg: alg.getId()], token.header) assertEquals(claims, token.payload) @@ -1593,7 +1593,7 @@ class JwtsTest { String jwt = Jwts.builder().setClaims(claims).signWith(key, alg).compact() - def token = Jwts.parserBuilder().verifyWith(key).build().parse(jwt) + def token = Jwts.parser().verifyWith(key).build().parse(jwt) assertEquals([alg: alg.getId()], token.header) assertEquals(claims, token.payload) @@ -1614,7 +1614,7 @@ class JwtsTest { key = privateKey } - def token = Jwts.parserBuilder().verifyWith(key).build().parse(jwt) + def token = Jwts.parser().verifyWith(key).build().parse(jwt) assertEquals([alg: alg.getId()], token.header) assertEquals(claims, token.payload) diff --git a/impl/src/test/groovy/io/jsonwebtoken/RsaSigningKeyResolverAdapterTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/RsaSigningKeyResolverAdapterTest.groovy index 8f653c426..7abedf882 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/RsaSigningKeyResolverAdapterTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/RsaSigningKeyResolverAdapterTest.groovy @@ -32,7 +32,7 @@ class RsaSigningKeyResolverAdapterTest { def compact = Jwts.builder().claim('foo', 'bar').signWith(pair.private, alg).compact() - Jws jws = Jwts.parserBuilder().setSigningKey(pair.public).build().parseClaimsJws(compact) + Jws jws = Jwts.parser().setSigningKey(pair.public).build().parseClaimsJws(compact) try { new SigningKeyResolverAdapter().resolveSigningKey(jws.header, jws.payload) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy index 88da99e8d..67a3f2290 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy @@ -30,7 +30,7 @@ class DefaultJweTest { def alg = Jwts.ENC.A128CBC_HS256 as AeadAlgorithm def key = alg.keyBuilder().build() String compact = Jwts.builder().claim('foo', 'bar').encryptWith(key, alg).compact() - def jwe = Jwts.parserBuilder().decryptWith(key).build().parseClaimsJwe(compact) + def jwe = Jwts.parser().decryptWith(key).build().parseClaimsJwe(compact) String encodedIv = Encoders.BASE64URL.encode(jwe.initializationVector) String encodedTag = Encoders.BASE64URL.encode(jwe.digest) String expected = "header={alg=dir, enc=A128CBC-HS256},payload={foo=bar},tag=$encodedTag,iv=$encodedIv" @@ -42,7 +42,7 @@ class DefaultJweTest { def alg = Jwts.ENC.A128CBC_HS256 as AeadAlgorithm def key = alg.keyBuilder().build() String compact = Jwts.builder().claim('foo', 'bar').encryptWith(key, alg).compact() - def parser = Jwts.parserBuilder().decryptWith(key).build() + def parser = Jwts.parser().decryptWith(key).build() def jwe1 = parser.parseClaimsJwe(compact) def jwe2 = parser.parseClaimsJwe(compact) assertNotEquals jwe1, 'hello' as String diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy index 0cfae6bab..b2393c5f3 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy @@ -40,7 +40,7 @@ class DefaultJwsTest { String compact = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() int i = compact.lastIndexOf('.') String signature = compact.substring(i + 1) - def jws = Jwts.parserBuilder().verifyWith(key).build().parseClaimsJws(compact) + def jws = Jwts.parser().verifyWith(key).build().parseClaimsJws(compact) assertEquals 'header={alg=HS256},payload={foo=bar},signature=' + signature, jws.toString() } @@ -49,7 +49,7 @@ class DefaultJwsTest { def alg = Jwts.SIG.HS256 def key = alg.keyBuilder().build() String compact = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() - def parser = Jwts.parserBuilder().verifyWith(key).build() + def parser = Jwts.parser().verifyWith(key).build() def jws1 = parser.parseClaimsJws(compact) def jws2 = parser.parseClaimsJws(compact) assertNotEquals jws1, 'hello' as String diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index 64e10077d..850eadb27 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -444,7 +444,7 @@ class DefaultJwtBuilderTest { .claim('foo', 'bar') .compact() - assertEquals 'bar', Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jws).getPayload().get('foo') + assertEquals 'bar', Jwts.parser().setSigningKey(key).build().parseClaimsJws(jws).getPayload().get('foo') } @Test @@ -476,7 +476,7 @@ class DefaultJwtBuilderTest { def enc = Jwts.ENC.A128GCM def key = enc.keyBuilder().build() def jwe = builder.setPayload("me").encryptWith(key, enc).compact() - def jwt = Jwts.parserBuilder().decryptWith(key).build().parseContentJwe(jwe) + def jwt = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe) assertEquals 'me', new String(jwt.getPayload(), StandardCharsets.UTF_8) } @@ -485,7 +485,7 @@ class DefaultJwtBuilderTest { def enc = Jwts.ENC.A128GCM def key = enc.keyBuilder().build() def jwe = builder.setSubject('joe').encryptWith(key, enc).compact() - def jwt = Jwts.parserBuilder().decryptWith(key).build().parseClaimsJwe(jwe) + def jwt = Jwts.parser().decryptWith(key).build().parseClaimsJwe(jwe) assertEquals 'joe', jwt.getPayload().getSubject() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index eedb82abe..eb217265c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -18,6 +18,7 @@ package io.jsonwebtoken.impl import com.fasterxml.jackson.databind.ObjectMapper import io.jsonwebtoken.* import io.jsonwebtoken.impl.security.ConstantKeyLocator +import io.jsonwebtoken.impl.security.LocatingKeyResolver import io.jsonwebtoken.impl.security.TestKeys import io.jsonwebtoken.io.Decoder import io.jsonwebtoken.io.DecodingException @@ -54,10 +55,24 @@ class DefaultJwtParserBuilderTest { def parser = builder.setProvider(provider).build() - assertSame provider, parser.jwtParser.provider + assertSame provider, parser.provider verify provider } + @Test + void testKeyLocatorAndVerificationKeyConfigured() { + try { + builder + .setKeyLocator(new ConstantKeyLocator(null, null)) + .verifyWith(TestKeys.HS256) + .build() + fail() + } catch (IllegalStateException e) { + String msg = "Both 'keyLocator' and a 'verifyWith' key cannot be configured. Prefer 'keyLocator' if possible." + assertEquals msg, e.getMessage() + } + } + @Test void testKeyLocatorAndDecryptionKeyConfigured() { try { @@ -67,7 +82,7 @@ class DefaultJwtParserBuilderTest { .build() fail() } catch (IllegalStateException e) { - String msg = "Both 'keyLocator' and 'decryptWith' key cannot be configured. Prefer 'keyLocator' if possible." + String msg = "Both 'keyLocator' and a 'decryptWith' key cannot be configured. Prefer 'keyLocator' if possible." assertEquals msg, e.getMessage() } } @@ -85,7 +100,7 @@ class DefaultJwtParserBuilderTest { return null } } - def b = builder.base64UrlDecodeWith(decoder) + def b = builder.base64UrlDecodeWith(decoder).build() assertSame decoder, b.base64UrlDecoder } @@ -139,7 +154,7 @@ class DefaultJwtParserBuilderTest { } } def parser = builder.setCompressionCodecResolver(resolver).build() - assertSame resolver, parser.jwtParser.compressionAlgorithmLocator.resolver + assertSame resolver, parser.zipAlgFn.resolver } @Test @@ -147,7 +162,7 @@ class DefaultJwtParserBuilderTest { def codec = new TestCompressionCodec(id: 'test') def parser = builder.addCompressionAlgorithms([codec] as Set).build() def header = Jwts.header().setCompressionAlgorithm(codec.getId()).build() - assertSame codec, parser.jwtParser.compressionAlgorithmLocator.locate(header) + assertSame codec, parser.zipAlgFn.locate(header) } @Test @@ -203,10 +218,7 @@ class DefaultJwtParserBuilderTest { @Test void testDefaultDeserializer() { JwtParser parser = builder.build() - assertThat parser.jwtParser.deserializer, CoreMatchers.instanceOf(JwtDeserializer) - - // TODO: When the ImmutableJwtParser replaces the default implementation this test will need updating, something like: - // assertThat parser.deserializer, CoreMatchers.instanceOf(JwtDeserializer) + assertThat parser.deserializer, CoreMatchers.instanceOf(JwtDeserializer) } @Test @@ -214,20 +226,19 @@ class DefaultJwtParserBuilderTest { Deserializer deserializer = niceMock(Deserializer) JwtParser parser = builder.deserializeJsonWith(deserializer).build() - // TODO: When the ImmutableJwtParser replaces the default implementation this test will need updating - assertThat parser.jwtParser.deserializer, CoreMatchers.instanceOf(JwtDeserializer) - assertSame deserializer, parser.jwtParser.deserializer.deserializer + assertThat parser.deserializer, CoreMatchers.instanceOf(JwtDeserializer) + assertSame deserializer, parser.deserializer.deserializer } @Test void testVerificationKeyAndSigningKeyResolverBothConfigured() { def key = TestKeys.HS256 - builder.verifyWith(key).setSigningKeyResolver(new ConstantKeyLocator(key, null)) + builder.verifyWith(key).setSigningKeyResolver(new LocatingKeyResolver(new ConstantKeyLocator(key, null))) try { builder.build() fail() } catch (IllegalStateException expected) { - String msg = "Both 'signingKeyResolver and 'verifyWith/signWith' key cannot be configured. " + "Choose either, or prefer `keyLocator` when possible." + String msg = "Both a 'signingKeyResolver and a 'verifyWith' key cannot be configured. " + "Choose either, or prefer `keyLocator` when possible." assertEquals(msg, expected.getMessage()) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy index 2dd71c253..2ed6cdb80 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy @@ -20,7 +20,9 @@ import io.jsonwebtoken.Jwts import io.jsonwebtoken.MalformedJwtException import io.jsonwebtoken.SignatureAlgorithm import io.jsonwebtoken.impl.lang.Bytes -import io.jsonwebtoken.io.* +import io.jsonwebtoken.io.DeserializationException +import io.jsonwebtoken.io.Deserializer +import io.jsonwebtoken.io.Encoders import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.security.Keys import org.junit.Test @@ -42,31 +44,13 @@ class DefaultJwtParserTest { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - @Test(expected = IllegalArgumentException) - void testBase64UrlDecodeWithNullArgument() { - new DefaultJwtParser().base64UrlDecodeWith(null) - } - - @Test - void testBase64UrlDecodeWithCustomDecoder() { - def decoder = new Decoder() { - @Override - Object decode(Object o) throws DecodingException { - return null - } - } - def b = new DefaultJwtParser().base64UrlDecodeWith(decoder) - assertSame decoder, b.base64UrlDecoder + private DefaultJwtParser newParser() { + return Jwts.parser().build() as DefaultJwtParser } @Test(expected = MalformedJwtException) void testBase64UrlDecodeWithInvalidInput() { - new DefaultJwtParser().base64UrlDecode('20:SLDKJF;3993;----', 'test') - } - - @Test(expected = IllegalArgumentException) - void testDeserializeJsonWithNullArgument() { - new DefaultJwtParser().deserializeJsonWith(null) + newParser().base64UrlDecode('20:SLDKJF;3993;----', 'test') } @Test @@ -77,15 +61,16 @@ class DefaultJwtParserTest { return OBJECT_MAPPER.readValue(bytes, Map.class) } } - def p = new DefaultJwtParser().deserializeJsonWith(deserializer) + def pb = Jwts.parser().deserializeJsonWith(deserializer) + def p = pb.build() as DefaultJwtParser assertTrue("Expected wrapping deserializer to be instance of JwtDeserializer", p.deserializer instanceof JwtDeserializer ) assertSame deserializer, p.deserializer.deserializer - def key = Keys.secretKeyFor(SignatureAlgorithm.HS256) + def key = Jwts.SIG.HS256.keyBuilder().build() - String jws = Jwts.builder().claim('foo', 'bar').signWith(key, SignatureAlgorithm.HS256).compact() + String jws = Jwts.builder().claim('foo', 'bar').signWith(key, Jwts.SIG.HS256).compact() - assertEquals 'bar', p.setSigningKey(key).parseClaimsJws(jws).getPayload().get('foo') + assertEquals 'bar', pb.verifyWith(key).build().parseClaimsJws(jws).getPayload().get('foo') } @Test(expected = MalformedJwtException) @@ -103,7 +88,7 @@ class DefaultJwtParserTest { String invalidJws = compact + encodedSignature - new DefaultJwtParser().setSigningKey(key).parseClaimsJws(invalidJws) + Jwts.parser().verifyWith(key).build().parseClaimsJws(invalidJws) } @Test(expected = MalformedJwtException) @@ -121,7 +106,7 @@ class DefaultJwtParserTest { String invalidJws = compact + encodedSignature - new DefaultJwtParser().setSigningKey(key).parseClaimsJws(invalidJws) + Jwts.parser().verifyWith(key).build().parseClaimsJwe(invalidJws) } @Test(expected = MalformedJwtException) @@ -139,24 +124,7 @@ class DefaultJwtParserTest { String invalidJws = compact + encodedSignature - new DefaultJwtParser().setSigningKey(key).parseClaimsJws(invalidJws) - } - - @Test - void testMaxAllowedClockSkewSeconds() { - long max = Long.MAX_VALUE / 1000 as long - new DefaultJwtParser().setAllowedClockSkewSeconds(max) // no exception should be thrown - } - - @Test - void testExceededAllowedClockSkewSeconds() { - long value = Long.MAX_VALUE / 1000 as long - value = value + 1L - try { - new DefaultJwtParser().setAllowedClockSkewSeconds(value) - } catch (IllegalArgumentException expected) { - assertEquals DefaultJwtParserBuilder.MAX_CLOCK_SKEW_ILLEGAL_MSG, expected.message - } + Jwts.parser().verifyWith(key).build().parseClaimsJws(invalidJws) } @Test diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy index 28c4786df..69c06b638 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy @@ -30,7 +30,7 @@ class DefaultJwtTest { @Test void testToString() { String compact = Jwts.builder().setHeaderParam('foo', 'bar').setAudience('jsmith').compact() - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) assertEquals 'header={foo=bar, alg=none},payload={aud=jsmith}', jwt.toString() } @@ -39,14 +39,14 @@ class DefaultJwtTest { byte[] bytes = 'hello JJWT'.getBytes(StandardCharsets.UTF_8) String encoded = Encoders.BASE64URL.encode(bytes) String compact = Jwts.builder().setHeaderParam('foo', 'bar').setContent(bytes).compact() - Jwt jwt = Jwts.parserBuilder().enableUnsecuredJws().build().parseContentJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals "header={foo=bar, alg=none},payload=$encoded" as String, jwt.toString() } @Test void testEqualsAndHashCode() { String compact = Jwts.builder().claim('foo', 'bar').compact() - def parser = Jwts.parserBuilder().enableUnsecuredJws().build() + def parser = Jwts.parser().enableUnsecuredJws().build() def jwt1 = parser.parseClaimsJwt(compact) def jwt2 = parser.parseClaimsJwt(compact) assertNotEquals jwt1, 'hello' as String @@ -60,7 +60,7 @@ class DefaultJwtTest { @Test void testBodyAndPayloadSame() { String compact = Jwts.builder().claim('foo', 'bar').compact() - def parser = Jwts.parserBuilder().enableUnsecuredJws().build() + def parser = Jwts.parser().enableUnsecuredJws().build() def jwt1 = parser.parseClaimsJwt(compact) def jwt2 = parser.parseClaimsJwt(compact) assertEquals jwt1.getBody(), jwt1.getPayload() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/ImmutableJwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/ImmutableJwtParserTest.groovy deleted file mode 100644 index 0ae6987e8..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/ImmutableJwtParserTest.groovy +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.* -import io.jsonwebtoken.io.Decoder -import io.jsonwebtoken.io.Deserializer -import org.junit.Test - -import java.security.Key - -import static org.easymock.EasyMock.* -import static org.hamcrest.CoreMatchers.is -import static org.hamcrest.MatcherAssert.assertThat - -/** - * 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)) - } -} diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy index 3dd30a9ee..184466ae9 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/compression/DeflateCompressionCodecTest.groovy @@ -33,7 +33,7 @@ class DeflateCompressionCodecTest { @Test void testBackwardsCompatibility_0_10_6() { final String jwtFrom0106 = 'eyJhbGciOiJub25lIiwiemlwIjoiREVGIn0.eNqqVsosLlayUspNVdJRKi5NAjJLi1OLgJzMxBIlK0sTMzMLEwsDAx2l1IoCJSsTQwMjExOQQC0AAAD__w.' - Jwts.parserBuilder().enableUnsecuredJws().enableUnsecuredDecompression().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown + Jwts.parser().enableUnsecuredJws().enableUnsecuredDecompression().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown } /** diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/lang/LegacyServicesTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/lang/LegacyServicesTest.groovy deleted file mode 100644 index 264e43c24..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/lang/LegacyServicesTest.groovy +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2021 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.lang - -import io.jsonwebtoken.lang.UnknownClassException -import org.junit.Test - -class LegacyServicesTest { - - @Test(expected = UnknownClassException) - void serviceNotFoundTest() { - // try to load a class that will NOT have any services, i.e. this test class. - LegacyServices.loadFirst(LegacyServicesTest) - } -} diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy index ff9936c0a..50465bf6c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy @@ -138,7 +138,7 @@ class EdSignatureAlgorithmTest { static void testSig(SignatureAlgorithm alg, PrivateKey signing, PublicKey verification) { String jwt = Jwts.builder().setIssuer('me').setAudience('you').signWith(signing, alg).compact() - def token = Jwts.parserBuilder().verifyWith(verification).build().parseClaimsJws(jwt) + def token = Jwts.parser().verifyWith(verification).build().parseClaimsJws(jwt) assertEquals([alg: alg.getId()], token.header) assertEquals 'me', token.getPayload().getIssuer() assertEquals 'you', token.getPayload().getAudience() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy index 4c2c7b7ce..f38333d31 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy @@ -56,7 +56,7 @@ class Issue542Test { for (alg in algs) { PublicKey key = TestKeys.forAlgorithm(alg).pair.public String jws = JWS_0_10_7_VALUES[alg] - def token = Jwts.parserBuilder().verifyWith(key).build().parseClaimsJws(jws) + def token = Jwts.parser().verifyWith(key).build().parseClaimsJws(jws) assert 'joe' == token.payload.getIssuer() } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy index 4ceee9d40..9f721f9a3 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy @@ -174,7 +174,7 @@ class RFC7516AppendixA1Test { RsaPrivateJwk jwk = Jwks.builder().set(KEK_VALUES).build() as RsaPrivateJwk RSAPrivateKey privKey = jwk.toKey() - Jwe jwe = Jwts.parserBuilder().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) + Jwe jwe = Jwts.parser().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) assertEquals PLAINTEXT, new String(jwe.getPayload(), StandardCharsets.UTF_8) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy index 4880c909b..0734932ac 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy @@ -168,7 +168,7 @@ class RFC7516AppendixA2Test { RsaPrivateJwk jwk = Jwks.builder().set(KEK_VALUES).build() as RsaPrivateJwk RSAPrivateKey privKey = jwk.toKey() - Jwe jwe = Jwts.parserBuilder().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) + Jwe jwe = Jwts.parser().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) assertEquals PLAINTEXT, new String(jwe.getPayload(), StandardCharsets.UTF_8) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy index ff75182b7..7ea4022fe 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy @@ -109,7 +109,7 @@ class RFC7516AppendixA3Test { SecretKey kek = jwk.toKey() // test decryption per the RFC - Jwe jwe = Jwts.parserBuilder().decryptWith(kek).build().parseContentJwe(COMPLETE_JWE) + Jwe jwe = Jwts.parser().decryptWith(kek).build().parseContentJwe(COMPLETE_JWE) assertEquals PLAINTEXT, new String(jwe.getPayload(), StandardCharsets.UTF_8) // now ensure that when JJWT does the encryption (i.e. a compact value is produced from JJWT, not from the RFC text), diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy index e81336843..b5303a34b 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy @@ -331,7 +331,7 @@ class RFC7517AppendixCTest { assertEquals RFC_COMPACT_JWE, compact //ensure we can decrypt now: - Jwe jwe = Jwts.parserBuilder().decryptWith(key).build().parseContentJwe(compact) + Jwe jwe = Jwts.parser().decryptWith(key).build().parseContentJwe(compact) assertEquals RFC_JWK_JSON, new String(jwe.getPayload(), StandardCharsets.UTF_8) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy index bad76beb0..9880e3f7d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy @@ -126,7 +126,7 @@ class RFC7518AppendixCTest { assertArrayEquals RFC_DERIVED_KEY, derivedKey // now reverse the process and ensure it all works: - Jwe claimsJwe = Jwts.parserBuilder() + Jwe claimsJwe = Jwts.parser() .decryptWith(bobJwk.toKey()) .build().parseClaimsJwe(jwe) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy index e3124a8be..aa827f95d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy @@ -227,7 +227,7 @@ class RFC7520Section4Test { assertEquals FIGURE_13, result // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().verifyWith(jwk.toPublicJwk().toKey()).build().parseContentJws(result) + def parsed = Jwts.parser().verifyWith(jwk.toPublicJwk().toKey()).build().parseContentJws(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals jwk.getId(), parsed.header.getKeyId() assertEquals FIGURE_7, utf8(parsed.payload) @@ -271,7 +271,7 @@ class RFC7520Section4Test { // even though we can't know what the signature output is ahead of time due to random data, we can assert // the signature to guarantee a round trip works as expected: - def parsed = Jwts.parserBuilder() + def parsed = Jwts.parser() .verifyWith(jwk.toPublicJwk().toKey()) .build().parseContentJws(result) @@ -316,7 +316,7 @@ class RFC7520Section4Test { // even though we can't know what the signature output is ahead of time due to random data, we can assert // the signature to guarantee a round trip works as expected: - def parsed = Jwts.parserBuilder() + def parsed = Jwts.parser() .verifyWith(jwk.toPublicJwk().toKey()) .build().parseContentJws(result) @@ -357,7 +357,7 @@ class RFC7520Section4Test { assertEquals FIGURE_34, result // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().verifyWith(key).build().parseContentJws(result) + def parsed = Jwts.parser().verifyWith(key).build().parseContentJws(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals jwk.getId(), parsed.header.getKeyId() assertEquals FIGURE_7, utf8(parsed.payload) @@ -398,7 +398,7 @@ class RFC7520Section4Test { assertEquals FIGURE_41, detached // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().verifyWith(key).build().parseContentJws(result) + def parsed = Jwts.parser().verifyWith(key).build().parseContentJws(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals jwk.getId(), parsed.header.getKeyId() assertEquals FIGURE_7, utf8(parsed.payload) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy index 1fbe2abbd..89d2d2a11 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy @@ -481,7 +481,7 @@ class RFC7520Section5Test { assertEquals FIGURE_81, result // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().decryptWith(jwk.toKey()).build().parseContentJwe(result) + def parsed = Jwts.parser().decryptWith(jwk.toKey()).build().parseContentJwe(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals jwk.getId(), parsed.header.getKeyId() assertEquals enc.getId(), parsed.header.getEncryptionAlgorithm() @@ -545,7 +545,7 @@ class RFC7520Section5Test { assertEquals FIGURE_92, result // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().decryptWith(jwk.toKey()).build().parseContentJwe(result) + def parsed = Jwts.parser().decryptWith(jwk.toKey()).build().parseContentJwe(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals jwk.getId(), parsed.header.getKeyId() assertEquals enc.getId(), parsed.header.getEncryptionAlgorithm() @@ -606,7 +606,7 @@ class RFC7520Section5Test { assertEquals FIGURE_105, result // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().decryptWith(key).build().parseContentJwe(result) + def parsed = Jwts.parser().decryptWith(key).build().parseContentJwe(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals FIGURE_99, b64Url(parsed.header.getPbes2Salt()) assertEquals p2c, parsed.header.getPbes2Count() @@ -668,7 +668,7 @@ class RFC7520Section5Test { assertEquals FIGURE_117, result // Assert round trip works as expected: - def parsed = Jwts.parserBuilder().decryptWith(jwk.toKey()).build().parseContentJwe(result) + def parsed = Jwts.parser().decryptWith(jwk.toKey()).build().parseContentJwe(result) assertEquals alg.getId(), parsed.header.getAlgorithm() assertEquals enc.getId(), parsed.header.getEncryptionAlgorithm() assertEquals jwk.getId(), parsed.header.getKeyId() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy index e86dabdd7..7e6f99da1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy @@ -108,7 +108,7 @@ class RFC8037AppendixATest { assertEquals A4_JWS_COMPACT, compact def pubJwk = a2Jwk() - def payloadBytes = Jwts.parserBuilder().verifyWith(pubJwk.toKey()).build().parse(compact).getPayload() as byte[] + def payloadBytes = Jwts.parser().verifyWith(pubJwk.toKey()).build().parse(compact).getPayload() as byte[] def payload = new String(payloadBytes, StandardCharsets.UTF_8) assertEquals A4_JWS_PAYLOAD, payload } @@ -193,7 +193,7 @@ class RFC8037AppendixATest { assertEquals(rfcExpectedHeaderMap.get('epk'), jweHeaderMap.get('epk')) //ensure that bob can decrypt: - def jwt = Jwts.parserBuilder().decryptWith(bobPrivJwk.toKey() as PrivateKey).build().parseClaimsJwe(jwe) + def jwt = Jwts.parser().decryptWith(bobPrivJwk.toKey() as PrivateKey).build().parseClaimsJwe(jwe) assertEquals(issuer, jwt.getPayload().getIssuer()) } @@ -284,7 +284,7 @@ class RFC8037AppendixATest { assertEquals(rfcExpectedHeaderMap.get('epk'), jweHeaderMap.get('epk')) //ensure that Bob ("Dave") can decrypt: - def jwt = Jwts.parserBuilder().decryptWith(bobPrivJwk.toKey() as PrivateKey).build().parseClaimsJwe(jwe) + def jwt = Jwts.parser().decryptWith(bobPrivJwk.toKey() as PrivateKey).build().parseClaimsJwe(jwe) //assert that we've decrypted and the value in the body/content is as expected: assertEquals(issuer, jwt.getPayload().getIssuer()) diff --git a/tdjar/src/test/groovy/io/jsonwebtoken/all/BasicTest.groovy b/tdjar/src/test/groovy/io/jsonwebtoken/all/BasicTest.groovy index bf1ffaa39..258abeae3 100644 --- a/tdjar/src/test/groovy/io/jsonwebtoken/all/BasicTest.groovy +++ b/tdjar/src/test/groovy/io/jsonwebtoken/all/BasicTest.groovy @@ -38,7 +38,7 @@ class BasicTest { .signWith(key, SignatureAlgorithm.HS256) .compact() - JwtParser parser = Jwts.parserBuilder() + JwtParser parser = Jwts.parser() .setSigningKey(key) .build() diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index 542810ac4..d1850ea49 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -70,7 +70,7 @@ public void testExampleJwsHS() { String jws = Jwts.builder().setContent(content, "text/plain").signWith(key, alg).compact(); // Parse the compact JWS: - content = Jwts.parserBuilder().verifyWith(key).build().parseContentJws(jws).getPayload(); + content = Jwts.parser().verifyWith(key).build().parseContentJws(jws).getPayload(); assert message.equals(new String(content, StandardCharsets.UTF_8)); } @@ -90,7 +90,7 @@ public void testExampleJwsRSA() { .compact(); // Alice receives and verifies the compact JWS came from Bob: - String subject = Jwts.parserBuilder() + String subject = Jwts.parser() .verifyWith(pair.getPublic()) // <-- Bob's RSA public key .build().parseClaimsJws(jws).getPayload().getSubject(); @@ -112,7 +112,7 @@ public void testExampleJwsECDSA() { .compact(); // Alice receives and verifies the compact JWS came from Bob: - String subject = Jwts.parserBuilder() + String subject = Jwts.parser() .verifyWith(pair.getPublic()) // <-- Bob's EC public key .build().parseClaimsJws(jws).getPayload().getSubject(); @@ -136,7 +136,7 @@ public void testExampleJweDir() { String jwe = Jwts.builder().setContent(content, "text/plain").encryptWith(key, enc).compact(); // Parse the compact JWE: - content = Jwts.parserBuilder().decryptWith(key).build().parseContentJwe(jwe).getPayload(); + content = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe).getPayload(); assert message.equals(new String(content, StandardCharsets.UTF_8)); } @@ -160,7 +160,7 @@ public void testExampleJweRSA() { .compact(); // Alice receives and decrypts the compact JWE: - String audience = Jwts.parserBuilder() + String audience = Jwts.parser() .decryptWith(pair.getPrivate()) // <-- Alice's RSA private key .build().parseClaimsJwe(jwe).getPayload().getAudience(); @@ -183,7 +183,7 @@ public void testExampleJweAESKW() { String jwe = Jwts.builder().setIssuer("me").encryptWith(key, alg, enc).compact(); // Parse the compact JWE: - String issuer = Jwts.parserBuilder().decryptWith(key).build() + String issuer = Jwts.parser().decryptWith(key).build() .parseClaimsJwe(jwe).getPayload().getIssuer(); assert "me".equals(issuer); @@ -208,7 +208,7 @@ public void testExampleJweECDHES() { .compact(); // Alice receives and decrypts the compact JWE: - String audience = Jwts.parserBuilder() + String audience = Jwts.parser() .decryptWith(pair.getPrivate()) // <-- Alice's EC private key .build().parseClaimsJwe(jwe).getPayload().getAudience(); @@ -246,7 +246,7 @@ public void testExampleJwePassword() { .compact(); // Parse the compact JWE: - String issuer = Jwts.parserBuilder().decryptWith(password) + String issuer = Jwts.parser().decryptWith(password) .build().parseClaimsJwe(jwe).getPayload().getIssuer(); assert "me".equals(issuer); From c0d16a838151a6dac6cb6233a4bfe8733591d78a Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Fri, 4 Aug 2023 16:30:10 -0700 Subject: [PATCH 2/2] Minor JavaDoc fix --- api/src/main/java/io/jsonwebtoken/Identifiable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/io/jsonwebtoken/Identifiable.java b/api/src/main/java/io/jsonwebtoken/Identifiable.java index e02b9a1f3..9d2cc8d92 100644 --- a/api/src/main/java/io/jsonwebtoken/Identifiable.java +++ b/api/src/main/java/io/jsonwebtoken/Identifiable.java @@ -40,7 +40,7 @@ * parameter value. * * - * {@link io.jsonwebtoken.CompressionCodec CompressionCodec} + * {@link io.jsonwebtoken.io.CompressionAlgorithm CompressionAlgorithm} * JWE protected header's * {@code zip} (Compression Algorithm) * parameter value.