From 84defef39a1bd22b147d337a0b2207f10dc1c455 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:33:34 -0700 Subject: [PATCH 01/24] impl checkpoint of modern builder-style setters (without the 'set' prefix) --- README.md | 6 +- .../java/io/jsonwebtoken/ClaimsMutator.java | 101 ++++++++++++++++++ .../java/io/jsonwebtoken/HeaderMutator.java | 26 +---- .../io/jsonwebtoken/JweHeaderMutator.java | 14 +-- .../main/java/io/jsonwebtoken/JwtBuilder.java | 39 +++---- .../io/jsonwebtoken/JwtParserBuilder.java | 76 +++++++++++-- .../jsonwebtoken/ProtectedHeaderMutator.java | 8 +- .../io/jsonwebtoken/SigningKeyResolver.java | 2 +- .../SigningKeyResolverAdapter.java | 6 +- .../security/AsymmetricJwkBuilder.java | 4 +- .../io/jsonwebtoken/security/JwkBuilder.java | 16 +-- .../security/JwkParserBuilder.java | 4 +- .../java/io/jsonwebtoken/security/Jwks.java | 2 +- .../security/PrivateJwkBuilder.java | 6 +- .../security/ProtoJwkBuilder.java | 96 ++++++++--------- .../security/PublicJwkBuilder.java | 4 +- .../security/SecurityBuilder.java | 8 +- .../io/jsonwebtoken/security/X509Builder.java | 8 +- .../io/jsonwebtoken/security/X509Mutator.java | 8 +- .../impl/AbstractX509Context.java | 8 +- .../impl/DefaultClaimsBuilder.java | 35 ++++++ .../impl/DefaultJweHeaderMutator.java | 55 +++++----- .../jsonwebtoken/impl/DefaultJwtBuilder.java | 69 +++++++++--- .../impl/DefaultJwtParserBuilder.java | 30 +++++- .../AbstractAsymmetricJwkBuilder.java | 24 ++--- .../impl/security/AbstractJwkBuilder.java | 16 +-- .../impl/security/CryptoAlgorithm.java | 2 +- .../impl/security/DefaultCurve.java | 2 +- .../impl/security/DefaultJwkParser.java | 2 +- .../security/DefaultJwkParserBuilder.java | 2 +- .../impl/security/DefaultKeyPairBuilder.java | 4 +- .../impl/security/DefaultProtoJwkBuilder.java | 66 ++++++------ .../security/DefaultSecretKeyBuilder.java | 6 +- .../impl/security/EcSignatureAlgorithm.java | 4 +- .../impl/security/EcdhKeyAlgorithm.java | 8 +- .../impl/security/EdwardsCurve.java | 2 +- .../security/EdwardsPublicKeyDeriver.java | 2 +- .../impl/security/RsaSignatureAlgorithm.java | 4 +- .../impl/security/StandardKeyAlgorithms.java | 2 +- .../impl/security/X509BuilderSupport.java | 12 +-- .../groovy/io/jsonwebtoken/JwtsTest.groovy | 8 +- .../impl/AbstractProtectedHeaderTest.groovy | 8 +- .../impl/DefaultJweHeaderTest.groovy | 14 +-- .../impl/DefaultJwtBuilderTest.groovy | 8 +- .../impl/DefaultJwtHeaderBuilderTest.groovy | 24 +++-- .../impl/DefaultJwtParserBuilderTest.groovy | 8 +- .../jsonwebtoken/impl/DefaultJwtTest.groovy | 2 +- .../impl/DefaultMutableJweHeaderTest.groovy | 18 ++-- .../io/jsonwebtoken/impl/IdLocatorTest.groovy | 4 +- .../AbstractAsymmetricJwkBuilderTest.groovy | 22 ++-- .../security/AbstractJwkBuilderTest.groovy | 10 +- .../impl/security/AbstractJwkTest.groovy | 18 ++-- .../security/DefaultJwkContextTest.groovy | 8 +- .../DefaultJwkParserBuilderTest.groovy | 2 +- .../impl/security/DefaultJwkParserTest.groovy | 6 +- .../impl/security/EcdhKeyAlgorithmTest.groovy | 10 +- .../security/FixedSecretKeyBuilder.groovy | 4 +- .../impl/security/HashAlgorithmsTest.groovy | 2 +- .../impl/security/JwkConverterTest.groovy | 6 +- .../impl/security/JwkSerializationTest.groovy | 6 +- .../impl/security/JwkThumbprintsTest.groovy | 8 +- .../impl/security/JwksTest.groovy | 72 ++++++------- .../impl/security/OctetJwksTest.groovy | 10 +- .../security/Pbes2HsAkwAlgorithmTest.groovy | 4 +- .../impl/security/RFC7517AppendixCTest.groovy | 2 +- .../impl/security/RFC7518AppendixCTest.groovy | 2 +- .../impl/security/RFC7520Section4Test.groovy | 2 +- .../impl/security/RFC7520Section5Test.groovy | 2 +- .../impl/security/RFC8037AppendixATest.groovy | 4 +- .../security/RsaPrivateJwkFactoryTest.groovy | 16 +-- .../impl/security/SecretJwkFactoryTest.groovy | 30 +++--- .../security/EncryptionAlgorithmsTest.groovy | 2 +- .../security/KeyAlgorithmsTest.groovy | 2 +- .../io/jsonwebtoken/all/JavaReadmeTest.java | 20 ++-- 74 files changed, 695 insertions(+), 458 deletions(-) diff --git a/README.md b/README.md index 1a08a672b..4ff87d64a 100644 --- a/README.md +++ b/README.md @@ -840,7 +840,7 @@ Each time `setHeaderParam` is called, it simply appends the key-value pair to an potentially overwriting any existing identically-named key/value pair. The downside with this approach is that you lose any type-safe setter methods or additional builder utility methods -available on the `Jwts.headerBuilder()` such as `setContentType`,`setKeyId`, `withX509Sha256Thumbprint`, etc. +available on the `Jwts.header()` builder such as `contentType`,`keyId`, `withX509Sha256Thumbprint`, etc. > **Note** > @@ -1527,7 +1527,7 @@ If you want to specify a specific JCA `Provider` or `SecureRandom` to use during as builder arguments. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().setProvider(aProvider).setRandom(aSecureRandom).build(); +SecretKey key = Jwts.SIG.HS256.keyBuilder().provider(aProvider).random(aSecureRandom).build(); ``` If you need to save this new `SecretKey`, you can Base64 (or Base64URL) encode it: @@ -2312,7 +2312,7 @@ You can read/parse a JWK by building a `JwkParser` and parsing the JWK JSON stri ```java String json = getJwkJsonString(); Jwk jwk = Jwks.parser() - //.setProvider(aJcaProvider) // optional + //.provider(aJcaProvider) // optional //.deserializeJsonWith(deserializer) // optional .build() // create the parser .parse(json); // actually parse the JSON diff --git a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java index 70a4718e8..0c5829ee1 100644 --- a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java @@ -33,27 +33,66 @@ public interface ClaimsMutator> { * * @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #issuer(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setIssuer(String iss); + /** + * Sets the JWT + * iss (issuer) value. A {@code null} value will remove the property from the JSON map. + * + * @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T issuer(String iss); + /** * Sets the JWT * sub (subject) value. A {@code null} value will remove the property from the JSON map. * * @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #subject(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setSubject(String sub); + /** + * Sets the JWT + * sub (subject) value. A {@code null} value will remove the property from the JSON map. + * + * @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T subject(String sub); + /** * Sets the JWT * aud (audience) value. A {@code null} value will remove the property from the JSON map. * * @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #audience(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setAudience(String aud); + /** + * Sets the JWT + * aud (audience) value. A {@code null} value will remove the property from the JSON map. + * + * @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T audience(String aud); + /** * Sets the JWT * exp (expiration) timestamp. A {@code null} value will remove the property from the JSON map. @@ -62,9 +101,24 @@ public interface ClaimsMutator> { * * @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #expiration(Date)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setExpiration(Date exp); + /** + * Sets the JWT + * exp (expiration) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

A JWT obtained after this timestamp should not be used.

+ * + * @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T expiration(Date exp); + /** * Sets the JWT * nbf (not before) timestamp. A {@code null} value will remove the property from the JSON map. @@ -73,9 +127,24 @@ public interface ClaimsMutator> { * * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #notBefore(Date)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setNotBefore(Date nbf); + /** + * Sets the JWT + * nbf (not before) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

A JWT obtained before this timestamp should not be used.

+ * + * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T notBefore(Date nbf); + /** * Sets the JWT * iat (issued at) timestamp. A {@code null} value will remove the property from the JSON map. @@ -84,9 +153,24 @@ public interface ClaimsMutator> { * * @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #issuedAt(Date)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setIssuedAt(Date iat); + /** + * Sets the JWT + * iat (issued at) timestamp. A {@code null} value will remove the property from the JSON map. + * + *

The value is the timestamp when the JWT was created.

+ * + * @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T issuedAt(Date iat); + /** * Sets the JWT * jti (JWT ID) value. A {@code null} value will remove the property from the JSON map. @@ -97,6 +181,23 @@ public interface ClaimsMutator> { * * @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map. * @return the {@code Claims} instance for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #id(String)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated T setId(String jti); + + /** + * Sets the JWT + * jti (JWT ID) value. A {@code null} value will remove the property from the JSON map. + * + *

This value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a + * manner that ensures that there is a negligible probability that the same value will be accidentally + * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

+ * + * @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map. + * @return the {@code Claims} instance for method chaining. + * @since JJWT_RELEASE_VERSION + */ + T id(String jti); } diff --git a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java index 180b2e70c..454270599 100644 --- a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java @@ -32,7 +32,7 @@ public interface HeaderMutator> extends MapMutator @@ -59,9 +59,9 @@ public interface HeaderMutator> extends MapMutator @@ -78,25 +78,7 @@ public interface HeaderMutator> extends MapMutatorzip - * (Compression Algorithm) header parameter value. A {@code null} value will remove - * the property from the JSON map. * - *

Compatibility Note

- * - *

While the JWT family of specifications only defines the zip header in the JWE - * (JSON Web Encryption) specification, JJWT will also support compression for JWS as well if you choose to use it. - * However, be aware that if you use compression when creating a JWS token, other libraries may not be able to - * parse the JWS. However, Compression when creating JWE tokens should be universally accepted for any library - * that supports JWE.

- * - * @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the JSON map. - * @return the {@code Header} instance for method chaining. - * @since 0.6.0 + T algorithm(String alg); */ - T setCompressionAlgorithm(String zip); } diff --git a/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java b/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java index 7382faa3d..d118c7374 100644 --- a/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/JweHeaderMutator.java @@ -37,7 +37,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyUInfo(byte[] info); + T agreementPartyUInfo(byte[] info); /** * Sets any information about the JWE producer for use with key agreement algorithms. A {@code null} value removes @@ -45,7 +45,7 @@ public interface JweHeaderMutator> extends Protect * *

If not {@code null}, this is a convenience method that calls the equivalent of the following:

*
-     * {@link #setAgreementPartyUInfo(byte[]) setAgreementPartyUInfo}(info.getBytes(StandardCharsets.UTF_8))
+ * {@link #agreementPartyUInfo(byte[]) agreementPartyUInfo}(info.getBytes(StandardCharsets.UTF_8)) * * @param info information about the JWE producer to use with key agreement algorithms. * @return the header for method chaining. @@ -55,7 +55,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyUInfo(String info); + T agreementPartyUInfo(String info); /** * Sets any information about the JWE recipient for use with key agreement algorithms. A {@code null} value removes @@ -69,7 +69,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyVInfo(byte[] info); + T agreementPartyVInfo(byte[] info); /** * Sets any information about the JWE recipient for use with key agreement algorithms. A {@code null} value removes @@ -77,7 +77,7 @@ public interface JweHeaderMutator> extends Protect * *

If not {@code null}, this is a convenience method that calls the equivalent of the following:

*
-     * {@link #setAgreementPartyVInfo(byte[]) setAgreementPartVUInfo}(info.getBytes(StandardCharsets.UTF_8))
+ * {@link #agreementPartyVInfo(byte[]) setAgreementPartVUInfo}(info.getBytes(StandardCharsets.UTF_8)) * * @param info information about the JWE recipient to use with key agreement algorithms. * @return the header for method chaining. @@ -87,7 +87,7 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#ECDH_ES_A192KW * @see Jwts.KEY#ECDH_ES_A256KW */ - T setAgreementPartyVInfo(String info); + T agreementPartyVInfo(String info); /** * Sets the number of PBKDF2 iterations necessary to derive the key used during JWE encryption. If this value @@ -112,5 +112,5 @@ public interface JweHeaderMutator> extends Protect * @see Jwts.KEY#PBES2_HS512_A256KW * @see OWASP PBKDF2 Iteration Recommendations */ - T setPbes2Count(int count); + T pbes2Count(int count); } diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 8501e3efe..7ef279871 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -55,7 +55,7 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setProvider(Provider provider); + JwtBuilder provider(Provider provider); /** * Sets the {@link SecureRandom} to use during cryptographic signing or encryption operations, or {@code null} if @@ -66,7 +66,7 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setSecureRandom(SecureRandom secureRandom); + JwtBuilder random(SecureRandom secureRandom); /** * Returns the {@link JwtBuilder.Header} to use to modify the constructed JWT's header name/value pairs as desired. @@ -77,7 +77,7 @@ public interface JwtBuilder extends ClaimsMutator { * String jwt = Jwts.builder() * * .header() - * .setKeyId("keyId") + * .keyId("keyId") * .set(myHeaderMap) * // ... other header params ... * .{@link JwtBuilder.Header#and() and()} //return back to the JwtBuilder @@ -123,13 +123,13 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the - * {@link Header#setContentType(String) contentType} header value so the JWT recipient may inspect that value to + * {@link Header#contentType(String) contentType} header value so the JWT recipient may inspect that value to * determine how to convert the byte array to the final data type as desired. In this case, consider using - * {@link #setContent(byte[], String)} instead. + * {@link #content(byte[], String)} instead. * *

This is a convenience method that is effectively the same as:

*
-     * {@link #setContent(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));
+ * {@link #content(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8)); * *

If you want the JWT payload to be JSON, use the * {@link #setClaims(Claims)} or {@link #setClaims(java.util.Map)} methods instead.

@@ -138,12 +138,13 @@ public interface JwtBuilder extends ClaimsMutator { * * @param payload the string used to set UTF-8-encoded bytes as the JWT payload. * @return the builder for method chaining. - * @see #setContent(byte[]) - * @see #setContent(byte[], String) - * @deprecated since JJWT_RELEASE VERSION in favor of {@link #setContent(byte[])} or {@link #setContent(byte[], String)} + * @see #content(byte[]) + * @see #content(byte[], String) + * @deprecated since JJWT_RELEASE VERSION in favor of {@link #content(byte[])} or {@link #content(byte[], String)} * because both Claims and Content are technically 'payloads', so this method name is misleading. This method will * be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder setPayload(String payload); @@ -154,7 +155,7 @@ public interface JwtBuilder extends ClaimsMutator { * *

Unless you are confident that the JWT recipient will always know how to use * the given byte array without additional metadata, it is strongly recommended to use the - * {@link #setContent(byte[], String)} method instead of this one. That method ensures that a JWT recipient + * {@link #content(byte[], String)} method instead of this one. That method ensures that a JWT recipient * can inspect the {@code cty} header to know how to handle the byte array without ambiguity.

* *

Note that the content and claims properties are mutually exclusive - only one of the two may be used.

@@ -163,11 +164,11 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setContent(byte[] content); + JwtBuilder content(byte[] content); /** * Convenience method that sets the JWT payload to be the specified content byte array and also sets the - * {@link Header#setContentType(String) contentType} header value to a compact {@code cty} media type + * {@link Header#contentType(String) contentType} header value to a compact {@code cty} media type * identifier to indicate the data format of the byte array. The JWT recipient can inspect the * {@code cty} value to determine how to convert the byte array to the final content type as desired. * @@ -178,13 +179,13 @@ public interface JwtBuilder extends ClaimsMutator { * JWT specification recommendations.

* *

If for some reason you do not wish to adhere to the JWT specification recommendation, do not call this - * method - instead call {@link #setContent(byte[])} and set the header's - * {@link Header#setContentType(String) contentType} independently. For example:

+ * method - instead call {@link #content(byte[])} and set the header's + * {@link Header#contentType(String) contentType} independently. For example:

* *
      * Jwts.builder()
-     *     .header().setContentType("application/whatever").and()
-     *     .setContent(byteArray)
+     *     .header().contentType("application/whatever").and()
+     *     .content(byteArray)
      *     ...
      *     .build();
* @@ -199,11 +200,11 @@ public interface JwtBuilder extends ClaimsMutator { * @throws IllegalArgumentException if either {@code payload} or {@code cty} are null or empty. * @since JJWT_RELEASE_VERSION */ - JwtBuilder setContent(byte[] content, String cty) throws IllegalArgumentException; + JwtBuilder content(byte[] content, String cty) throws IllegalArgumentException; /** * Sets the JWT payload to be a JSON Claims instance. If you do not want the JWT payload to be JSON claims and - * instead want it to be a byte array representing any type of content, use the {@link #setContent(byte[])} + * instead want it to be a byte array representing any type of content, use the {@link #content(byte[])} * method instead. * *

The payload and claims properties are mutually exclusive - only one of the two may be used.

@@ -216,7 +217,7 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. If you do not * want the JWT payload to be JSON claims and instead want it to be a byte array for any content, use the - * {@link #setContent(byte[])} or {@link #setContent(byte[], String)} methods instead. + * {@link #content(byte[])} or {@link #content(byte[], String)} methods instead. * *

The payload and claims properties are mutually exclusive - only one of the two may be used.

* diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index eadf800ea..d6e226c50 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -100,7 +100,7 @@ public interface JwtParserBuilder extends Builder { * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder setProvider(Provider provider); + JwtParserBuilder provider(Provider provider); /** * Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed @@ -205,9 +205,21 @@ public interface JwtParserBuilder extends Builder { * * @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT. * @return the parser builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION for the more modern builder-style named {@link #clock(Clock)} method. + * This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder setClock(Clock clock); + /** + * Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT. + * The parser uses a default Clock implementation that simply returns {@code new Date()} when called. + * + * @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT. + * @return the parser builder for method chaining. + */ + JwtParserBuilder clock(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. @@ -217,9 +229,24 @@ public interface JwtParserBuilder extends Builder { * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as * any such value would cause numeric overflow when multiplying by 1000 to obtain * a millisecond value. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #clockSkewSeconds(long)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException; + /** + * Sets the amount of clock skew in seconds to tolerate when verifying the local time against the {@code exp} + * and {@code nbf} claims. + * + * @param seconds the number of seconds to tolerate for clock skew when verifying {@code exp} or {@code nbf} claims. + * @return the parser builder for method chaining. + * @throws IllegalArgumentException if {@code seconds} is a value greater than {@code Long.MAX_VALUE / 1000} as + * any such value would cause numeric overflow when multiplying by 1000 to obtain + * a millisecond value. + */ + JwtParserBuilder clockSkewSeconds(long seconds) throws IllegalArgumentException; + /** *

Deprecation Notice

* @@ -320,7 +347,7 @@ public interface JwtParserBuilder extends Builder { *

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

+ * {@link #keyLocator(Locator) keyLocator} method instead of using this one.

* *

Calling this method overrides any previously set signature verification key.

* @@ -332,7 +359,7 @@ public interface JwtParserBuilder extends Builder { /** * 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), + * {@link #keyLocator(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 @@ -342,7 +369,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 + * your own {@link Locator Locator} via the {@link #keyLocator(Locator) keyLocator} method instead of * using {@code decryptWith}.

* *

Calling this method overrides any previously set decryption key.

@@ -367,7 +394,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.parser().setKeyLocator(new Locator<Key>() {
+     * Jws<Claims> jws = Jwts.parser().keyLocator(new Locator<Key>() {
      *         @Override
      *         public Key locate(Header<?> header) {
      *             if (header instanceof JwsHeader) {
@@ -386,14 +413,14 @@ public interface JwtParserBuilder extends Builder {
      * @return the parser builder for method chaining.
      * @since JJWT_RELEASE_VERSION
      */
-    JwtParserBuilder setKeyLocator(Locator keyLocator);
+    JwtParserBuilder keyLocator(Locator keyLocator);
 
     /**
      * 

Deprecation Notice

* *

This method has been deprecated as of JJWT version JJWT_RELEASE_VERSION because it only supports key location * for JWSs (signed JWTs) instead of both signed (JWS) and encrypted (JWE) scenarios. Use the - * {@link #setKeyLocator(Locator) setKeyLocator} method instead to ensure a locator that can work for both JWS and + * {@link #keyLocator(Locator) keyLocator} method instead to ensure a locator that can work for both JWS and * JWE inputs. This method will be removed for the 1.0 release.

* *

Previous Documentation

@@ -420,7 +447,7 @@ public interface JwtParserBuilder extends Builder { * * @param signingKeyResolver the signing key resolver used to retrieve the signing key. * @return the parser builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #setKeyLocator(Locator)} + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #keyLocator(Locator)} */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -531,6 +558,7 @@ public interface JwtParserBuilder extends Builder { * @param compressionCodecResolver the compression codec resolver used to decompress the JWT body. * @return the parser builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #addCompressionAlgorithms(Collection)}. + * This method will be removed before the 1.0 release. */ @Deprecated JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver); @@ -543,9 +571,23 @@ public interface JwtParserBuilder extends Builder { * * @param base64UrlDecoder the decoder to use when Base64Url-decoding * @return the parser builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #base64UrlDecoder(Decoder)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder); + /** + * 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 builder for method chaining. + */ + JwtParserBuilder base64UrlDecoder(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 @@ -558,9 +600,27 @@ public interface JwtParserBuilder extends Builder { * * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named + * {@link #jsonDeserializer(Deserializer)}. This method will be removed before the JJWT 1.0 release. */ + @Deprecated JwtParserBuilder deserializeJsonWith(Deserializer> deserializer); + /** + * 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 builder for method chaining. + */ + JwtParserBuilder jsonDeserializer(Deserializer> deserializer); + /** * Returns an immutable/thread-safe {@link JwtParser} created from the configuration from this JwtParserBuilder. * diff --git a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java index 3c4a8ef9b..ebad27730 100644 --- a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java @@ -43,7 +43,7 @@ public interface ProtectedHeaderMutator> ext * @see JWS JWK Set URL * @see JWE JWK Set URL */ - T setJwkSetUrl(URI uri); + T jwkSetUrl(URI uri); /** * Sets the {@code jwk} (JSON Web Key) associated with the JWT. When set for a {@link JwsHeader}, the @@ -56,7 +56,7 @@ public interface ProtectedHeaderMutator> ext * @see JWS jwk (JSON Web Key) Header Parameter * @see JWE jwk (JSON Web Key) Header Parameter */ - T setJwk(PublicJwk jwk); + T jwk(PublicJwk jwk); /** * Sets the JWT case-sensitive {@code kid} (Key ID) header value. A {@code null} value will remove the property @@ -73,7 +73,7 @@ public interface ProtectedHeaderMutator> ext * @see JWS Key ID * @see JWE Key ID */ - T setKeyId(String kid); + T keyId(String kid); /** * Sets the header parameter names that use extensions to the JWT or JWA specification that MUST @@ -86,5 +86,5 @@ public interface ProtectedHeaderMutator> ext * @see JWS crit (Critical) Header Parameter * @see JWS crit (Critical) Header Parameter */ - T setCritical(Set crit); + T critical(Set crit); } diff --git a/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java b/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java index eb78e008d..bbbd17a7a 100644 --- a/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java +++ b/api/src/main/java/io/jsonwebtoken/SigningKeyResolver.java @@ -44,7 +44,7 @@ * the {@link io.jsonwebtoken.SigningKeyResolverAdapter} and overriding only the method you need to support instead of * implementing this interface directly.

* - * @see io.jsonwebtoken.JwtParserBuilder#setKeyLocator(Locator) + * @see io.jsonwebtoken.JwtParserBuilder#keyLocator(Locator) * @since 0.4 * @deprecated since JJWT_RELEASE_VERSION. Implement {@link Locator} instead. */ diff --git a/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java b/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java index c3af881fe..6695f5acd 100644 --- a/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java +++ b/api/src/main/java/io/jsonwebtoken/SigningKeyResolverAdapter.java @@ -25,7 +25,7 @@ * *

As of JJWT JJWT_RELEASE_VERSION, various Resolver concepts (including the {@code SigningKeyResolver}) have been * unified into a single {@link Locator} interface. For key location, (for both signing and encryption keys), - * use the {@link JwtParserBuilder#setKeyLocator(Locator)} to configure a parser with your desired Key locator instead + * use the {@link JwtParserBuilder#keyLocator(Locator)} to configure a parser with your desired Key locator instead * of using a {@code SigningKeyResolver}. Also see {@link LocatorAdapter} for the Adapter pattern parallel of this * class. This {@code SigningKeyResolverAdapter} class will be removed before the 1.0 release.

* @@ -46,11 +46,11 @@ * are not overridden, one (or both) of the *KeyBytes variants must be overridden depending on your expected * use case. You do not have to override any method that does not represent an expected condition.

* - * @see io.jsonwebtoken.JwtParserBuilder#setKeyLocator(Locator) + * @see io.jsonwebtoken.JwtParserBuilder#keyLocator(Locator) * @see LocatorAdapter * @since 0.4 * @deprecated since JJWT_RELEASE_VERSION. Use {@link LocatorAdapter LocatorAdapter} with - * {@link JwtParserBuilder#setKeyLocator(Locator)} + * {@link JwtParserBuilder#keyLocator(Locator)} */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated diff --git a/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java index cf106351c..cf0e29b15 100644 --- a/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java @@ -69,7 +69,7 @@ public interface AsymmetricJwkBuilder, * *

Per * JWK RFC 7517, Section 4.3, last paragraph, - * the {@code use} (Public Key Use) and {@link #setOperations(Set) key_ops (Key Operations)} members + * the {@code use} (Public Key Use) and {@link #operations(Set) key_ops (Key Operations)} members * SHOULD NOT be used together; however, if both are used, the information they convey MUST be * consistent. Applications should specify which of these members they use, if either is to be used by the * application.

@@ -78,5 +78,5 @@ public interface AsymmetricJwkBuilder, * @return the builder for method chaining. * @throws IllegalArgumentException if the {@code use} value is {@code null} or empty. */ - T setPublicKeyUse(String use) throws IllegalArgumentException; + T publicKeyUse(String use) throws IllegalArgumentException; } diff --git a/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java index bb7227a5d..25aa92665 100644 --- a/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java @@ -57,7 +57,7 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @throws IllegalArgumentException if {@code alg} is {@code null} or empty. */ - T setAlgorithm(String alg) throws IllegalArgumentException; + T algorithm(String alg) throws IllegalArgumentException; /** * Sets the JWK {@code kid} (Key ID) @@ -77,22 +77,22 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @throws IllegalArgumentException if the argument is {@code null} or empty. */ - T setId(String kid) throws IllegalArgumentException; + T id(String kid) throws IllegalArgumentException; /** - * Sets the JWK's {@link #setId(String) kid} value to be the Base64URL-encoding of its {@code SHA-256} + * Sets the JWK's {@link #id(String) kid} value to be the Base64URL-encoding of its {@code SHA-256} * {@link Jwk#thumbprint(HashAlgorithm) thumbprint}. That is, the constructed JWK's {@code kid} value will equal * jwk.{@link Jwk#thumbprint(HashAlgorithm) thumbprint}({@link Jwks.HASH}.{@link Jwks.HASH#SHA256 SHA256}).{@link JwkThumbprint#toString() toString()}. * - *

This is a convenience method that delegates to {@link #setIdFromThumbprint(HashAlgorithm)} using + *

This is a convenience method that delegates to {@link #idFromThumbprint(HashAlgorithm)} using * {@link Jwks.HASH}{@code .}{@link Jwks.HASH#SHA256 SHA256}.

* * @return the builder for method chaining. */ - T setIdFromThumbprint(); + T idFromThumbprint(); /** - * Sets the JWK's {@link #setId(String) kid} value to be the Base64URL-encoding of its + * Sets the JWK's {@link #id(String) kid} value to be the Base64URL-encoding of its * {@link Jwk#thumbprint(HashAlgorithm) thumbprint} using the specified {@link HashAlgorithm}. That is, the * constructed JWK's {@code kid} value will equal * {@link Jwk#thumbprint(HashAlgorithm) thumbprint}(alg).{@link JwkThumbprint#toString() toString()}. @@ -101,7 +101,7 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @see Jwks.HASH */ - T setIdFromThumbprint(HashAlgorithm alg); + T idFromThumbprint(HashAlgorithm alg); /** * Sets the JWK
{@code key_ops} @@ -174,5 +174,5 @@ public interface JwkBuilder, T extends JwkBuilde * @return the builder for method chaining. * @throws IllegalArgumentException if {@code ops} is {@code null} or empty. */ - T setOperations(Set ops) throws IllegalArgumentException; + T operations(Set ops) throws IllegalArgumentException; } diff --git a/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java b/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java index 7dd07f5e9..7390765f4 100644 --- a/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/JwkParserBuilder.java @@ -25,7 +25,7 @@ * A builder to construct a {@link JwkParser}. Example usage: *
  * Jwk<?> jwk = Jwks.parser()
- *         .setProvider(aJcaProvider)         // optional
+ *         .provider(aJcaProvider)            // optional
  *         .deserializeJsonWith(deserializer) // optional
  *         .build()
  *         .parse(jwkString);
@@ -42,7 +42,7 @@ public interface JwkParserBuilder extends Builder { * if the JCA subsystem preferred provider should be used. * @return the builder for method chaining. */ - JwkParserBuilder setProvider(Provider provider); + JwkParserBuilder provider(Provider provider); /** * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. The diff --git a/api/src/main/java/io/jsonwebtoken/security/Jwks.java b/api/src/main/java/io/jsonwebtoken/security/Jwks.java index 3f502be48..3dc9a76ed 100644 --- a/api/src/main/java/io/jsonwebtoken/security/Jwks.java +++ b/api/src/main/java/io/jsonwebtoken/security/Jwks.java @@ -54,7 +54,7 @@ private Jwks() { *
      * Jwks.{@link Jwks#builder}()
      *     // ... etc ...
-     *     .{@link JwkBuilder#setIdFromThumbprint(HashAlgorithm) setIdFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // <---
+     *     .{@link JwkBuilder#idFromThumbprint(HashAlgorithm) idFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // <---
      *     .build()
*

or

*
diff --git a/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java
index f51e14b9b..c9bdb3fcf 100644
--- a/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/security/PrivateJwkBuilder.java
@@ -26,7 +26,7 @@
  * @param  the type of {@link PrivateJwk} created
  * @param  the type of {@link PublicJwk} paired with the created private JWK.
  * @param  the type of the builder, for subtype method chaining
- * @see #setPublicKey(PublicKey)
+ * @see #publicKey(PublicKey)
  * @since JJWT_RELEASE_VERSION
  */
 public interface PrivateJwkBuilderAs discussed in the {@link PrivateJwk} documentation, the JWK and JWA specifications require private JWKs to
      * contain both private key and public key data.  If a public key is not provided via this
-     * {@code setPublicKey} method, the builder implementation must go through the work to derive the
+     * {@code publicKey} method, the builder implementation must go through the work to derive the
      * {@code PublicKey} instance based on the {@code PrivateKey} to obtain the necessary public key information.

* *

Calling this method with the {@code PrivateKey}'s matching {@code PublicKey} instance eliminates the need @@ -49,5 +49,5 @@ public interface PrivateJwkBuilder> extends JwkBui * @param key the {@link SecretKey} to represent as a {@link SecretJwk}. * @return the builder coerced as a {@link SecretJwkBuilder}. */ - SecretJwkBuilder forKey(SecretKey key); + SecretJwkBuilder key(SecretKey key); /** * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link RSAPublicKey}. @@ -51,20 +51,20 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link RSAPublicKey} to represent as a {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPublicJwkBuilder}. */ - RsaPublicJwkBuilder forKey(RSAPublicKey key); + RsaPublicJwkBuilder key(RSAPublicKey key); /** * Ensures the builder will create an {@link RsaPrivateJwk} for the specified Java {@link RSAPrivateKey}. If * possible, it is recommended to also call the resulting builder's - * {@link RsaPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method with the private key's matching + * {@link RsaPrivateJwkBuilder#publicKey(PublicKey) publicKey} method with the private key's matching * {@link PublicKey} for better performance. See the - * {@link RsaPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} and {@link PrivateJwk} JavaDoc for more + * {@link RsaPrivateJwkBuilder#publicKey(PublicKey) publicKey} and {@link PrivateJwk} JavaDoc for more * information. * * @param key the {@link RSAPublicKey} to represent as a {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPrivateJwkBuilder}. */ - RsaPrivateJwkBuilder forKey(RSAPrivateKey key); + RsaPrivateJwkBuilder key(RSAPrivateKey key); /** * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link ECPublicKey}. @@ -72,31 +72,31 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link ECPublicKey} to represent as a {@link EcPublicJwk}. * @return the builder coerced as an {@link EcPublicJwkBuilder}. */ - EcPublicJwkBuilder forKey(ECPublicKey key); + EcPublicJwkBuilder key(ECPublicKey key); /** * Ensures the builder will create an {@link EcPrivateJwk} for the specified Java {@link ECPrivateKey}. If * possible, it is recommended to also call the resulting builder's - * {@link EcPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method with the private key's matching + * {@link EcPrivateJwkBuilder#publicKey(PublicKey) publicKey} method with the private key's matching * {@link PublicKey} for better performance. See the - * {@link EcPrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} and {@link PrivateJwk} JavaDoc for more + * {@link EcPrivateJwkBuilder#publicKey(PublicKey) publicKey} and {@link PrivateJwk} JavaDoc for more * information. * * @param key the {@link ECPublicKey} to represent as an {@link EcPublicJwk}. * @return the builder coerced as a {@link EcPrivateJwkBuilder}. */ - EcPrivateJwkBuilder forKey(ECPrivateKey key); + EcPrivateJwkBuilder key(ECPrivateKey key); /** * Ensures the builder will create a {@link PublicJwk} for the specified Java {@link PublicKey} argument. This - * method is provided for congruence with the other {@code forKey} methods and is expected to be used when + * method is provided for congruence with the other {@code key} methods and is expected to be used when * the calling code has an untyped {@code PublicKey} reference. Based on the argument type, it will delegate to one * of the following methods if possible: *

    - *
  • {@link #forKey(RSAPublicKey)}
  • - *
  • {@link #forKey(ECPublicKey)}
  • - *
  • {@link #forOctetKey(PublicKey)}
  • + *
  • {@link #key(RSAPublicKey)}
  • + *
  • {@link #key(ECPublicKey)}
  • + *
  • {@link #octetKey(PublicKey)}
  • *
* *

If the specified {@code key} argument is not capable of being supported by one of those methods, an @@ -106,10 +106,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

In addition to the public key type A, the public key's associated private key type * B is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PublicJwkBuilder#setPrivateKey(PrivateKey) setPrivateKey} method will be type-safe. For example:

+ * {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:

* - *
Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPublicKey)
-     *     .setPrivateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
+     * 
Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPublicKey)
+     *     .privateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
      *     ... etc ...
      *     .build();
* @@ -119,21 +119,21 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link PublicKey} to represent as a {@link PublicJwk}. * @return the builder coerced as a {@link PublicJwkBuilder} for continued method chaining. * @throws UnsupportedKeyException if the specified key is not a supported type and cannot be used to delegate to - * other {@code forKey} methods. + * other {@code key} methods. * @see PublicJwk * @see PrivateJwk */ -
PublicJwkBuilder forKey(A key) throws UnsupportedKeyException; + PublicJwkBuilder key(A key) throws UnsupportedKeyException; /** * Ensures the builder will create a {@link PrivateJwk} for the specified Java {@link PrivateKey} argument. This - * method is provided for congruence with the other {@code forKey} methods and is expected to be used when + * method is provided for congruence with the other {@code key} methods and is expected to be used when * the calling code has an untyped {@code PrivateKey} reference. Based on the argument type, it will delegate to one * of the following methods if possible: *
    - *
  • {@link #forKey(RSAPrivateKey)}
  • - *
  • {@link #forKey(ECPrivateKey)}
  • - *
  • {@link #forOctetKey(PrivateKey)}
  • + *
  • {@link #key(RSAPrivateKey)}
  • + *
  • {@link #key(ECPrivateKey)}
  • + *
  • {@link #octetKey(PrivateKey)}
  • *
* *

If the specified {@code key} argument is not capable of being supported by one of those methods, an @@ -143,10 +143,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

In addition to the private key type B, the private key's associated public key type * A is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method will be type-safe. For example:

+ * {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:

* - *
Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPrivateKey)
-     *     .setPublicKey(aPublicKey) // <-- must be an EdECPublicKey instance
+     * 
Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPrivateKey)
+     *     .publicKey(aPublicKey) // <-- must be an EdECPublicKey instance
      *     ... etc ...
      *     .build();
* @@ -155,11 +155,11 @@ public interface ProtoJwkBuilder> extends JwkBui * @param key the {@link PrivateKey} to represent as a {@link PrivateJwk}. * @return the builder coerced as a {@link PrivateJwkBuilder} for continued method chaining. * @throws UnsupportedKeyException if the specified key is not a supported type and cannot be used to delegate to - * other {@code forKey} methods. + * other {@code key} methods. * @see PublicJwk * @see PrivateJwk */ -
PrivateJwkBuilder forKey(B key) throws UnsupportedKeyException; + PrivateJwkBuilder key(B key) throws UnsupportedKeyException; /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Edwards-curve {@code PublicKey} @@ -175,10 +175,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

In addition to the public key type A, the public key's associated private key type * B is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PublicJwkBuilder#setPrivateKey(PrivateKey) setPrivateKey} method will be type-safe. For example:

+ * {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:

* - *
Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPublicKey)
-     *     .setPrivateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
+     * 
Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPublicKey)
+     *     .privateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
      *     ... etc ...
      *     .build();
* @@ -191,7 +191,7 @@ public interface ProtoJwkBuilder> extends JwkBui * @see
java.security.interfaces.XECPublicKey * @see java.security.interfaces.EdECPublicKey */ - OctetPublicJwkBuilder forOctetKey(A key); + OctetPublicJwkBuilder octetKey(A key); /** * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Edwards-curve {@code PrivateKey} @@ -209,10 +209,10 @@ public interface ProtoJwkBuilder> extends JwkBui * *

In addition to the private key type B, the private key's associated public key type * A is parameterized as well. This ensures that any subsequent call to the builder's - * {@link PrivateJwkBuilder#setPublicKey(PublicKey) setPublicKey} method will be type-safe. For example:

+ * {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:

* - *
Jwks.builder().<EdECPublicKey, EdECPrivateKey>forKey(anEdECPrivateKey)
-     *     .setPublicKey(aPublicKey) // <-- must be an EdECPublicKey instance
+     * 
Jwks.builder().<EdECPublicKey, EdECPrivateKey>key(anEdECPrivateKey)
+     *     .publicKey(aPublicKey) // <-- must be an EdECPublicKey instance
      *     ... etc ...
      *     .build();
* @@ -225,14 +225,14 @@ public interface ProtoJwkBuilder> extends JwkBui * @see
java.security.interfaces.XECPrivateKey * @see java.security.interfaces.EdECPrivateKey */ - OctetPrivateJwkBuilder forOctetKey(A key); + OctetPrivateJwkBuilder octetKey(A key); /** * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Java Edwards-curve * {@link KeyPair}. The pair's {@link KeyPair#getPublic() public key} MUST be an - * Edwards-curve public key as defined by {@link #forOctetKey(PublicKey)}. The pair's + * Edwards-curve public key as defined by {@link #octetKey(PublicKey)}. The pair's * {@link KeyPair#getPrivate() private key} MUST be an Edwards-curve private key as defined by - * {@link #forOctetKey(PrivateKey)}. + * {@link #octetKey(PrivateKey)}. * * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. @@ -241,13 +241,13 @@ public interface ProtoJwkBuilder> extends JwkBui * @throws IllegalArgumentException if the {@code keyPair} does not contain Edwards-curve public and private key * instances. */ - OctetPrivateJwkBuilder forOctetKeyPair(KeyPair keyPair); + OctetPrivateJwkBuilder octetKeyPair(KeyPair keyPair); /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Java {@link X509Certificate} chain. * The first {@code X509Certificate} in the chain (at list index 0) MUST * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by - * {@link #forOctetKey(PublicKey)}. + * {@link #octetKey(PublicKey)}. * * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce @@ -256,13 +256,13 @@ public interface ProtoJwkBuilder> extends JwkBui * represent as an {@link OctetPublicJwk}. * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. */ - OctetPublicJwkBuilder forOctetChain(List chain); + OctetPublicJwkBuilder octetChain(List chain); /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Java {@link X509Certificate} chain. * The first {@code X509Certificate} in the chain (at array index 0) MUST * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by - * {@link #forOctetKey(PublicKey)}. + * {@link #octetKey(PublicKey)}. * * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce @@ -271,7 +271,7 @@ public interface ProtoJwkBuilder> extends JwkBui * represent as an {@link OctetPublicJwk}. * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. */ - OctetPublicJwkBuilder forOctetChain(X509Certificate... chain); + OctetPublicJwkBuilder octetChain(X509Certificate... chain); /** * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -282,7 +282,7 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link EcPublicJwk}. * @return the builder coerced as an {@link EcPublicJwkBuilder}. */ - EcPublicJwkBuilder forEcChain(X509Certificate... chain); + EcPublicJwkBuilder ecChain(X509Certificate... chain); /** * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -293,7 +293,7 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link EcPublicJwk}. * @return the builder coerced as an {@link EcPublicJwkBuilder}. */ - EcPublicJwkBuilder forEcChain(List chain); + EcPublicJwkBuilder ecChain(List chain); /** * Ensures the builder will create an {@link EcPrivateJwk} for the specified Java Elliptic Curve @@ -306,7 +306,7 @@ public interface ProtoJwkBuilder> extends JwkBui * @throws IllegalArgumentException if the {@code keyPair} does not contain {@link ECPublicKey} and * {@link ECPrivateKey} instances. */ - EcPrivateJwkBuilder forEcKeyPair(KeyPair keyPair) throws IllegalArgumentException; + EcPrivateJwkBuilder ecKeyPair(KeyPair keyPair) throws IllegalArgumentException; /** * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -317,7 +317,7 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPublicJwkBuilder}. */ - RsaPublicJwkBuilder forRsaChain(X509Certificate... chain); + RsaPublicJwkBuilder rsaChain(X509Certificate... chain); /** * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -328,7 +328,7 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link RsaPublicJwk}. * @return the builder coerced as an {@link RsaPublicJwkBuilder}. */ - RsaPublicJwkBuilder forRsaChain(List chain); + RsaPublicJwkBuilder rsaChain(List chain); /** * Ensures the builder will create an {@link RsaPrivateJwk} for the specified Java RSA @@ -341,5 +341,5 @@ public interface ProtoJwkBuilder> extends JwkBui * @throws IllegalArgumentException if the {@code keyPair} does not contain {@link RSAPublicKey} and * {@link RSAPrivateKey} instances. */ - RsaPrivateJwkBuilder forRsaKeyPair(KeyPair keyPair) throws IllegalArgumentException; + RsaPrivateJwkBuilder rsaKeyPair(KeyPair keyPair) throws IllegalArgumentException; } diff --git a/api/src/main/java/io/jsonwebtoken/security/PublicJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/PublicJwkBuilder.java index adfcc5a3e..1687cce82 100644 --- a/api/src/main/java/io/jsonwebtoken/security/PublicJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/PublicJwkBuilder.java @@ -27,7 +27,7 @@ * @param the type of {@link PrivateJwk} that matches the created {@link PublicJwk} * @param

the type of {@link PrivateJwkBuilder} that matches this builder if a {@link PrivateJwk} is desired. * @param the type of the builder, for subtype method chaining - * @see #setPrivateKey(PrivateKey) + * @see #privateKey(PrivateKey) * @since JJWT_RELEASE_VERSION */ public interface PublicJwkBuilder The type of object that will be created each time {@link #build()} is invoked. - * @see #setProvider(Provider) - * @see #setRandom(SecureRandom) + * @see #provider(Provider) + * @see #random(SecureRandom) * @since JJWT_RELEASE_VERSION */ public interface SecurityBuilder> extends Builder { @@ -38,7 +38,7 @@ public interface SecurityBuilder> extends Bui * @param provider the JCA Security Provider instance to use if necessary when building the new instance. * @return the builder for method chaining. */ - B setProvider(Provider provider); + B provider(Provider provider); /** * Sets the {@link SecureRandom} to use if necessary when calling {@link #build()}. This is an optional property @@ -47,5 +47,5 @@ public interface SecurityBuilder> extends Bui * @param random the {@link SecureRandom} instance to use if necessary when building the new instance. * @return the builder for method chaining. */ - B setRandom(SecureRandom random); + B random(SecureRandom random); } diff --git a/api/src/main/java/io/jsonwebtoken/security/X509Builder.java b/api/src/main/java/io/jsonwebtoken/security/X509Builder.java index 99a7551d0..215dd48f8 100644 --- a/api/src/main/java/io/jsonwebtoken/security/X509Builder.java +++ b/api/src/main/java/io/jsonwebtoken/security/X509Builder.java @@ -28,8 +28,8 @@ public interface X509Builder> extends X509Mutator { /** * If the {@code enable} argument is {@code true}, compute the SHA-1 thumbprint of the first - * {@link X509Certificate} in the configured {@link #setX509CertificateChain(List) x509CertificateChain}, and set - * the resulting value as the {@link #setX509CertificateSha1Thumbprint(byte[])} parameter. + * {@link X509Certificate} in the configured {@link #x509CertificateChain(List) x509CertificateChain}, and set + * the resulting value as the {@link #x509CertificateSha1Thumbprint(byte[])} parameter. * *

If no chain has been configured, or {@code enable} is {@code false}, the builder will not compute nor add a * {@code x5t} value.

@@ -42,8 +42,8 @@ public interface X509Builder> extends X509Mutator { /** * If the {@code enable} argument is {@code true}, compute the SHA-256 thumbprint of the first - * {@link X509Certificate} in the configured {@link #setX509CertificateChain(List) x509CertificateChain}, and set - * the resulting value as the {@link #setX509CertificateSha256Thumbprint(byte[])} parameter. + * {@link X509Certificate} in the configured {@link #x509CertificateChain(List) x509CertificateChain}, and set + * the resulting value as the {@link #x509CertificateSha256Thumbprint(byte[])} parameter. * *

If no chain has been configured, or {@code enable} is {@code false}, the builder will not compute nor add a * {@code x5t#S256} value.

diff --git a/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java b/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java index 2fa241f8d..cd72d0b3a 100644 --- a/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java +++ b/api/src/main/java/io/jsonwebtoken/security/X509Mutator.java @@ -62,7 +62,7 @@ public interface X509Mutator> { * @see
JWS x5u (X.509 URL) Header Parameter * @see JWE x5u (X.509 URL) Header Parameter */ - T setX509Url(URI uri); + T x509Url(URI uri); /** * Sets the {@code x5c} (X.509 Certificate Chain) of the associated JWT or JWK. A {@code null} value will remove the @@ -85,7 +85,7 @@ public interface X509Mutator> { * @see JWS x5c (X.509 Certificate Chain) Header Parameter * @see JWE x5c (X.509 Certificate Chain) Header Parameter */ - T setX509CertificateChain(List chain); + T x509CertificateChain(List chain); /** * Sets the {@code x5t} (X.509 Certificate SHA-1 Thumbprint) (a.k.a. digest) of the DER-encoding of the @@ -111,7 +111,7 @@ public interface X509Mutator> { * @see JWS x5t (X.509 Certificate SHA-1 Thumbprint) Header Parameter * @see JWE x5t (X.509 Certificate SHA-1 Thumbprint) Header Parameter */ - T setX509CertificateSha1Thumbprint(byte[] thumbprint); + T x509CertificateSha1Thumbprint(byte[] thumbprint); /** * Sets the {@code x5t#S256} (X.509 Certificate SHA-256 Thumbprint) (a.k.a. digest) of the DER-encoding of the @@ -137,5 +137,5 @@ public interface X509Mutator> { * @see JWS x5t#S256 (X.509 Certificate SHA-256 Thumbprint) Header Parameter * @see JWE x5t#S256 (X.509 Certificate SHA-256 Thumbprint) Header Parameter */ - T setX509CertificateSha256Thumbprint(byte[] thumbprint); + T x509CertificateSha256Thumbprint(byte[] thumbprint); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java b/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java index 202aeffea..93ebc65c8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/AbstractX509Context.java @@ -41,7 +41,7 @@ public URI getX509Url() { } @Override - public T setX509Url(URI uri) { + public T x509Url(URI uri) { put(AbstractAsymmetricJwk.X5U, uri); return self(); } @@ -52,7 +52,7 @@ public List getX509CertificateChain() { } @Override - public T setX509CertificateChain(List chain) { + public T x509CertificateChain(List chain) { put(AbstractAsymmetricJwk.X5C, chain); return self(); } @@ -63,7 +63,7 @@ public byte[] getX509CertificateSha1Thumbprint() { } @Override - public T setX509CertificateSha1Thumbprint(byte[] thumbprint) { + public T x509CertificateSha1Thumbprint(byte[] thumbprint) { put(AbstractAsymmetricJwk.X5T, thumbprint); return self(); } @@ -74,7 +74,7 @@ public byte[] getX509CertificateSha256Thumbprint() { } @Override - public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { + public T x509CertificateSha256Thumbprint(byte[] thumbprint) { put(AbstractAsymmetricJwk.X5T_S256, thumbprint); return self(); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java index 4d5643e2b..2b53cdd2a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java @@ -40,36 +40,71 @@ ClaimsBuilder put(Field field, Object value) { @Override public ClaimsBuilder setIssuer(String iss) { + return issuer(iss); + } + + @Override + public ClaimsBuilder issuer(String iss) { return put(DefaultClaims.ISSUER, iss); } @Override public ClaimsBuilder setSubject(String sub) { + return subject(sub); + } + + @Override + public ClaimsBuilder subject(String sub) { return put(DefaultClaims.SUBJECT, sub); } @Override public ClaimsBuilder setAudience(String aud) { + return audience(aud); + } + + @Override + public ClaimsBuilder audience(String aud) { return put(DefaultClaims.AUDIENCE, aud); } @Override public ClaimsBuilder setExpiration(Date exp) { + return expiration(exp); + } + + @Override + public ClaimsBuilder expiration(Date exp) { return put(DefaultClaims.EXPIRATION, exp); } @Override public ClaimsBuilder setNotBefore(Date nbf) { + return notBefore(nbf); + } + + @Override + public ClaimsBuilder notBefore(Date nbf) { return put(DefaultClaims.NOT_BEFORE, nbf); } @Override public ClaimsBuilder setIssuedAt(Date iat) { + return issuedAt(iat); + } + + @Override + public ClaimsBuilder issuedAt(Date iat) { return put(DefaultClaims.ISSUED_AT, iat); } @Override public ClaimsBuilder setId(String jti) { + return id(jti); + } + + @Override + public ClaimsBuilder id(String jti) { return put(DefaultClaims.JTI, jti); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java index bbefc9c04..7bc5b63de 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java @@ -67,47 +67,42 @@ public void clear() { // JWT Header methods // ============================================================= - @Override - public T setAlgorithm(String alg) { - return put(DefaultHeader.ALGORITHM, alg); - } +// @Override +// public T algorithm(String alg) { +// return put(DefaultHeader.ALGORITHM, alg); +// } @Override - public T setContentType(String cty) { + public T contentType(String cty) { return put(DefaultHeader.CONTENT_TYPE, cty); } @Override - public T setType(String typ) { + public T type(String typ) { return put(DefaultHeader.TYPE, typ); } - @Override - public T setCompressionAlgorithm(String zip) { - return put(DefaultHeader.COMPRESSION_ALGORITHM, zip); - } - // ============================================================= // Protected Header methods // ============================================================= @Override - public T setJwkSetUrl(URI uri) { + public T jwkSetUrl(URI uri) { return put(DefaultProtectedHeader.JKU, uri); } @Override - public T setJwk(PublicJwk jwk) { + public T jwk(PublicJwk jwk) { return put(DefaultProtectedHeader.JWK, jwk); } @Override - public T setKeyId(String kid) { + public T keyId(String kid) { return put(DefaultProtectedHeader.KID, kid); } @Override - public T setCritical(Set crit) { + public T critical(Set crit) { return put(DefaultProtectedHeader.CRIT, crit); } @@ -117,26 +112,26 @@ public T setCritical(Set crit) { // ============================================================= @Override - public T setX509Url(URI uri) { - this.x509.setX509Url(uri); + public T x509Url(URI uri) { + this.x509.x509Url(uri); return self(); } @Override - public T setX509CertificateChain(List chain) { - this.x509.setX509CertificateChain(chain); + public T x509CertificateChain(List chain) { + this.x509.x509CertificateChain(chain); return self(); } @Override - public T setX509CertificateSha1Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha1Thumbprint(thumbprint); + public T x509CertificateSha1Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha1Thumbprint(thumbprint); return self(); } @Override - public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha256Thumbprint(thumbprint); + public T x509CertificateSha256Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha256Thumbprint(thumbprint); return self(); } @@ -145,27 +140,27 @@ public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { // ============================================================= @Override - public T setAgreementPartyUInfo(byte[] info) { + public T agreementPartyUInfo(byte[] info) { return put(DefaultJweHeader.APU, info); } @Override - public T setAgreementPartyUInfo(String info) { - return setAgreementPartyUInfo(Strings.utf8(Strings.clean(info))); + public T agreementPartyUInfo(String info) { + return agreementPartyUInfo(Strings.utf8(Strings.clean(info))); } @Override - public T setAgreementPartyVInfo(byte[] info) { + public T agreementPartyVInfo(byte[] info) { return put(DefaultJweHeader.APV, info); } @Override - public T setAgreementPartyVInfo(String info) { - return setAgreementPartyVInfo(Strings.utf8(Strings.clean(info))); + public T agreementPartyVInfo(String info) { + return agreementPartyVInfo(Strings.utf8(Strings.clean(info))); } @Override - public T setPbes2Count(int count) { + public T pbes2Count(int count) { return put(DefaultJweHeader.P2C, count); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 9800dfacf..2bcd2010d 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -98,13 +98,13 @@ public JwtBuilder.Header header() { } @Override - public JwtBuilder setProvider(Provider provider) { + public JwtBuilder provider(Provider provider) { this.provider = provider; return this; } @Override - public JwtBuilder setSecureRandom(SecureRandom secureRandom) { + public JwtBuilder random(SecureRandom secureRandom) { this.secureRandom = secureRandom; return this; } @@ -294,22 +294,22 @@ public JwtBuilder compressWith(CompressionAlgorithm alg) { @Override public JwtBuilder setPayload(String payload) { byte[] bytes = payload != null ? payload.getBytes(StandardCharsets.UTF_8) : null; - return setContent(bytes); + return content(bytes); } @Override - public JwtBuilder setContent(byte[] content) { + public JwtBuilder content(byte[] content) { this.content = content; return this; } @Override - public JwtBuilder setContent(byte[] content, String cty) { + public JwtBuilder content(byte[] content, String cty) { Assert.notEmpty(content, "content byte array cannot be null or empty."); Assert.hasText(cty, "Content Type String cannot be null or empty."); cty = CompactMediaTypeIdConverter.INSTANCE.applyFrom(cty); - this.headerBuilder.setContentType(cty); - return setContent(content); + this.headerBuilder.contentType(cty); + return content(content); } @Override @@ -334,43 +334,78 @@ public JwtBuilder addClaims(Map claims) { @Override public JwtBuilder setIssuer(String iss) { - this.claimsBuilder.setIssuer(iss); + return issuer(iss); + } + + @Override + public JwtBuilder issuer(String iss) { + this.claimsBuilder.issuer(iss); return this; } @Override public JwtBuilder setSubject(String sub) { - this.claimsBuilder.setSubject(sub); + return subject(sub); + } + + @Override + public JwtBuilder subject(String sub) { + this.claimsBuilder.subject(sub); return this; } @Override public JwtBuilder setAudience(String aud) { - this.claimsBuilder.setAudience(aud); + return audience(aud); + } + + @Override + public JwtBuilder audience(String aud) { + this.claimsBuilder.audience(aud); return this; } @Override public JwtBuilder setExpiration(Date exp) { - this.claimsBuilder.setExpiration(exp); + return expiration(exp); + } + + @Override + public JwtBuilder expiration(Date exp) { + this.claimsBuilder.expiration(exp); return this; } @Override public JwtBuilder setNotBefore(Date nbf) { - this.claimsBuilder.setNotBefore(nbf); + return notBefore(nbf); + } + + @Override + public JwtBuilder notBefore(Date nbf) { + this.claimsBuilder.notBefore(nbf); return this; } @Override public JwtBuilder setIssuedAt(Date iat) { - this.claimsBuilder.setIssuedAt(iat); + return issuedAt(iat); + } + + @Override + public JwtBuilder issuedAt(Date iat) { + this.claimsBuilder.issuedAt(iat); return this; } @Override public JwtBuilder setId(String jti) { - this.claimsBuilder.setId(jti); + return id(jti); + } + + @Override + public JwtBuilder id(String jti) { + this.claimsBuilder.id(jti); return this; } @@ -415,7 +450,7 @@ public String compact() { } if (!Objects.isEmpty(payload) && compressionAlgorithm != null) { payload = compressionAlgorithm.compress(payload); - this.headerBuilder.setCompressionAlgorithm(compressionAlgorithm.getId()); + this.headerBuilder.set(DefaultHeader.COMPRESSION_ALGORITHM.getId(), compressionAlgorithm.getId()); } if (jwe) { @@ -437,7 +472,7 @@ private String compact(byte[] payload) { // header = new DefaultJwsHeader(header); // } - this.headerBuilder.setAlgorithm(sigAlg.getId()); + this.headerBuilder.set(DefaultHeader.ALGORITHM.getId(), sigAlg.getId()); final io.jsonwebtoken.Header header = buildHeader(); @@ -483,7 +518,7 @@ private String encrypt(byte[] payload) { SecretKey cek = Assert.notNull(keyResult.getKey(), "KeyResult must return a content encryption key."); byte[] encryptedCek = Assert.notNull(keyResult.getPayload(), "KeyResult must return an encrypted key byte array, even if empty."); - this.headerBuilder.setAlgorithm(keyAlg.getId()); + this.headerBuilder.set(DefaultHeader.ALGORITHM.getId(), keyAlg.getId()); this.headerBuilder.put(DefaultJweHeader.ENCRYPTION_ALGORITHM.getId(), enc.getId()); final io.jsonwebtoken.Header header = buildHeader(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index 0b797bad3..706f935ea 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -108,22 +108,32 @@ public JwtParserBuilder enableUnsecuredDecompression() { } @Override - public JwtParserBuilder setProvider(Provider provider) { + public JwtParserBuilder provider(Provider provider) { this.provider = provider; return this; } @Override public JwtParserBuilder deserializeJsonWith(Deserializer> deserializer) { + return jsonDeserializer(deserializer); + } + + @Override + public JwtParserBuilder jsonDeserializer(Deserializer> deserializer) { Assert.notNull(deserializer, "deserializer cannot be null."); this.deserializer = deserializer; return this; } @Override - public JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder) { - Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); - this.base64UrlDecoder = base64UrlDecoder; + public JwtParserBuilder base64UrlDecodeWith(Decoder decoder) { + return base64UrlDecoder(decoder); + } + + @Override + public JwtParserBuilder base64UrlDecoder(Decoder decoder) { + Assert.notNull(decoder, "base64UrlDecoder cannot be null."); + this.base64UrlDecoder = decoder; return this; } @@ -179,6 +189,11 @@ public JwtParserBuilder require(String claimName, Object value) { @Override public JwtParserBuilder setClock(Clock clock) { + return clock(clock); + } + + @Override + public JwtParserBuilder clock(Clock clock) { Assert.notNull(clock, "Clock instance cannot be null."); this.clock = clock; return this; @@ -186,6 +201,11 @@ public JwtParserBuilder setClock(Clock clock) { @Override public JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException { + return clockSkewSeconds(seconds); + } + + @Override + public JwtParserBuilder clockSkewSeconds(long seconds) throws IllegalArgumentException { Assert.isTrue(seconds <= MAX_CLOCK_SKEW_MILLIS, MAX_CLOCK_SKEW_ILLEGAL_MSG); this.allowedClockSkewMillis = Math.max(0, seconds * MILLISECONDS_PER_SECOND); return this; @@ -258,7 +278,7 @@ public JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResol } @Override - public JwtParserBuilder setKeyLocator(Locator keyLocator) { + public JwtParserBuilder keyLocator(Locator keyLocator) { this.keyLocator = Assert.notNull(keyLocator, "Key locator cannot be null."); return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java index 70a67a9d4..88d54dcf9 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilder.java @@ -69,7 +69,7 @@ public AbstractAsymmetricJwkBuilder(JwkContext ctx) { } @Override - public T setPublicKeyUse(String use) { + public T publicKeyUse(String use) { Assert.hasText(use, "publicKeyUse cannot be null or empty."); this.DELEGATE.setPublicKeyUse(use); return self(); @@ -83,16 +83,16 @@ public T setKeyUseStrategy(KeyUseStrategy strategy) { */ @Override - public T setX509CertificateChain(List chain) { + public T x509CertificateChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be null or empty."); - this.x509.setX509CertificateChain(chain); + this.x509.x509CertificateChain(chain); return self(); } @Override - public T setX509Url(URI uri) { + public T x509Url(URI uri) { Assert.notNull(uri, "X509Url cannot be null."); - this.x509.setX509Url(uri); + this.x509.x509Url(uri); return self(); } @@ -105,14 +105,14 @@ public T withX509KeyUse(boolean enable) { */ @Override - public T setX509CertificateSha1Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha1Thumbprint(thumbprint); + public T x509CertificateSha1Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha1Thumbprint(thumbprint); return self(); } @Override - public T setX509CertificateSha256Thumbprint(byte[] thumbprint) { - this.x509.setX509CertificateSha256Thumbprint(thumbprint); + public T x509CertificateSha256Thumbprint(byte[] thumbprint) { + this.x509.x509CertificateSha256Thumbprint(thumbprint); return self(); } @@ -145,10 +145,10 @@ private abstract static class DefaultPublicJwkBuilder ctx); @@ -170,7 +170,7 @@ private abstract static class DefaultPrivateJwkBuilder JwkContext newContext(A key) { } @Override - public T setProvider(Provider provider) { + public T provider(Provider provider) { this.DELEGATE.setProvider(provider); return self(); } @Override - public T setRandom(SecureRandom random) { + public T random(SecureRandom random) { this.DELEGATE.setRandom(random); return self(); } @Override - public T setAlgorithm(String alg) { + public T algorithm(String alg) { Assert.hasText(alg, "Algorithm cannot be null or empty."); this.DELEGATE.setAlgorithm(alg); return self(); } @Override - public T setId(String id) { + public T id(String id) { Assert.hasText(id, "Id cannot be null or empty."); this.DELEGATE.setIdThumbprintAlgorithm(null); //clear out any previously set value this.DELEGATE.setId(id); @@ -81,12 +81,12 @@ public T setId(String id) { } @Override - public T setIdFromThumbprint() { - return setIdFromThumbprint(Jwks.HASH.SHA256); + public T idFromThumbprint() { + return idFromThumbprint(Jwks.HASH.SHA256); } @Override - public T setIdFromThumbprint(HashAlgorithm alg) { + public T idFromThumbprint(HashAlgorithm alg) { Assert.notNull(alg, "Thumbprint HashAlgorithm cannot be null."); Assert.notNull(alg.getId(), "Thumbprint HashAlgorithm ID cannot be null."); this.DELEGATE.setId(null); // clear out any previous value @@ -95,7 +95,7 @@ public T setIdFromThumbprint(HashAlgorithm alg) { } @Override - public T setOperations(Set ops) { + public T operations(Set ops) { Assert.notEmpty(ops, "Operations cannot be null or empty."); this.DELEGATE.setOperations(ops); return self(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java index 087fa8d3d..55a126e57 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java @@ -93,7 +93,7 @@ protected Provider getProvider(Request request) { protected SecretKey generateKey(KeyRequest request) { AeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null."); SecretKeyBuilder builder = Assert.notNull(enc.keyBuilder(), "Request encryptionAlgorithm keyBuilder cannot be null."); - SecretKey key = builder.setProvider(getProvider(request)).setRandom(request.getSecureRandom()).build(); + SecretKey key = builder.provider(getProvider(request)).random(request.getSecureRandom()).build(); return Assert.notNull(key, "Request encryptionAlgorithm SecretKeyBuilder cannot produce null keys."); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java index 7598cf641..af4d2f64c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java @@ -75,6 +75,6 @@ public String toString() { } public KeyPairBuilder keyPairBuilder() { - return new DefaultKeyPairBuilder(this.JCA_NAME).setProvider(this.PROVIDER); + return new DefaultKeyPairBuilder(this.JCA_NAME).provider(this.PROVIDER); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java index 864087893..346d2ccc4 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java @@ -59,7 +59,7 @@ public Jwk parse(String json) throws KeyException { JwkBuilder builder = Jwks.builder(); if (this.provider != null) { - builder.setProvider(this.provider); + builder.provider(this.provider); } return builder.set(data).build(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java index a2ed3a818..d71822be0 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParserBuilder.java @@ -31,7 +31,7 @@ public class DefaultJwkParserBuilder implements JwkParserBuilder { private Deserializer> deserializer; @Override - public JwkParserBuilder setProvider(Provider provider) { + public JwkParserBuilder provider(Provider provider) { this.provider = provider; return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java index 9c70e0a1a..3d21081cc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyPairBuilder.java @@ -50,13 +50,13 @@ public DefaultKeyPairBuilder(String jcaName, AlgorithmParameterSpec params) { } @Override - public KeyPairBuilder setProvider(Provider provider) { + public KeyPairBuilder provider(Provider provider) { this.provider = provider; return this; } @Override - public KeyPairBuilder setRandom(SecureRandom random) { + public KeyPairBuilder random(SecureRandom random) { this.random = random; return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java index b73ddfc60..709f949fd 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java @@ -52,27 +52,27 @@ public DefaultProtoJwkBuilder() { } @Override - public SecretJwkBuilder forKey(SecretKey key) { + public SecretJwkBuilder key(SecretKey key) { return new AbstractJwkBuilder.DefaultSecretJwkBuilder(newContext(key)); } @Override - public RsaPublicJwkBuilder forKey(RSAPublicKey key) { + public RsaPublicJwkBuilder key(RSAPublicKey key) { return new AbstractAsymmetricJwkBuilder.DefaultRsaPublicJwkBuilder(newContext(key)); } @Override - public RsaPrivateJwkBuilder forKey(RSAPrivateKey key) { + public RsaPrivateJwkBuilder key(RSAPrivateKey key) { return new AbstractAsymmetricJwkBuilder.DefaultRsaPrivateJwkBuilder(newContext(key)); } @Override - public EcPublicJwkBuilder forKey(ECPublicKey key) { + public EcPublicJwkBuilder key(ECPublicKey key) { return new AbstractAsymmetricJwkBuilder.DefaultEcPublicJwkBuilder(newContext(key)); } @Override - public EcPrivateJwkBuilder forKey(ECPrivateKey key) { + public EcPrivateJwkBuilder key(ECPrivateKey key) { return new AbstractAsymmetricJwkBuilder.DefaultEcPrivateJwkBuilder(newContext(key)); } @@ -84,14 +84,14 @@ private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { @SuppressWarnings("unchecked") @Override - public PublicJwkBuilder forKey(A key) { + public PublicJwkBuilder key(A key) { if (key instanceof RSAPublicKey) { - return (PublicJwkBuilder) forKey((RSAPublicKey) key); + return (PublicJwkBuilder) key((RSAPublicKey) key); } else if (key instanceof ECPublicKey) { - return (PublicJwkBuilder) forKey((ECPublicKey) key); + return (PublicJwkBuilder) key((ECPublicKey) key); } else { try { - return forOctetKey(key); + return octetKey(key); } catch (Exception e) { throw unsupportedKey(key, e); } @@ -100,15 +100,15 @@ private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { @SuppressWarnings("unchecked") @Override - public PrivateJwkBuilder forKey(B key) { + public PrivateJwkBuilder key(B key) { Assert.notNull(key, "Key cannot be null."); if (key instanceof RSAPrivateKey) { - return (PrivateJwkBuilder) forKey((RSAPrivateKey) key); + return (PrivateJwkBuilder) key((RSAPrivateKey) key); } else if (key instanceof ECPrivateKey) { - return (PrivateJwkBuilder) forKey((ECPrivateKey) key); + return (PrivateJwkBuilder) key((ECPrivateKey) key); } else { try { - return forOctetKey(key); + return octetKey(key); } catch (Exception e) { throw unsupportedKey(key, e); } @@ -116,84 +116,84 @@ private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { } @Override - public OctetPublicJwkBuilder forOctetKey(A key) { + public OctetPublicJwkBuilder octetKey(A key) { return new AbstractAsymmetricJwkBuilder.DefaultOctetPublicJwkBuilder<>(newContext(key)); } @Override - public OctetPrivateJwkBuilder forOctetKey(A key) { + public OctetPrivateJwkBuilder octetKey(A key) { return new AbstractAsymmetricJwkBuilder.DefaultOctetPrivateJwkBuilder<>(newContext(key)); } @Override - public RsaPublicJwkBuilder forRsaChain(X509Certificate... chain) { + public RsaPublicJwkBuilder rsaChain(X509Certificate... chain) { Assert.notEmpty(chain, "chain cannot be null or empty."); - return forRsaChain(Arrays.asList(chain)); + return rsaChain(Arrays.asList(chain)); } @Override - public RsaPublicJwkBuilder forRsaChain(List chain) { + public RsaPublicJwkBuilder rsaChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); X509Certificate cert = chain.get(0); PublicKey key = cert.getPublicKey(); RSAPublicKey pubKey = KeyPairs.assertKey(key, RSAPublicKey.class, "The first X509Certificate's "); - return forKey(pubKey).setX509CertificateChain(chain); + return key(pubKey).x509CertificateChain(chain); } @Override - public EcPublicJwkBuilder forEcChain(X509Certificate... chain) { + public EcPublicJwkBuilder ecChain(X509Certificate... chain) { Assert.notEmpty(chain, "chain cannot be null or empty."); - return forEcChain(Arrays.asList(chain)); + return ecChain(Arrays.asList(chain)); } @Override - public EcPublicJwkBuilder forEcChain(List chain) { + public EcPublicJwkBuilder ecChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); X509Certificate cert = chain.get(0); PublicKey key = cert.getPublicKey(); ECPublicKey pubKey = KeyPairs.assertKey(key, ECPublicKey.class, "The first X509Certificate's "); - return forKey(pubKey).setX509CertificateChain(chain); + return key(pubKey).x509CertificateChain(chain); } @SuppressWarnings("unchecked") // ok because of the EdwardsCurve.assertEdwards calls @Override - public OctetPrivateJwkBuilder forOctetKeyPair(KeyPair pair) { + public OctetPrivateJwkBuilder octetKeyPair(KeyPair pair) { PublicKey pub = KeyPairs.getKey(pair, PublicKey.class); PrivateKey priv = KeyPairs.getKey(pair, PrivateKey.class); EdwardsCurve.assertEdwards(pub); EdwardsCurve.assertEdwards(priv); - return (OctetPrivateJwkBuilder) forOctetKey(priv).setPublicKey(pub); + return (OctetPrivateJwkBuilder) octetKey(priv).publicKey(pub); } @Override - public OctetPublicJwkBuilder forOctetChain(X509Certificate... chain) { + public OctetPublicJwkBuilder octetChain(X509Certificate... chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be null or empty."); - return forOctetChain(Arrays.asList(chain)); + return octetChain(Arrays.asList(chain)); } @SuppressWarnings("unchecked") // ok because of the EdwardsCurve.assertEdwards calls @Override - public OctetPublicJwkBuilder forOctetChain(List chain) { + public OctetPublicJwkBuilder octetChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); X509Certificate cert = chain.get(0); PublicKey key = cert.getPublicKey(); Assert.notNull(key, "The first X509Certificate's PublicKey cannot be null."); EdwardsCurve.assertEdwards(key); - return this.forOctetKey((A) key).setX509CertificateChain(chain); + return this.octetKey((A) key).x509CertificateChain(chain); } @Override - public RsaPrivateJwkBuilder forRsaKeyPair(KeyPair pair) { + public RsaPrivateJwkBuilder rsaKeyPair(KeyPair pair) { RSAPublicKey pub = KeyPairs.getKey(pair, RSAPublicKey.class); RSAPrivateKey priv = KeyPairs.getKey(pair, RSAPrivateKey.class); - return forKey(priv).setPublicKey(pub); + return key(priv).publicKey(pub); } @Override - public EcPrivateJwkBuilder forEcKeyPair(KeyPair pair) { + public EcPrivateJwkBuilder ecKeyPair(KeyPair pair) { ECPublicKey pub = KeyPairs.getKey(pair, ECPublicKey.class); ECPrivateKey priv = KeyPairs.getKey(pair, ECPrivateKey.class); - return forKey(priv).setPublicKey(pub); + return key(priv).publicKey(pub); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java index 63ead5912..c4f2002bc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultSecretKeyBuilder.java @@ -39,17 +39,17 @@ public DefaultSecretKeyBuilder(String jcaName, int bitLength) { throw new IllegalArgumentException(msg); } this.BIT_LENGTH = Assert.gt(bitLength, 0, "bitLength must be > 0"); - setRandom(Randoms.secureRandom()); + random(Randoms.secureRandom()); } @Override - public SecretKeyBuilder setProvider(Provider provider) { + public SecretKeyBuilder provider(Provider provider) { this.provider = provider; return this; } @Override - public SecretKeyBuilder setRandom(SecureRandom random) { + public SecretKeyBuilder random(SecureRandom random) { this.random = random != null ? random : Randoms.secureRandom(); return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java index ccf137c2f..8b40485e0 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java @@ -102,8 +102,8 @@ public EcSignatureAlgorithm(int orderBitLength) { @Override public KeyPairBuilder keyPairBuilder() { return new DefaultKeyPairBuilder(ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, this.KEY_PAIR_GEN_PARAMS) - .setProvider(getProvider()) - .setRandom(Randoms.secureRandom()); + .provider(getProvider()) + .random(Randoms.secureRandom()); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java index 84f6e19a7..e763c4e3d 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java @@ -98,7 +98,7 @@ protected KeyPair generateKeyPair(final Request request, final ECParameterSpe //visible for testing, for Edwards elliptic curves protected KeyPair generateKeyPair(SecureRandom random, EdwardsCurve curve, Provider provider) { - return curve.keyPairBuilder().setProvider(provider).setRandom(random).build(); + return curve.keyPairBuilder().provider(provider).random(random).build(); } protected byte[] generateZ(final KeyRequest request, final PublicKey pub, final PrivateKey priv) { @@ -183,7 +183,7 @@ public KeyResult getEncryptionKey(KeyRequest request) throws Security KeyPair pair; // generated (ephemeral) key pair final SecureRandom random = ensureSecureRandom(request); - ProtoJwkBuilder jwkBuilder = Jwks.builder().setRandom(random); + ProtoJwkBuilder jwkBuilder = Jwks.builder().random(random); if (publicKey instanceof ECKey) { ECKey ecPublicKey = (ECKey) publicKey; @@ -204,13 +204,13 @@ public KeyResult getEncryptionKey(KeyRequest request) throws Security request.getHeader(), request.getEncryptionAlgorithm()); } pair = generateKeyPair(random, curve, provider); - jwkBuilder.setProvider(provider); + jwkBuilder.provider(provider); } Assert.stateNotNull(pair, "Internal implementation state: KeyPair cannot be null."); // This asserts that the generated public key (and therefore the request key) is on a JWK-supported curve: - PublicJwk jwk = jwkBuilder.forKey(pair.getPublic()).build(); + PublicJwk jwk = jwkBuilder.key(pair.getPublic()).build(); final SecretKey derived = deriveKey(request, publicKey, pair.getPrivate()); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java index e1c4ccd99..d5a06ed9a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java @@ -358,7 +358,7 @@ public boolean isSignatureCurve() { @Override public KeyPairBuilder keyPairBuilder() { - return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).setProvider(getProvider()); + return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).provider(getProvider()); } public static boolean isEdwards(Key key) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java index 453a9d1b7..de257a20a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java @@ -51,7 +51,7 @@ public PublicKey apply(PrivateKey privateKey) { // Since we already have a private key, we provide a RNG that 'generates' the existing private key // instead of a random one, and the corresponding public key will be computed for us automatically. SecureRandom random = new ConstantRandom(pkBytes); - KeyPair pair = curve.keyPairBuilder().setRandom(random).build(); + KeyPair pair = curve.keyPairBuilder().random(random).build(); Assert.stateNotNull(pair, "Edwards curve generated keypair cannot be null."); return Assert.stateNotNull(pair.getPublic(), "Edwards curve KeyPair must have a PublicKey"); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java index c7dc1fc75..2dc049c6d 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java @@ -80,8 +80,8 @@ public Signature get() throws Exception { @Override public KeyPairBuilder keyPairBuilder() { return new DefaultKeyPairBuilder("RSA", this.preferredKeyBitLength) - .setProvider(getProvider()) - .setRandom(Randoms.secureRandom()); + .provider(getProvider()) + .random(Randoms.secureRandom()); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java index 67a2ccc4a..99e051860 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java @@ -145,7 +145,7 @@ public static int estimateIterations(KeyAlgorithm alg, long char[] password = randomChars(PASSWORD_LENGTH); Password key = Keys.forPassword(password); - HEADER.setPbes2Count(workFactor); + HEADER.pbes2Count(workFactor); KeyRequest request = new DefaultKeyRequest<>(null, null, key, HEADER, ENC_ALG); long start = System.currentTimeMillis(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java b/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java index 76f00fdb7..cc0d2e829 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/X509BuilderSupport.java @@ -72,25 +72,25 @@ public X509BuilderSupport withX509Sha256Thumbprint(boolean enable) { } @Override - public X509BuilderSupport setX509Url(URI uri) { + public X509BuilderSupport x509Url(URI uri) { this.fieldMap.put(AbstractAsymmetricJwk.X5U.getId(), uri); return this; } @Override - public X509BuilderSupport setX509CertificateChain(List chain) { + public X509BuilderSupport x509CertificateChain(List chain) { this.fieldMap.put(AbstractAsymmetricJwk.X5C.getId(), chain); return this; } @Override - public X509BuilderSupport setX509CertificateSha1Thumbprint(byte[] thumbprint) { + public X509BuilderSupport x509CertificateSha1Thumbprint(byte[] thumbprint) { this.fieldMap.put(AbstractAsymmetricJwk.X5T.getId(), thumbprint); return this; } @Override - public X509BuilderSupport setX509CertificateSha256Thumbprint(byte[] thumbprint) { + public X509BuilderSupport x509CertificateSha256Thumbprint(byte[] thumbprint) { this.fieldMap.put(AbstractAsymmetricJwk.X5T_S256.getId(), thumbprint); return this; } @@ -118,11 +118,11 @@ public void apply() { if (firstCert != null) { if (computeX509Sha1Thumbprint) { byte[] thumbprint = computeThumbprint(firstCert, DefaultHashAlgorithm.SHA1); - setX509CertificateSha1Thumbprint(thumbprint); + x509CertificateSha1Thumbprint(thumbprint); } if (computeX509Sha256) { byte[] thumbprint = computeThumbprint(firstCert, Jwks.HASH.SHA256); - setX509CertificateSha256Thumbprint(thumbprint); + x509CertificateSha256Thumbprint(thumbprint); } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index c4dee7712..6506bcb91 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -165,7 +165,7 @@ class JwtsTest { void testSetContentWithContentType() { String s = 'Hello JJWT' String cty = 'text/plain' - String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() + String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals cty, jwt.header.getContentType() assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8) @@ -176,7 +176,7 @@ class JwtsTest { String s = 'Hello JJWT' String subtype = 'foo' String cty = "application/$subtype" - String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() + String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).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) @@ -187,7 +187,7 @@ class JwtsTest { String s = 'Hello JJWT' String subtype = 'foo' String cty = "application/$subtype;part=1/2" - String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact() + String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).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) @@ -1135,7 +1135,7 @@ class JwtsTest { try { Jwts.parser() - .setKeyLocator(new ConstantKeyLocator(TestKeys.HS256, TestKeys.A128GCM)) + .keyLocator(new ConstantKeyLocator(TestKeys.HS256, TestKeys.A128GCM)) .addKeyAlgorithms([badKeyAlg]) // <-- add bad alg here .build() .parseClaimsJwe(compact) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy index f4c644258..4a02d74cd 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy @@ -108,7 +108,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithJwk() { - EcPrivateJwk jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).build() + EcPrivateJwk jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).build() EcPublicJwk pubJwk = jwk.toPublicJwk() def header = h([jwk: pubJwk]) assertEquals pubJwk, header.getJwk() @@ -116,7 +116,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithMap() { - EcPrivateJwk jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).build() + EcPrivateJwk jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).build() EcPublicJwk pubJwk = jwk.toPublicJwk() Map m = new LinkedHashMap<>(pubJwk) def header = h([jwk: m]) @@ -138,7 +138,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithSecretJwk() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() try { h([jwk: jwk]) fail() @@ -151,7 +151,7 @@ class AbstractProtectedHeaderTest { @Test void testJwkWithPrivateJwk() { - EcPrivateJwk jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).build() + EcPrivateJwk jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).build() try { h([jwk: jwk]) fail() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy index cd4dc5243..ca16d5fdf 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweHeaderTest.groovy @@ -57,7 +57,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithSecretJwk() { - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type try { h([epk: values]) @@ -71,7 +71,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithPrivateJwk() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.private as ECPrivateKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.private as ECPrivateKey).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type try { h([epk: values]) @@ -86,7 +86,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithRsaPublicJwk() { - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type def epk = h([epk: values]).getEphemeralPublicKey() assertTrue epk instanceof RsaPublicJwk @@ -95,14 +95,14 @@ class DefaultJweHeaderTest { @Test void testEpkWithEcPublicJwkValues() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.public as ECPublicKey).build() def values = new LinkedHashMap(jwk) //extract values to remove JWK type assertEquals jwk, h([epk: values]).get('epk') } @Test void testEpkWithInvalidEcPublicJwk() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.public as ECPublicKey).build() def values = new LinkedHashMap(jwk) // copy fields so we can mutate // We have a public JWK for a point on the curve, now swap out the x coordinate for something invalid: values.put('x', 'Kg') @@ -121,7 +121,7 @@ class DefaultJweHeaderTest { @Test void testEpkWithEcPublicJwk() { - def jwk = Jwks.builder().forKey(TestKeys.ES256.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES256.pair.public as ECPublicKey).build() header = h([epk: jwk]) assertEquals jwk, header.get('epk') assertEquals jwk, header.getEphemeralPublicKey() @@ -131,7 +131,7 @@ class DefaultJweHeaderTest { void testEpkWithEdPublicJwk() { def keys = TestKeys.EdEC.collect({it -> it.pair.public as PublicKey}) for(PublicKey key : keys) { - def jwk = Jwks.builder().forKey((PublicKey)key as PublicKey).build() + def jwk = Jwks.builder().key((PublicKey)key as PublicKey).build() header = h([epk: jwk]) assertEquals jwk, header.get('epk') assertEquals jwk, header.getEphemeralPublicKey() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index 850eadb27..39b427b7c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -81,7 +81,7 @@ class DefaultJwtBuilderTest { } replay provider - def b = new DefaultJwtBuilder().setProvider(provider) + def b = new DefaultJwtBuilder().provider(provider) .setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg) assertSame provider, b.provider b.compact() @@ -123,7 +123,7 @@ class DefaultJwtBuilderTest { } } - def b = new DefaultJwtBuilder().setSecureRandom(random) + def b = new DefaultJwtBuilder().random(random) .setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg) assertSame random, b.secureRandom b.compact() @@ -253,7 +253,7 @@ class DefaultJwtBuilderTest { @Test void testCompactWithJwsHeader() { def b = new DefaultJwtBuilder() - b.header().setKeyId('a') + b.header().keyId('a') b.setPayload('foo') def alg = SignatureAlgorithm.HS256 def key = Keys.secretKeyFor(alg) @@ -306,7 +306,7 @@ class DefaultJwtBuilderTest { void testSignWithKeyOnly() { def b = new DefaultJwtBuilder() - b.header().setKeyId('a') + b.header().keyId('a') b.setPayload('foo') def key = KeyGenerator.getInstance('HmacSHA256').generateKey() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy index eafecbe79..677717758 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy @@ -47,7 +47,11 @@ class DefaultJwtHeaderBuilderTest { @SuppressWarnings('GroovyAssignabilityCheck') private static void assertSymmetry(String propName, def val) { def name = Strings.capitalize(propName) - builder."set$name"(val) + switch (propName) { + case 'algorithm': builder.set('alg', val); break // no setter + case 'compressionAlgorithm': builder.set('zip', val); break // no setter + default: builder."$propName"(val) + } header = builder.build() if (val instanceof byte[]) { assertArrayEquals val, header."get$name"() @@ -277,7 +281,7 @@ class DefaultJwtHeaderBuilderTest { */ @Test void testJwk() { - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() assertJws('jwk', jwk) } @@ -332,7 +336,7 @@ class DefaultJwtHeaderBuilderTest { def x5t = DefaultHashAlgorithm.SHA1.digest(request) String encoded = Encoders.BASE64URL.encode(x5t) - builder.setX509CertificateSha1Thumbprint(x5t) + builder.x509CertificateSha1Thumbprint(x5t) header = builder.build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5t, header.getX509CertificateSha1Thumbprint() @@ -345,7 +349,7 @@ class DefaultJwtHeaderBuilderTest { Request request = new DefaultRequest(chain[0].getEncoded(), null, null) def x5t = DefaultHashAlgorithm.SHA1.digest(request) String encoded = Encoders.BASE64URL.encode(x5t) - def header = builder.setX509CertificateChain(chain).withX509Sha1Thumbprint(true).build() as JwsHeader + def header = builder.x509CertificateChain(chain).withX509Sha1Thumbprint(true).build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5t, header.getX509CertificateSha1Thumbprint() assertEquals encoded, header.get('x5t') @@ -361,7 +365,7 @@ class DefaultJwtHeaderBuilderTest { def x5tS256 = Jwks.HASH.@SHA256.digest(request) String encoded = Encoders.BASE64URL.encode(x5tS256) - builder.setX509CertificateSha256Thumbprint(x5tS256) + builder.x509CertificateSha256Thumbprint(x5tS256) header = builder.build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5tS256, header.getX509CertificateSha256Thumbprint() @@ -374,7 +378,7 @@ class DefaultJwtHeaderBuilderTest { Request request = new DefaultRequest(chain[0].getEncoded(), null, null) def x5tS256 = Jwks.HASH.SHA256.digest(request) String encoded = Encoders.BASE64URL.encode(x5tS256) - def header = builder.setX509CertificateChain(chain).withX509Sha256Thumbprint(true).build() as JwsHeader + def header = builder.x509CertificateChain(chain).withX509Sha256Thumbprint(true).build() as JwsHeader assertTrue header instanceof JwsHeader assertArrayEquals x5tS256, header.getX509CertificateSha256Thumbprint() assertEquals encoded, header.get('x5t#S256') @@ -393,7 +397,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testEphemeralPublicKey() { def key = TestKeys.ES256.pair.public - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() builder.put('epk', jwk) header = builder.build() as JweHeader assertEquals jwk, header.getEphemeralPublicKey() @@ -409,7 +413,7 @@ class DefaultJwtHeaderBuilderTest { void testAgreementPartyUInfoString() { def s = "UInfo" def info = Strings.utf8(s) - builder.setAgreementPartyUInfo(s).build() + builder.agreementPartyUInfo(s).build() header = builder.build() as JweHeader assertArrayEquals info, header.getAgreementPartyUInfo() } @@ -424,7 +428,7 @@ class DefaultJwtHeaderBuilderTest { void testAgreementPartyVInfoString() { def s = "VInfo" def info = Strings.utf8(s) - builder.setAgreementPartyVInfo(s) + builder.agreementPartyVInfo(s) header = builder.build() as JweHeader assertArrayEquals info, header.getAgreementPartyVInfo() } @@ -465,7 +469,7 @@ class DefaultJwtHeaderBuilderTest { assertEquals new DefaultHeader([foo: 'bar']), builder.build() // add JWS-required property: - builder.setAlgorithm('HS256') + builder.set(DefaultHeader.ALGORITHM.getId(), 'HS256') assertEquals new DefaultJwsHeader([foo: 'bar', alg: 'HS256']), builder.build() // add JWE required property: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index eb217265c..2cd07f6e7 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -53,7 +53,7 @@ class DefaultJwtParserBuilderTest { Provider provider = createMock(Provider) replay provider - def parser = builder.setProvider(provider).build() + def parser = builder.provider(provider).build() assertSame provider, parser.provider verify provider @@ -63,7 +63,7 @@ class DefaultJwtParserBuilderTest { void testKeyLocatorAndVerificationKeyConfigured() { try { builder - .setKeyLocator(new ConstantKeyLocator(null, null)) + .keyLocator(new ConstantKeyLocator(null, null)) .verifyWith(TestKeys.HS256) .build() fail() @@ -77,7 +77,7 @@ class DefaultJwtParserBuilderTest { void testKeyLocatorAndDecryptionKeyConfigured() { try { builder - .setKeyLocator(new ConstantKeyLocator(null, null)) + .keyLocator(new ConstantKeyLocator(null, null)) .decryptWith(TestKeys.A128GCM) .build() fail() @@ -161,7 +161,7 @@ class DefaultJwtParserBuilderTest { void testAddCompressionAlgorithms() { def codec = new TestCompressionCodec(id: 'test') def parser = builder.addCompressionAlgorithms([codec] as Set).build() - def header = Jwts.header().setCompressionAlgorithm(codec.getId()).build() + def header = Jwts.header().set('zip', codec.getId()).build() assertSame codec, parser.zipAlgFn.locate(header) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy index 69c06b638..49a374649 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy @@ -38,7 +38,7 @@ class DefaultJwtTest { void testByteArrayPayloadToString() { byte[] bytes = 'hello JJWT'.getBytes(StandardCharsets.UTF_8) String encoded = Encoders.BASE64URL.encode(bytes) - String compact = Jwts.builder().setHeaderParam('foo', 'bar').setContent(bytes).compact() + String compact = Jwts.builder().setHeaderParam('foo', 'bar').content(bytes).compact() Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) assertEquals "header={foo=bar, alg=none},payload=$encoded" as String, jwt.toString() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy index 9a74abf3b..8b9085dad 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy @@ -43,7 +43,11 @@ class DefaultMutableJweHeaderTest { @SuppressWarnings('GroovyAssignabilityCheck') private static void assertSymmetry(String propName, def val) { def name = Strings.capitalize(propName) - header."set$name"(val) + switch (propName) { + case 'algorithm': header.set('alg', val); break // no setter + case 'compressionAlgorithm': header.set('zip', val); break // no setter + default: header."$propName"(val) + } if (val instanceof byte[]) { assertArrayEquals val, header."get$name"() @@ -214,7 +218,7 @@ class DefaultMutableJweHeaderTest { */ @Test void testJwk() { - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() assertSymmetry('jwk', jwk) } @@ -269,7 +273,7 @@ class DefaultMutableJweHeaderTest { def x5t = DefaultHashAlgorithm.SHA1.digest(request) String encoded = Encoders.BASE64URL.encode(x5t) - header.setX509CertificateSha1Thumbprint(x5t) + header.x509CertificateSha1Thumbprint(x5t) assertArrayEquals x5t, header.getX509CertificateSha1Thumbprint() assertEquals encoded, header.get('x5t') } @@ -284,7 +288,7 @@ class DefaultMutableJweHeaderTest { def x5tS256 = Jwks.HASH.@SHA256.digest(request) String encoded = Encoders.BASE64URL.encode(x5tS256) - header.setX509CertificateSha256Thumbprint(x5tS256) + header.x509CertificateSha256Thumbprint(x5tS256) assertArrayEquals x5tS256, header.getX509CertificateSha256Thumbprint() assertEquals encoded, header.get('x5t#S256') } @@ -301,7 +305,7 @@ class DefaultMutableJweHeaderTest { @Test void testEphemeralPublicKey() { def key = TestKeys.ES256.pair.public - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() header.put('epk', jwk) assertEquals jwk, header.getEphemeralPublicKey() } @@ -316,7 +320,7 @@ class DefaultMutableJweHeaderTest { void testAgreementPartyUInfoString() { def s = "UInfo" def info = Strings.utf8(s) - header.setAgreementPartyVInfo(s) + header.agreementPartyVInfo(s) assertArrayEquals info, header.getAgreementPartyVInfo() } @@ -330,7 +334,7 @@ class DefaultMutableJweHeaderTest { void testAgreementPartyVInfoString() { def s = "VInfo" def info = Strings.utf8(s) - header.setAgreementPartyVInfo(s) + header.agreementPartyVInfo(s) assertArrayEquals info, header.getAgreementPartyVInfo() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy index d7acb07dd..63e8fb4ee 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy @@ -46,7 +46,7 @@ class IdLocatorTest { @Test void unrequiredHeaderValueTest() { locator = new IdLocator(TEST_FIELD, registry, Collections.emptyList(), null) - def header = Jwts.header().setAlgorithm('none').build() + def header = Jwts.header().set('a', 'b').build() assertNull locator.apply(header) } @@ -74,7 +74,7 @@ class IdLocatorTest { @Test void unlocatableJwsHeaderInstanceTest() { - def header = Jwts.header().setAlgorithm('HS256').set('foo', 'foo').build() + def header = Jwts.header().set('alg', 'HS256').set('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy index d24776a02..c3d3384ad 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractAsymmetricJwkBuilderTest.groovy @@ -34,19 +34,19 @@ class AbstractAsymmetricJwkBuilderTest { private static final RSAPublicKey PUB_KEY = CERT.getPublicKey() as RSAPublicKey private static RsaPublicJwkBuilder builder() { - return Jwks.builder().forKey(PUB_KEY) + return Jwks.builder().key(PUB_KEY) } @Test void testUse() { def val = UUID.randomUUID().toString() - def jwk = builder().setPublicKeyUse(val).build() + def jwk = builder().publicKeyUse(val).build() assertEquals val, jwk.getPublicKeyUse() assertEquals val, jwk.use RSAPrivateKey privateKey = TestKeys.RS256.pair.private as RSAPrivateKey - jwk = builder().setPublicKeyUse(val).setPrivateKey(privateKey).build() + jwk = builder().publicKeyUse(val).privateKey(privateKey).build() assertEquals val, jwk.getPublicKeyUse() assertEquals val, jwk.use } @@ -54,12 +54,12 @@ class AbstractAsymmetricJwkBuilderTest { @Test void testX509Url() { def val = new URI(UUID.randomUUID().toString()) - assertSame val, builder().setX509Url(val).build().getX509Url() + assertSame val, builder().x509Url(val).build().getX509Url() } @Test void testX509CertificateChain() { - assertEquals CHAIN, builder().setX509CertificateChain(CHAIN).build().getX509CertificateChain() + assertEquals CHAIN, builder().x509CertificateChain(CHAIN).build().getX509CertificateChain() } @Test @@ -67,7 +67,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5t = DefaultHashAlgorithm.SHA1.digest(request) def encoded = Encoders.BASE64URL.encode(x5t) - def jwk = builder().setX509CertificateSha1Thumbprint(x5t).build() + def jwk = builder().x509CertificateSha1Thumbprint(x5t).build() assertArrayEquals x5t, jwk.getX509CertificateSha1Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T.getId()) } @@ -77,7 +77,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5t = DefaultHashAlgorithm.SHA1.digest(request) def encoded = Encoders.BASE64URL.encode(x5t) - def jwk = builder().setX509CertificateChain(CHAIN).withX509Sha1Thumbprint(true).build() + def jwk = builder().x509CertificateChain(CHAIN).withX509Sha1Thumbprint(true).build() assertArrayEquals x5t, jwk.getX509CertificateSha1Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T.getId()) } @@ -87,7 +87,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5tS256 = Jwks.HASH.SHA256.digest(request) def encoded = Encoders.BASE64URL.encode(x5tS256) - def jwk = builder().setX509CertificateSha256Thumbprint(x5tS256).build() + def jwk = builder().x509CertificateSha256Thumbprint(x5tS256).build() assertArrayEquals x5tS256, jwk.getX509CertificateSha256Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T_S256.getId()) } @@ -97,7 +97,7 @@ class AbstractAsymmetricJwkBuilderTest { Request request = new DefaultRequest(TestKeys.RS256.cert.getEncoded(), null, null) def x5tS256 = Jwks.HASH.SHA256.digest(request) def encoded = Encoders.BASE64URL.encode(x5tS256) - def jwk = builder().setX509CertificateChain(CHAIN).withX509Sha256Thumbprint(true).build() + def jwk = builder().x509CertificateChain(CHAIN).withX509Sha256Thumbprint(true).build() assertArrayEquals x5tS256, jwk.getX509CertificateSha256Thumbprint() assertEquals encoded, jwk.get(AbstractAsymmetricJwk.X5T_S256.getId()) } @@ -107,11 +107,11 @@ class AbstractAsymmetricJwkBuilderTest { def pair = TestKeys.ES256.pair //start with a public key builder - def builder = Jwks.builder().forKey(pair.public as ECPublicKey) + def builder = Jwks.builder().key(pair.public as ECPublicKey) assertTrue builder instanceof AbstractAsymmetricJwkBuilder.DefaultEcPublicJwkBuilder //applying the private key turns it into a private key builder - builder = builder.setPrivateKey(pair.private as ECPrivateKey) + builder = builder.privateKey(pair.private as ECPrivateKey) assertTrue builder instanceof AbstractAsymmetricJwkBuilder.DefaultEcPrivateJwkBuilder //building creates a private jwk: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy index 5696949d2..ab7dcfcf8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy @@ -32,7 +32,7 @@ class AbstractJwkBuilderTest { private static final SecretKey SKEY = TestKeys.A256GCM private static AbstractJwkBuilder builder() { - return (AbstractJwkBuilder) Jwks.builder().forKey(SKEY) + return (AbstractJwkBuilder) Jwks.builder().key(SKEY) } @Test @@ -83,7 +83,7 @@ class AbstractJwkBuilderTest { @Test void testAlgorithm() { def alg = 'someAlgorithm' - def jwk = builder().setAlgorithm(alg).build() + def jwk = builder().algorithm(alg).build() assertEquals alg, jwk.getAlgorithm() assertEquals alg, jwk.alg //test raw get via JWA member id } @@ -99,7 +99,7 @@ class AbstractJwkBuilderTest { @Test void testId() { def kid = UUID.randomUUID().toString() - def jwk = builder().setId(kid).build() + def jwk = builder().id(kid).build() assertEquals kid, jwk.getId() assertEquals kid, jwk.kid //test raw get via JWA member id } @@ -117,7 +117,7 @@ class AbstractJwkBuilderTest { def a = UUID.randomUUID().toString() def b = UUID.randomUUID().toString() def set = [a, b] as Set - def jwk = builder().setOperations(set).build() + def jwk = builder().operations(set).build() assertEquals set, jwk.getOperations() assertEquals set, jwk.key_ops } @@ -145,7 +145,7 @@ class AbstractJwkBuilderTest { @Test void testProvider() { def provider = Providers.findBouncyCastle(Conditions.TRUE) - def jwk = builder().setProvider(provider).build() + def jwk = builder().provider(provider).build() assertEquals 'oct', jwk.getType() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy index 126609930..760ccb600 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy @@ -131,13 +131,13 @@ class AbstractJwkTest { @Test void testPrivateJwkToStringHasRedactedValues() { - def secretJwk = Jwks.builder().forKey(TestKeys.HS256).build() + def secretJwk = Jwks.builder().key(TestKeys.HS256).build() assertTrue secretJwk.toString().contains('k=') - def ecPrivJwk = Jwks.builder().forKey(TestKeys.ES256.pair.private).build() + def ecPrivJwk = Jwks.builder().key(TestKeys.ES256.pair.private).build() assertTrue ecPrivJwk.toString().contains('d=') - def rsaPrivJwk = Jwks.builder().forKey(TestKeys.RS256.pair.private).build() + def rsaPrivJwk = Jwks.builder().key(TestKeys.RS256.pair.private).build() String s = 'd=, p=, q=, dp=, dq=, qi=' assertTrue rsaPrivJwk.toString().contains(s) } @@ -146,20 +146,20 @@ class AbstractJwkTest { void testPrivateJwkHashCode() { assertEquals jwk.hashCode(), jwk.@context.hashCode() - def secretJwk1 = Jwks.builder().forKey(TestKeys.HS256).set('hello', 'world').build() - def secretJwk2 = Jwks.builder().forKey(TestKeys.HS256).set('hello', 'world').build() + def secretJwk1 = Jwks.builder().key(TestKeys.HS256).set('hello', 'world').build() + def secretJwk2 = Jwks.builder().key(TestKeys.HS256).set('hello', 'world').build() assertEquals secretJwk1.hashCode(), secretJwk1.@context.hashCode() assertEquals secretJwk2.hashCode(), secretJwk2.@context.hashCode() assertEquals secretJwk1.hashCode(), secretJwk2.hashCode() - def ecPrivJwk1 = Jwks.builder().forKey(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() - def ecPrivJwk2 = Jwks.builder().forKey(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() + def ecPrivJwk1 = Jwks.builder().key(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() + def ecPrivJwk2 = Jwks.builder().key(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() assertEquals ecPrivJwk1.hashCode(), ecPrivJwk2.hashCode() assertEquals ecPrivJwk1.hashCode(), ecPrivJwk1.@context.hashCode() assertEquals ecPrivJwk2.hashCode(), ecPrivJwk2.@context.hashCode() - def rsaPrivJwk1 = Jwks.builder().forKey(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() - def rsaPrivJwk2 = Jwks.builder().forKey(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() + def rsaPrivJwk1 = Jwks.builder().key(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() + def rsaPrivJwk2 = Jwks.builder().key(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() assertEquals rsaPrivJwk1.hashCode(), rsaPrivJwk2.hashCode() assertEquals rsaPrivJwk1.hashCode(), rsaPrivJwk1.@context.hashCode() assertEquals rsaPrivJwk2.hashCode(), rsaPrivJwk2.@context.hashCode() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy index 6f62aaa76..f77993071 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkContextTest.groovy @@ -28,7 +28,7 @@ class DefaultJwkContextTest { void testX509Url() { def uri = URI.create('https://github.com/jwtk/jjwt') def ctx = new DefaultJwkContext() - ctx.setX509Url(uri) + ctx.x509Url(uri) assertEquals uri, ctx.getX509Url() assertEquals uri.toString(), ctx.get('x5u') } @@ -37,7 +37,7 @@ class DefaultJwkContextTest { void testX509CertificateChain() { def chain = TestKeys.RS256.chain def ctx = new DefaultJwkContext() - ctx.setX509CertificateChain(chain) + ctx.x509CertificateChain(chain) assertEquals chain, ctx.getX509CertificateChain() } @@ -45,7 +45,7 @@ class DefaultJwkContextTest { void testX509CertificateSha1Thumbprint() { def thumbprint = Bytes.randomBits(128) def ctx = new DefaultJwkContext() - ctx.setX509CertificateSha1Thumbprint(thumbprint) + ctx.x509CertificateSha1Thumbprint(thumbprint) assertArrayEquals thumbprint, ctx.getX509CertificateSha1Thumbprint() assertEquals Encoders.BASE64URL.encode(thumbprint), ctx.get('x5t') } @@ -54,7 +54,7 @@ class DefaultJwkContextTest { void testX509CertificateSha256Thumbprint() { def thumbprint = Bytes.randomBits(256) def ctx = new DefaultJwkContext() - ctx.setX509CertificateSha256Thumbprint(thumbprint) + ctx.x509CertificateSha256Thumbprint(thumbprint) assertArrayEquals thumbprint, ctx.getX509CertificateSha256Thumbprint() assertEquals Encoders.BASE64URL.encode(thumbprint), ctx.get('x5t#S256') } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy index 5608ed15c..195f5f512 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserBuilderTest.groovy @@ -40,7 +40,7 @@ class DefaultJwkParserBuilderTest { @Test void testProvider() { def provider = createMock(Provider) - def parser = Jwks.parser().setProvider(provider).build() as DefaultJwkParser + def parser = Jwks.parser().provider(provider).build() as DefaultJwkParser assertSame provider, parser.provider } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy index 43355c5d1..5543528ef 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy @@ -48,7 +48,7 @@ class DefaultJwkParserTest { def serializer = Services.loadFirst(Serializer) for (Key key : keys) { //noinspection GroovyAssignabilityCheck - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() def data = serializer.serialize(jwk) String json = new String(data, StandardCharsets.UTF_8) def parsed = Jwks.parser().build().parse(json) @@ -75,10 +75,10 @@ class DefaultJwkParserTest { for (Key key : keys) { //noinspection GroovyAssignabilityCheck - def jwk = Jwks.builder().forKey(key).build() + def jwk = Jwks.builder().key(key).build() def data = serializer.serialize(jwk) String json = new String(data, StandardCharsets.UTF_8) - def parsed = Jwks.parser().setProvider(provider).build().parse(json) + def parsed = Jwks.parser().provider(provider).build().parse(json) assertEquals jwk, parsed assertSame provider, parsed.@context.@provider } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy index dbd608266..7ba665c4d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy @@ -101,7 +101,7 @@ class EcdhKeyAlgorithmTest { ECPrivateKey decryptionKey = TestKeys.ES256.pair.private as ECPrivateKey // Expected curve for this is P-256 // This uses curve P-384 instead, does not match private key, so it's unexpected: - def jwk = Jwks.builder().forKey(TestKeys.ES384.pair.public as ECPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.ES384.pair.public as ECPublicKey).build() JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader DecryptionKeyRequest req = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, decryptionKey) @@ -136,7 +136,7 @@ class EcdhKeyAlgorithmTest { void testDecryptionWithInvalidPrivateKey() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.RS256.pair.private as PrivateKey // not an elliptic curve key, must fail - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { @@ -169,7 +169,7 @@ class EcdhKeyAlgorithmTest { void testECDecryptionWithNonECEpk() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.ES256.pair.private as PrivateKey // valid key - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { @@ -189,7 +189,7 @@ class EcdhKeyAlgorithmTest { void testEdwardsDecryptionWithNonEdwardsEpk() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.X25519.pair.private as PrivateKey // valid key - def jwk = Jwks.builder().forKey(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk + def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { @@ -209,7 +209,7 @@ class EcdhKeyAlgorithmTest { void testEdwardsDecryptionWithEpkOnDifferentCurve() { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.X25519.pair.private as PrivateKey // valid key - def jwk = Jwks.builder().forKey(TestKeys.X448.pair.public as PublicKey).build() // epk is not on X25519 + def jwk = Jwks.builder().key(TestKeys.X448.pair.public as PublicKey).build() // epk is not on X25519 JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy index 343b97f6a..250664182 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/FixedSecretKeyBuilder.groovy @@ -35,12 +35,12 @@ class FixedSecretKeyBuilder implements SecretKeyBuilder { } @Override - SecretKeyBuilder setProvider(Provider provider) { + SecretKeyBuilder provider(Provider provider) { return this } @Override - SecretKeyBuilder setRandom(SecureRandom random) { + SecretKeyBuilder random(SecureRandom random) { return this } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy index 70566cda9..2c8be5ea9 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HashAlgorithmsTest.groovy @@ -54,7 +54,7 @@ class HashAlgorithmsTest { @Test(expected = IllegalArgumentException) void testForKeyWithInvalidId() { - //unlike the 'get' paradigm, 'forKey' requires the value to exist + //unlike the 'get' paradigm, 'key' requires the value to exist reg.forKey('invalid') } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy index b542111e7..181614a48 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkConverterTest.groovy @@ -39,7 +39,7 @@ class JwkConverterTest { @Test void testSecretJwkTypeString() { - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() assertEquals 'Secret JWK', typeString(jwk) } @@ -86,7 +86,7 @@ class JwkConverterTest { @Test void testPrivateJwk() { JwkConverter converter = new JwkConverter<>(PrivateJwk.class) - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() try { converter.applyFrom(jwk) fail() @@ -99,7 +99,7 @@ class JwkConverterTest { @Test void testRsaPrivateJwk() { JwkConverter converter = new JwkConverter<>(RsaPublicJwk.class) - def jwk = Jwks.builder().forKey(TestKeys.HS256).build() + def jwk = Jwks.builder().key(TestKeys.HS256).build() try { converter.applyFrom(jwk) fail() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy index 9904b870f..07a7112f5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy @@ -88,7 +88,7 @@ class JwkSerializationTest { static void testSecretJwk(Serializer serializer, Deserializer deserializer) { def key = TestKeys.A128GCM - def jwk = Jwks.builder().forKey(key).setId('id').build() + def jwk = Jwks.builder().key(key).id('id').build() assertWrapped(jwk, ['k']) // Ensure no Groovy or Java toString prints out secret values: @@ -114,7 +114,7 @@ class JwkSerializationTest { static void testPrivateEcJwk(Serializer serializer, Deserializer deserializer) { - def jwk = Jwks.builder().forEcKeyPair(TestKeys.ES256.pair).setId('id').build() + def jwk = Jwks.builder().ecKeyPair(TestKeys.ES256.pair).id('id').build() assertWrapped(jwk, ['d']) // Ensure no Groovy or Java toString prints out secret values: @@ -164,7 +164,7 @@ class JwkSerializationTest { static void testPrivateRsaJwk(Serializer serializer, Deserializer deserializer) { - def jwk = Jwks.builder().forRsaKeyPair(TestKeys.RS256.pair).setId('id').build() + def jwk = Jwks.builder().rsaKeyPair(TestKeys.RS256.pair).id('id').build() def privateFieldNames = ['d', 'p', 'q', 'dp', 'dq', 'qi'] assertWrapped(jwk, privateFieldNames) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy index d272351df..775c311b5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkThumbprintsTest.groovy @@ -44,7 +44,7 @@ class JwkThumbprintsTest { @Test void testSecretJwks() { TestKeys.SECRET.each { SecretKey key -> - def jwk = Jwks.builder().forKey((SecretKey) key).setIdFromThumbprint().build() + def jwk = Jwks.builder().key((SecretKey) key).idFromThumbprint().build() def json = RfcTests.stripws(""" {"k":"${jwk.get('k').get()}","kty":"oct"} """) @@ -58,7 +58,7 @@ class JwkThumbprintsTest { @Test void testRsaKeyPair() { def pair = TestKeys.RS256.pair - def privJwk = Jwks.builder().forRsaKeyPair(pair).setIdFromThumbprint().build() + def privJwk = Jwks.builder().rsaKeyPair(pair).idFromThumbprint().build() def pubJwk = privJwk.toPublicJwk() def json = RfcTests.stripws(""" {"e":"${pubJwk.get('e')}","kty":"RSA","n":"${pubJwk.get('n')}"} @@ -80,7 +80,7 @@ class JwkThumbprintsTest { @Test void testEcKeyPair() { def pair = TestKeys.ES256.pair - def privJwk = Jwks.builder().forEcKeyPair(pair).setIdFromThumbprint().build() + def privJwk = Jwks.builder().ecKeyPair(pair).idFromThumbprint().build() def pubJwk = privJwk.toPublicJwk() def json = RfcTests.stripws(""" {"crv":"${pubJwk.get('crv')}","kty":"EC","x":"${pubJwk.get('x')}","y":"${pubJwk.get('y')}"} @@ -102,7 +102,7 @@ class JwkThumbprintsTest { @Test void testEdECKeyPair() { def pair = TestKeys.Ed25519.pair - def privJwk = Jwks.builder().forOctetKeyPair(pair).setIdFromThumbprint().build() + def privJwk = Jwks.builder().octetKeyPair(pair).idFromThumbprint().build() def pubJwk = privJwk.toPublicJwk() def json = RfcTests.stripws(""" {"crv":"${pubJwk.get('crv')}","kty":"OKP","x":"${pubJwk.get('x')}"} diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index 412bd1e19..be9fa5f6e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -53,16 +53,16 @@ class JwksTest { //test non-null value: //noinspection GroovyAssignabilityCheck - def builder = Jwks.builder().forKey(key) - builder."set${cap}"(val) + def builder = Jwks.builder().key(key) + builder."$name"(val) def jwk = builder.build() assertEquals val, jwk."get${cap}"() assertEquals expectedFieldValue, jwk."${id}" //test null value: - builder = Jwks.builder().forKey(key) + builder = Jwks.builder().key(key) try { - builder."set${cap}"(null) + builder."$name"(null) fail("IAE should have been thrown") } catch (IllegalArgumentException ignored) { } @@ -72,10 +72,10 @@ class JwksTest { assertFalse jwk.containsKey(id) //test empty string value - builder = Jwks.builder().forKey(key) + builder = Jwks.builder().key(key) if (val instanceof String) { try { - builder."set${cap}"(' ' as String) + builder."$name"(' ' as String) fail("IAE should have been thrown") } catch (IllegalArgumentException ignored) { } @@ -93,7 +93,7 @@ class JwksTest { } if (val instanceof Collection) { try { - builder."set${cap}"(val) + builder."$name"(val) fail("IAE should have been thrown") } catch (IllegalArgumentException ignored) { } @@ -122,7 +122,7 @@ class JwksTest { @Test void testBuilderWithSecretKey() { - def jwk = Jwks.builder().forKey(SKEY).build() + def jwk = Jwks.builder().key(SKEY).build() assertEquals 'oct', jwk.getType() assertEquals 'oct', jwk.kty String k = jwk.k.get() as String @@ -171,13 +171,13 @@ class JwksTest { @Test void testRandom() { def random = new SecureRandom() - def jwk = Jwks.builder().forKey(SKEY).setRandom(random).build() + def jwk = Jwks.builder().key(SKEY).random(random).build() assertSame random, jwk.@context.getRandom() } @Test void testNullRandom() { - assertNotNull Jwks.builder().forKey(SKEY).setRandom(null).build() + assertNotNull Jwks.builder().key(SKEY).random(null).build() } static void testX509Thumbprint(int number) { @@ -190,11 +190,11 @@ class JwksTest { def builder = Jwks.builder() if (pubKey instanceof ECKey) { - builder = builder.forEcChain(cert) + builder = builder.ecChain(cert) } else if (pubKey instanceof RSAKey) { - builder = builder.forRsaChain(cert) + builder = builder.rsaChain(cert) } else { - builder = builder.forOctetChain(cert) + builder = builder.octetChain(cert) } if (number == 1) { @@ -216,7 +216,7 @@ class JwksTest { Collection algs = Jwts.SIG.get().values().findAll({ it instanceof MacAlgorithm }) as Collection for (def alg : algs) { SecretKey secretKey = alg.keyBuilder().build() - def jwk = Jwks.builder().forKey(secretKey).setId('id').build() + def jwk = Jwks.builder().key(secretKey).id('id').build() assertEquals 'oct', jwk.getType() assertTrue jwk.containsKey('k') assertEquals 'id', jwk.getId() @@ -228,7 +228,7 @@ class JwksTest { void testSecretKeyGetEncodedReturnsNull() { SecretKey key = new TestSecretKey(algorithm: "AES") try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String expectedMsg = 'Unable to encode SecretKey to JWK: ' + SecretJwkFactory.ENCODED_UNAVAILABLE_MSG @@ -249,7 +249,7 @@ class JwksTest { } } try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String expectedMsg = 'Unable to encode SecretKey to JWK: ' + SecretJwkFactory.ENCODED_UNAVAILABLE_MSG @@ -272,13 +272,13 @@ class JwksTest { PrivateKey priv = pair.getPrivate() // test individual keys - PublicJwk pubJwk = Jwks.builder().forKey(pub).setPublicKeyUse("sig").build() + PublicJwk pubJwk = Jwks.builder().key(pub).publicKeyUse("sig").build() assertEquals pub, pubJwk.toKey() - def builder = Jwks.builder().forKey(priv).setPublicKeyUse('sig') + def builder = Jwks.builder().key(priv).publicKeyUse('sig') if (alg instanceof EdSignatureAlgorithm) { // We haven't implemented EdDSA public-key derivation yet, so public key is required - builder.setPublicKey(pub) + builder.publicKey(pub) } PrivateJwk privJwk = builder.build() assertEquals priv, privJwk.toKey() @@ -291,13 +291,13 @@ class JwksTest { // test pair if (pub instanceof ECKey) { - builder = Jwks.builder().forEcKeyPair(pair) + builder = Jwks.builder().ecKeyPair(pair) } else if (pub instanceof RSAKey) { - builder = Jwks.builder().forRsaKeyPair(pair) + builder = Jwks.builder().rsaKeyPair(pair) } else { - builder = Jwks.builder().forOctetKeyPair(pair) + builder = Jwks.builder().octetKeyPair(pair) } - privJwk = builder.setPublicKeyUse("sig").build() as PrivateJwk + privJwk = builder.publicKeyUse("sig").build() as PrivateJwk assertEquals priv, privJwk.toKey() privPubJwk = privJwk.toPublicJwk() assertEquals pubJwk, privPubJwk @@ -317,12 +317,12 @@ class JwksTest { def pair = alg.keyPairBuilder().build() ECPublicKey pubKey = pair.getPublic() as ECPublicKey - EcPublicJwk jwk = Jwks.builder().forKey(pubKey).build() + EcPublicJwk jwk = Jwks.builder().key(pubKey).build() //try creating a JWK with a bad point: def badPubKey = new InvalidECPublicKey(pubKey) try { - Jwks.builder().forKey(badPubKey).build() + Jwks.builder().key(badPubKey).build() } catch (InvalidKeyException ike) { String curveId = jwk.get('crv') String msg = EcPublicJwkFactory.keyContainsErrorMessage(curveId) @@ -357,8 +357,8 @@ class JwksTest { @Test void testPublicJwkBuilderWithRSAPublicKey() { def key = TestKeys.RS256.pair.public - // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the forKey(RSAPublicKey) method: - def jwk = Jwks.builder().forKey((PublicKey) key).build() + // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the key(RSAPublicKey) method: + def jwk = Jwks.builder().key((PublicKey) key).build() assertNotNull jwk assertTrue jwk instanceof RsaPublicJwk } @@ -366,8 +366,8 @@ class JwksTest { @Test void testPublicJwkBuilderWithECPublicKey() { def key = TestKeys.ES256.pair.public - // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the forKey(ECPublicKey) method: - def jwk = Jwks.builder().forKey((PublicKey) key).build() + // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the key(ECPublicKey) method: + def jwk = Jwks.builder().key((PublicKey) key).build() assertNotNull jwk assertTrue jwk instanceof EcPublicJwk } @@ -375,9 +375,9 @@ class JwksTest { @Test void testPublicJwkBuilderWithUnsupportedKey() { def key = new TestPublicKey() - // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the forKey(ECPublicKey) method: + // must cast to PublicKey to avoid Groovy's dynamic type dispatch to the key(ECPublicKey) method: try { - Jwks.builder().forKey((PublicKey) key) + Jwks.builder().key((PublicKey) key) } catch (UnsupportedKeyException expected) { String msg = 'There is no builder that supports specified key of type io.jsonwebtoken.impl.security.TestPublicKey with algorithm \'null\'.' assertEquals(msg, expected.getMessage()) @@ -388,8 +388,8 @@ class JwksTest { @Test void testPrivateJwkBuilderWithRSAPrivateKey() { def key = TestKeys.RS256.pair.private - // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the forKey(RSAPrivateKey) method: - def jwk = Jwks.builder().forKey((PrivateKey) key).build() + // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the key(RSAPrivateKey) method: + def jwk = Jwks.builder().key((PrivateKey) key).build() assertNotNull jwk assertTrue jwk instanceof RsaPrivateJwk } @@ -397,8 +397,8 @@ class JwksTest { @Test void testPrivateJwkBuilderWithECPrivateKey() { def key = TestKeys.ES256.pair.private - // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the forKey(ECPrivateKey) method: - def jwk = Jwks.builder().forKey((PrivateKey) key).build() + // must cast to PrivateKey to avoid Groovy's dynamic type dispatch to the key(ECPrivateKey) method: + def jwk = Jwks.builder().key((PrivateKey) key).build() assertNotNull jwk assertTrue jwk instanceof EcPrivateJwk } @@ -407,7 +407,7 @@ class JwksTest { void testPrivateJwkBuilderWithUnsupportedKey() { def key = new TestPrivateKey() try { - Jwks.builder().forKey((PrivateKey) key) + Jwks.builder().key((PrivateKey) key) } catch (UnsupportedKeyException expected) { String msg = 'There is no builder that supports specified key of type io.jsonwebtoken.impl.security.TestPrivateKey with algorithm \'null\'.' assertEquals(msg, expected.getMessage()) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy index ac57b00f4..f07d4214e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy @@ -125,13 +125,13 @@ class OctetJwksTest { PrivateKey priv = pair.getPrivate() // test individual keys - PublicJwk pubJwk = Jwks.builder().forOctetKey(pub).setPublicKeyUse("sig").build() + PublicJwk pubJwk = Jwks.builder().octetKey(pub).publicKeyUse("sig").build() PublicJwk pubValuesJwk = Jwks.builder().set(pubJwk).build() as PublicJwk // ensure value map symmetry assertEquals pubJwk, pubValuesJwk assertEquals pub, pubJwk.toKey() assertEquals pub, pubValuesJwk.toKey() - PrivateJwk privJwk = Jwks.builder().forOctetKey(priv).setPublicKey(pub).setPublicKeyUse("sig").build() + PrivateJwk privJwk = Jwks.builder().octetKey(priv).publicKey(pub).publicKeyUse("sig").build() PrivateJwk privValuesJwk = Jwks.builder().set(privJwk).build() as PrivateJwk // ensure value map symmetry assertEquals privJwk, privValuesJwk assertEquals priv, privJwk.toKey() @@ -159,7 +159,7 @@ class OctetJwksTest { assertArrayEquals privMaterial, jwkKeyMaterial // Test public-to-private builder coercion: - privJwk = Jwks.builder().forOctetKey(pub).setPrivateKey(priv).setPublicKeyUse('sig').build() + privJwk = Jwks.builder().octetKey(pub).privateKey(priv).publicKeyUse('sig').build() privValuesJwk = Jwks.builder().set(privJwk).build() as PrivateJwk // ensure value map symmetry assertEquals privJwk, privValuesJwk assertEquals priv, privJwk.toKey() @@ -176,7 +176,7 @@ class OctetJwksTest { assertEquals pub, pubValuesJwk.toKey() // test pair - privJwk = Jwks.builder().forOctetKeyPair(pair).setPublicKeyUse("sig").build() + privJwk = Jwks.builder().octetKeyPair(pair).publicKeyUse("sig").build() assertEquals priv, privJwk.toKey() // see comments above about material equality instead of encoding equality privMaterial = curve.getKeyMaterial(priv) @@ -217,7 +217,7 @@ class OctetJwksTest { def priv = TestKeys.X448.pair.private def mismatchedPub = TestKeys.X25519.pair.public try { - Jwks.builder().forOctetKey(priv).setPublicKey(mismatchedPub).build() + Jwks.builder().octetKey(priv).publicKey(mismatchedPub).build() fail() } catch (InvalidKeyException ike) { String msg = "Specified Edwards Curve PublicKey does not match the specified PrivateKey's curve." diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy index af445438d..b69c7dbdc 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy @@ -38,7 +38,7 @@ class Pbes2HsAkwAlgorithmTest { void testInsufficientIterations() { for (Pbes2HsAkwAlgorithm alg : ALGS) { int iterations = 50 // must be 1000 or more - def header = Jwts.header().setPbes2Count(iterations) as DefaultJweHeaderMutator + def header = Jwts.header().pbes2Count(iterations) as DefaultJweHeaderMutator def mutable = new DefaultMutableJweHeader(header) KeyRequest req = new DefaultKeyRequest<>(KEY, null, null, mutable, Jwts.ENC.A256GCM) try { @@ -66,7 +66,7 @@ class Pbes2HsAkwAlgorithmTest { //double scale = 0.5035246727 def password = 'hellowor'.toCharArray() - def header = new DefaultJweHeader().setPbes2Count(iterations) + def header = new DefaultJweHeader().pbes2Count(iterations) def key = Keys.forPassword(password) def req = new DefaultKeyRequest(null, null, key, header, Jwts.ENC.A128GCM) int sum = 0 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 b5303a34b..bee9f8dab 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy @@ -323,7 +323,7 @@ class RFC7517AppendixCTest { String compact = Jwts.builder() .setPayload(RFC_JWK_JSON) - .header().setContentType('jwk+json').setPbes2Count(RFC_P2C).and() + .header().contentType('jwk+json').pbes2Count(RFC_P2C).and() .encryptWith(key, alg, enc) .serializeToJsonWith(serializer) //ensure header created as expected with an assertion serializer .compact() 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 9880e3f7d..b4c3b78a8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy @@ -112,7 +112,7 @@ class RFC7518AppendixCTest { } String jwe = Jwts.builder() - .header().setAgreementPartyUInfo("Alice").setAgreementPartyVInfo("Bob").and() + .header().agreementPartyUInfo("Alice").agreementPartyVInfo("Bob").and() .claim("Hello", "World") .encryptWith(bobJwk.toPublicJwk().toKey(), alg, Jwts.ENC.A128GCM) .compact() 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 aa827f95d..953f65525 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy @@ -219,7 +219,7 @@ class RFC7520Section4Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .header().setKeyId(jwk.getId()).and() + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() 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 89d2d2a11..848736923 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy @@ -598,7 +598,7 @@ class RFC7520Section5Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .header().setContentType(cty).setPbes2Count(p2c).and() + .header().contentType(cty).pbes2Count(p2c).and() .setPayload(FIGURE_95) .encryptWith(key, alg, enc) .compact() 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 7e6f99da1..821d446a0 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy @@ -73,7 +73,7 @@ class RFC8037AppendixATest { PrivateKey privKey = privJwk.toKey() as PrivateKey PublicKey pubKey = privJwk.toPublicJwk().toKey() as PublicKey - def builtPrivJwk = Jwks.builder().forKey(privKey).setPublicKey(pubKey).build() + def builtPrivJwk = Jwks.builder().key(privKey).publicKey(pubKey).build() //output should equal RFC input: assertEquals privJwk, builtPrivJwk @@ -102,7 +102,7 @@ class RFC8037AppendixATest { void test_Sections_A4_and_A5() { def privJwk = a1Jwk() String compact = Jwts.builder() - .setContent(A4_JWS_PAYLOAD.getBytes(StandardCharsets.UTF_8)) + .content(A4_JWS_PAYLOAD.getBytes(StandardCharsets.UTF_8)) .signWith(privJwk.toKey() as PrivateKey, Jwts.SIG.EdDSA) .compact() assertEquals A4_JWS_COMPACT, compact diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy index f5a8bca96..97389bdd1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy @@ -44,7 +44,7 @@ class RsaPrivateJwkFactoryTest { } try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String msg = 'Unable to derive RSAPublicKey from RSAPrivateKey implementation ' + @@ -119,7 +119,7 @@ class RsaPrivateJwkFactoryTest { } as RSAPrivateKey try { - Jwks.builder().forKey(key).build() + Jwks.builder().key(key).build() fail() } catch (UnsupportedKeyException expected) { String prefix = 'Unable to derive RSAPublicKey from RSAPrivateKey {kty=RSA}. Cause: ' @@ -139,7 +139,7 @@ class RsaPrivateJwkFactoryTest { //build up test key: RSAMultiPrimePrivateCrtKey key = new TestRSAMultiPrimePrivateCrtKey(priv, infos) - RsaPrivateJwk jwk = Jwks.builder().forKey(key).build() + RsaPrivateJwk jwk = Jwks.builder().key(key).build() List oth = jwk.get('oth') as List assertTrue oth instanceof List @@ -162,11 +162,11 @@ class RsaPrivateJwkFactoryTest { RSAPrivateCrtKey priv = pair.private as RSAPrivateCrtKey RSAPublicKey pub = pair.public as RSAPublicKey - RsaPrivateJwk jwk = Jwks.builder().forKey(priv).setPublicKey(pub).build() + RsaPrivateJwk jwk = Jwks.builder().key(priv).publicKey(pub).build() // an RSAMultiPrimePrivateCrtKey without OtherInfo elements is treated the same as a normal RSAPrivateCrtKey, // so ensure they are equal: RSAMultiPrimePrivateCrtKey key = new TestRSAMultiPrimePrivateCrtKey(priv, null) - RsaPrivateJwk jwk2 = Jwks.builder().forKey(key).setPublicKey(pub).build() + RsaPrivateJwk jwk2 = Jwks.builder().key(key).publicKey(pub).build() assertEquals jwk, jwk2 assertNull jwk.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId()) assertNull jwk2.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId()) @@ -181,7 +181,7 @@ class RsaPrivateJwkFactoryTest { def priv = new TestRSAPrivateKey(privCrtKey) - RsaPrivateJwk jwk = Jwks.builder().forKey(priv).setPublicKey(pub).build() + RsaPrivateJwk jwk = Jwks.builder().key(priv).publicKey(pub).build() assertEquals 4, jwk.size() // kty, public exponent, modulus, private exponent assertEquals 'RSA', jwk.getType() assertEquals Converters.BIGINT.applyTo(pub.getModulus()), jwk.get(DefaultRsaPublicJwk.MODULUS.getId()) @@ -194,7 +194,7 @@ class RsaPrivateJwkFactoryTest { def pair = TestKeys.RS256.pair RSAPublicKey pub = pair.public as RSAPublicKey RSAPrivateKey priv = new TestRSAPrivateKey(pair.private as RSAPrivateKey) - def jwk = Jwks.builder().forKey(priv).setPublicKey(pub).build() + def jwk = Jwks.builder().key(priv).publicKey(pub).build() //minimal values: kty, modulus, public exponent, private exponent = 4 fields: assertEquals 4, jwk.size() def map = new LinkedHashMap(jwk) @@ -217,7 +217,7 @@ class RsaPrivateJwkFactoryTest { def infos = [info1, info2] RSAMultiPrimePrivateCrtKey key = new TestRSAMultiPrimePrivateCrtKey(priv, infos) - final RsaPrivateJwk jwk = Jwks.builder().forKey(key).setPublicKey(pub).build() + final RsaPrivateJwk jwk = Jwks.builder().key(key).publicKey(pub).build() //we have to test the class directly and override, since the dummy MultiPrime values won't be accepted by the //JVM: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy index b2cd99e08..1a1379f1d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy @@ -32,22 +32,22 @@ class SecretJwkFactoryTest { @Test // if a jwk does not have an 'alg' or 'use' field, we default to an AES key void testNoAlgNoSigJcaName() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() SecretJwk result = Jwks.builder().set(jwk).build() as SecretJwk assertEquals 'AES', result.toKey().getAlgorithm() } @Test void testJwkHS256AlgSetsKeyJcaNameCorrectly() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS256').build() as SecretJwk assertEquals 'HmacSHA256', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA256() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).setOperations(["sign"] as Set).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() + SecretJwk result = Jwks.builder().set(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA256', result.toKey().getAlgorithm() @@ -55,15 +55,15 @@ class SecretJwkFactoryTest { @Test void testJwkHS384AlgSetsKeyJcaNameCorrectly() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS384).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS384').build() as SecretJwk assertEquals 'HmacSHA384', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA384() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS384).build() - SecretJwk result = Jwks.builder().set(jwk).setOperations(["sign"] as Set).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() + SecretJwk result = Jwks.builder().set(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA384', result.toKey().getAlgorithm() @@ -71,15 +71,15 @@ class SecretJwkFactoryTest { @Test void testJwkHS512AlgSetsKeyJcaNameCorrectly() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS512).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS512').build() as SecretJwk assertEquals 'HmacSHA512', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA512() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS512).build() - SecretJwk result = Jwks.builder().set(jwk).setOperations(["sign"] as Set).build() as SecretJwk + SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() + SecretJwk result = Jwks.builder().set(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA512', result.toKey().getAlgorithm() @@ -87,7 +87,7 @@ class SecretJwkFactoryTest { @Test // no 'alg' jwk property, but 'use' is 'sig', so forces jcaName to be HmacSHA256 void testNoAlgAndSigUseForHS256() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk @@ -96,7 +96,7 @@ class SecretJwkFactoryTest { @Test // no 'alg' jwk property, but 'use' is 'sig', so forces jcaName to be HmacSHA384 void testNoAlgAndSigUseForHS384() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS384).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk @@ -105,7 +105,7 @@ class SecretJwkFactoryTest { @Test // no 'alg' jwk property, but 'use' is 'sig', so forces jcaName to be HmacSHA512 void testNoAlgAndSigUseForHS512() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS512).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk @@ -114,7 +114,7 @@ class SecretJwkFactoryTest { @Test // no 'alg' jwk property, but 'use' is something other than 'sig', so jcaName should default to AES void testNoAlgAndNonSigUse() { - SecretJwk jwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') SecretJwk result = Jwks.builder().set(jwk).set('use', 'foo').build() as SecretJwk @@ -129,7 +129,7 @@ class SecretJwkFactoryTest { void testSizeMismatchedSecretJwk() { //first get a valid HS256 JWK: - SecretJwk validJwk = Jwks.builder().forKey(TestKeys.HS256).build() + SecretJwk validJwk = Jwks.builder().key(TestKeys.HS256).build() //now associate it with an alg identifier that is more than the key is capable of: try { diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy index 6b1301a9a..cd87dcbae 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy @@ -86,7 +86,7 @@ class EncryptionAlgorithmsTest { @Test(expected = IllegalArgumentException) void testForIdWithInvalidId() { - //unlike the 'get' paradigm, 'forKey' requires the value to exist + //unlike the 'get' paradigm, 'key' requires the value to exist registry.forKey('invalid') } diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy index 4502c6bac..254e2fa1a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeyAlgorithmsTest.groovy @@ -72,7 +72,7 @@ class KeyAlgorithmsTest { @Test(expected = IllegalArgumentException) void testForKeyWithInvalidId() { - //unlike the 'get' paradigm, 'forKey' requires the value to exist + //unlike the 'get' paradigm, 'key' requires the value to exist Jwts.KEY.get().forKey('invalid') } diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index d1850ea49..4ce2db266 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -67,7 +67,7 @@ public void testExampleJwsHS() { byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWS: - String jws = Jwts.builder().setContent(content, "text/plain").signWith(key, alg).compact(); + String jws = Jwts.builder().content(content, "text/plain").signWith(key, alg).compact(); // Parse the compact JWS: content = Jwts.parser().verifyWith(key).build().parseContentJws(jws).getPayload(); @@ -133,7 +133,7 @@ public void testExampleJweDir() { byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWE: - String jwe = Jwts.builder().setContent(content, "text/plain").encryptWith(key, enc).compact(); + String jwe = Jwts.builder().content(content, "text/plain").encryptWith(key, enc).compact(); // Parse the compact JWE: content = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe).getPayload(); @@ -241,7 +241,7 @@ public void testExampleJwePassword() { // Create the compact JWE: String jwe = Jwts.builder().setIssuer("me") // Optional work factor is specified in the header: - //.header().setPbes2Count(pbkdf2Iterations)).and() + //.header().pbes2Count(pbkdf2Iterations)).and() .encryptWith(password, alg, enc) .compact(); @@ -256,7 +256,7 @@ public void testExampleJwePassword() { @Test public void testExampleSecretJwk() { SecretKey key = Jwts.SIG.HS512.keyBuilder().build(); // or HS384 or HS256 - SecretJwk jwk = builder().forKey(key).setIdFromThumbprint().build(); + SecretJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -273,7 +273,7 @@ public void testExampleSecretJwk() { @Test public void testExampleRsaPublicJwk() { RSAPublicKey key = (RSAPublicKey) Jwts.SIG.RS512.keyPairBuilder().build().getPublic(); - RsaPublicJwk jwk = builder().forKey(key).setIdFromThumbprint().build(); + RsaPublicJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -293,7 +293,7 @@ public void testExampleRsaPrivateJwk() { RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate(); - RsaPrivateJwk privJwk = builder().forKey(privKey).setIdFromThumbprint().build(); + RsaPrivateJwk privJwk = builder().key(privKey).idFromThumbprint().build(); RsaPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -313,7 +313,7 @@ public void testExampleRsaPrivateJwk() { @Test public void testExampleEcPublicJwk() { ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPairBuilder().build().getPublic(); - EcPublicJwk jwk = builder().forKey(key).setIdFromThumbprint().build(); + EcPublicJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -333,7 +333,7 @@ public void testExampleEcPrivateJwk() { ECPublicKey pubKey = (ECPublicKey) pair.getPublic(); ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate(); - EcPrivateJwk privJwk = builder().forKey(privKey).setIdFromThumbprint().build(); + EcPrivateJwk privJwk = builder().key(privKey).idFromThumbprint().build(); EcPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -353,7 +353,7 @@ public void testExampleEcPrivateJwk() { @Test public void testExampleEdEcPublicJwk() { PublicKey key = Jwts.SIG.Ed25519.keyPairBuilder().build().getPublic(); - OctetPublicJwk jwk = builder().forOctetKey(key).setIdFromThumbprint().build(); + OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -373,7 +373,7 @@ public void testExampleEdEcPrivateJwk() { PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); - OctetPrivateJwk privJwk = builder().forOctetKey(privKey).setIdFromThumbprint().build(); + OctetPrivateJwk privJwk = builder().octetKey(privKey).idFromThumbprint().build(); OctetPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); From cdc601a1e2ad6a210714617c6e84b153ade173f2 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:42:23 -0700 Subject: [PATCH 02/24] impl checkpoint of modern builder-style setters (without the 'set' prefix) --- .../io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy index 4a02d74cd..c73a0eb1d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/AbstractProtectedHeaderTest.groovy @@ -15,6 +15,7 @@ */ package io.jsonwebtoken.impl +import io.jsonwebtoken.Jwts import io.jsonwebtoken.impl.security.Randoms import io.jsonwebtoken.impl.security.TestKeys import io.jsonwebtoken.io.Encoders @@ -56,7 +57,7 @@ class AbstractProtectedHeaderTest { @Test void testJku() { URI uri = URI.create('https://github.com') - def header = h([jku: uri]) + def header = Jwts.header().jwkSetUrl(uri).build() as DefaultProtectedHeader assertEquals uri.toString(), header.get('jku') assertEquals uri, header.getJwkSetUrl() } @@ -212,7 +213,7 @@ class AbstractProtectedHeaderTest { @Test void testCritical() { Set crits = Collections.setOf('foo', 'bar') - def header = h([crit: crits]) + def header = Jwts.header().critical(crits).build() as DefaultProtectedHeader assertEquals crits, header.getCritical() } From d2bea841c05f192a1e2daca86f2933fb1aa1b240 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Sun, 6 Aug 2023 11:03:03 -0700 Subject: [PATCH 03/24] impl checkpoint of modern builder-style setters (without the 'set' prefix) - Renamed Keys.forPassword to slightly cleaner/less verbose Keys.password - Ensured ClaimsMutator extends MapMutator - Ensured JwtBuilder verifyWith is overloaded and accepts only SecretKey and PublicKey instances - Ensured JwtBuilder decryptWith is overloaded and accepts only SecretKey and PrivateKey instances - Renamed JwtParserBuilder#enableUnsecuredJwts() to enableUnsecured() since any JWT or JWS without a header (or with an alg of none) are both considered 'unsecured', so the suffix was removed to avoid confusion. --- CHANGELOG.md | 45 +++-- .../java/io/jsonwebtoken/ClaimsBuilder.java | 3 +- .../java/io/jsonwebtoken/ClaimsMutator.java | 4 +- .../java/io/jsonwebtoken/HeaderMutator.java | 48 +++-- .../main/java/io/jsonwebtoken/JwtBuilder.java | 180 +++++++++++++----- .../io/jsonwebtoken/JwtParserBuilder.java | 118 ++++++++---- .../jsonwebtoken/ProtectedHeaderMutator.java | 50 ++--- .../java/io/jsonwebtoken/lang/MapMutator.java | 30 +-- .../java/io/jsonwebtoken/security/Keys.java | 4 +- .../jsonwebtoken/impl/DefaultJwtBuilder.java | 34 +++- .../jsonwebtoken/impl/DefaultJwtParser.java | 10 +- .../impl/DefaultJwtParserBuilder.java | 37 +++- .../impl/DefaultTextCodecFactory.java | 55 ------ .../jsonwebtoken/impl/TextCodecFactory.java | 25 --- .../impl/security/KeysBridge.java | 2 +- .../impl/security/StandardKeyAlgorithms.java | 2 +- .../CustomObjectDeserializationTest.groovy | 4 +- .../io/jsonwebtoken/JwtParserTest.groovy | 44 ++--- .../groovy/io/jsonwebtoken/JwtsTest.groovy | 52 ++--- .../impl/DefaultJwtBuilderTest.groovy | 25 +++ .../impl/DefaultJwtParserBuilderTest.groovy | 6 +- .../jsonwebtoken/impl/DefaultJwtTest.groovy | 8 +- .../impl/DefaultTextCodecFactoryTest.groovy | 74 ------- .../DeflateCompressionCodecTest.groovy | 2 +- .../security/DefaultMacAlgorithmTest.groovy | 2 +- .../impl/security/PasswordSpecTest.groovy | 8 +- .../security/Pbes2HsAkwAlgorithmTest.groovy | 4 +- .../impl/security/RFC7517AppendixCTest.groovy | 2 +- .../impl/security/RFC7520Section5Test.groovy | 2 +- .../io/jsonwebtoken/security/KeysTest.groovy | 2 +- .../io/jsonwebtoken/all/JavaReadmeTest.java | 13 +- 31 files changed, 479 insertions(+), 416 deletions(-) delete mode 100644 impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java delete mode 100644 impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java delete mode 100644 impl/src/test/groovy/io/jsonwebtoken/impl/DefaultTextCodecFactoryTest.groovy diff --git a/CHANGELOG.md b/CHANGELOG.md index 621f4cd37..25952bdec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,15 +121,34 @@ deprecate some concepts, or in some cases, completely break backwards compatibil support expected congruent behavior with `Jwe` instances (both have digests). -* `io.jsonwebtoken.CompressionCodec` now inherits a new `io.jsonwebtoken.Identifiable` interface and its `getId()` - method is preferred over the now-deprecated `getAlgorithmName()` method. This is to guarantee API congruence with - all other JWT-identifiable algorithm names that can be set as a header value. +* `io.jsonwebtoken.CompressionCodec` is now deprecated in favor of the new `io.jsonwebtoken.io.CompressionAlgorithm` + interface. This is to guarantee API congruence with all other JWT-identifiable algorithm IDs that can be set as a + header value. + + +* `io.jsonwebtoken.CompressionCodecResolver` has been deprecated in favor of the new + `JwtParserBuilder#addCompressionAlgorithms` method. #### Breaking Changes +* **`io.jsonwebtoken.Claims` and `io.jsonwebtoken.Header` instances are now immutable** to enhance security and thread + safety. Creation and mutation are supported with newly introduced `ClaimsBuilder` and `HeaderBuilder` concepts. + Even though mutation methods have migrated, there are a couple that have been removed entirely: + * `io.jsonwebtoken.JwsHeader#setAlgorithm` has been removed - the `JwtBuilder` will always set the appropriate + `alg` header automatically based on builder state. + * `io.jsonwebtoken.Header#setCompressionAlgorithm` has been removed - the `JwtBuilder` will always set the appropriate + `zip` header automatically based on builder state. + + * `io.jsonwebtoken.Jwts`'s `header(Map)`, `jwsHeader()` and `jwsHeader(Map)` methods have been removed in favor - of the new `header()` builder-based method to support method chaining and dynamic Header type creation. + of the new `header()` method that returns a `HeaderBuilder` to support method chaining and dynamic `Header` type + creation. The `HeaderBuilder` will dynamically create a `Header`, `JwsHeader` or `JweHeader` automatically based on + builder state. + + +* Similarly, `io.jsonwebtoken.Jwts`'s `claims()` static method has been changed to return a `ClaimsBuilder` instead + of a `Claims` instance. * **JWTs that do not contain JSON Claims now have a payload type of `byte[]` instead of `String`** (that is, @@ -166,19 +185,6 @@ deprecate some concepts, or in some cases, completely break backwards compatibil `resolveSigningKey(JwsHeader, byte[])`. -* **`io.jsonwebtoken.Claims` and `io.jsonwebtoken.Header` instances are now immutable** to enhance security and thread - safety. Creation and mutation are supported with newly introduced `ClaimsBuilder` and `HeaderBuilder` concepts. - - -* Consequently, `io.jsonwebtoken.Jwts`'s `claims()` static method has been changed to return a `ClaimsBuilder` instead - of a `Claims` instance. - - -* Similarly, `io.jsonwebtoken.Jwts`'s `header()` static method has been changed to return a `HeaderBuilder` instead of - a `Header` instance. The `HeaderBuilder` will dynamically create a `Header`, `JwsHeader` or `JweHeader` - automatically based on builder state. - - * `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()`). @@ -191,7 +197,8 @@ deprecate some concepts, or in some cases, completely break backwards compatibil * `io.jsonwebtoken.CompressionCodec` implementations are no longer discoverable via `java.util.ServiceLoader` due to runtime performance problems with the JDK's `ServiceLoader` implementation per - https://github.com/jwtk/jjwt/issues/648. + https://github.com/jwtk/jjwt/issues/648. Custom implementations should be made available to the `JwtParser` via + the new `JwtParserBuilder#addCompressionAlgorithms` method. * Prior to this release, if there was a serialization problem when serializing the JWT Header, an `IllegalStateException` @@ -202,7 +209,7 @@ deprecate some concepts, or in some cases, completely break backwards compatibil * Parsing of unsecured JWTs (`alg` header of `none`) are now disabled by default as mandated by [RFC 7518, Section 3.6](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6). If you require parsing of - unsecured JWTs, you must call the `enableUnsecuredJws` method on the `JwtParserBuilder`, but note the security + unsecured JWTs, you must call the `JwtParserBuilder#enableUnsecured()` method, but note the security implications mentioned in that method's JavaDoc before doing so. diff --git a/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java b/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java index 22e19932c..9877bad36 100644 --- a/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java @@ -16,7 +16,6 @@ package io.jsonwebtoken; import io.jsonwebtoken.lang.Builder; -import io.jsonwebtoken.lang.MapMutator; /** * {@link Builder} used to create an immutable {@link Claims} instance. @@ -25,5 +24,5 @@ * @see Claims * @since JJWT_RELEASE_VERSION */ -public interface ClaimsBuilder extends MapMutator, ClaimsMutator, Builder { +public interface ClaimsBuilder extends ClaimsMutator, Builder { } diff --git a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java index 0c5829ee1..251d62cb1 100644 --- a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java @@ -15,6 +15,8 @@ */ package io.jsonwebtoken; +import io.jsonwebtoken.lang.MapMutator; + import java.util.Date; /** @@ -25,7 +27,7 @@ * @see io.jsonwebtoken.Claims * @since 0.2 */ -public interface ClaimsMutator> { +public interface ClaimsMutator> extends MapMutator { /** * Sets the JWT diff --git a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java index 454270599..336f25052 100644 --- a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java @@ -25,6 +25,33 @@ */ public interface HeaderMutator> extends MapMutator { + //IMPLEMENTOR NOTE: if this `algorithm` method ever needs to be exposed in the public API, it's probably better to + // have it in the Jwts.HeaderBuilder interface and NOT this one: in the context of + // JwtBuilder.Header, there is never a reason for an application developer to call algorithm(id) + // directly because the KeyAlgorithm or SecureDigestAlgorithm instance must always be provided + // via the signWith or encryptWith methods. The JwtBuilder will always set the algorithm + // header based on these two instances, so there is no need for an app dev to do so. + /* + * Sets the JWT {@code alg} (Algorithm) header value. A {@code null} value will remove the property + * from the JSON map. + *
    + *
  • If the JWT is a Signed JWT (a JWS), the + * {@code alg} (Algorithm) header + * parameter identifies the cryptographic algorithm used to secure the JWS.
  • + *
  • If the JWT is an Encrypted JWT (a JWE), the + * alg (Algorithm) header parameter + * identifies the cryptographic key management algorithm used to encrypt or determine the value of the Content + * Encryption Key (CEK). The encrypted content is not usable if the alg value does not represent a + * supported algorithm, or if the recipient does not have a key that can be used with that algorithm.
  • + *
+ * + * @param alg the {@code alg} header value + * @return this header for method chaining + * @since JJWT_RELEASE_VERSION + * + T algorithm(String alg); + */ + /** * Sets the JWT * typ (Type) header value. A {@code null} value will remove the property from the JSON map. @@ -60,25 +87,4 @@ public interface HeaderMutator> extends MapMutator - *
  • If the JWT is a Signed JWT (a JWS), the - * {@code alg} (Algorithm) header - * parameter identifies the cryptographic algorithm used to secure the JWS.
  • - *
  • If the JWT is an Encrypted JWT (a JWE), the - * alg (Algorithm) header parameter - * identifies the cryptographic key management algorithm used to encrypt or determine the value of the Content - * Encryption Key (CEK). The encrypted content is not usable if the alg value does not represent a - * supported algorithm, or if the recipient does not have a key that can be used with that algorithm.
  • - * - * - * @param alg the {@code alg} header value - * @return this header for method chaining - * @since JJWT_RELEASE_VERSION - * - T algorithm(String alg); - */ } diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 7ef279871..16e928115 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -78,8 +78,9 @@ public interface JwtBuilder extends ClaimsMutator { * * .header() * .keyId("keyId") + * .set("aName", aValue) * .set(myHeaderMap) - * // ... other header params ... + * // ... etc ... * .{@link JwtBuilder.Header#and() and()} //return back to the JwtBuilder * * .setSubject("Joe") // resume JwtBuilder calls @@ -92,35 +93,101 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder.Header header(); /** - * Sets (and replaces) any existing header with the specified name/value pairs. If you do not want to replace the - * existing header and only want to append to it, call - * {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)} - * instead. + * Per standard Java idiom 'setter' conventions, this method sets (and fully replaces) any existing header with the + * specified name/value pairs. This method is identical to calling + * {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#empty() empty()}{@code .} + * {@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}{@code .}{@link Header#and() and()}. + * + *

    If you do not want to replace the existing header and only want to append to it, + * call {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)} instead.

    * * @param map the name/value pairs to set as (and potentially replace) the constructed JWT header. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} + * {@link io.jsonwebtoken.lang.MapMutator#empty() empty()}{@code .} + * {@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}{@code .}{@link Header#and() and()} (to replace + * all header parameters) or {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)} + * {@code .}{@link Header#and() and()} to only append the {@code map} entries. This + * method will be removed before the 1.0 release. */ + @Deprecated JwtBuilder setHeader(Map map); /** - * Applies the specified name/value pairs to the header. If a header does not yet exist at the time this method - * is called, one will be created automatically before applying the name/value pairs. + * Adds the specified name/value pairs to the header. Any parameter with an empty or null value will remove the + * entry from the header. * * @param params the header name/value pairs to append to the header. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} + * {@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}{@code .}{@link Header#and() and()}. This + * method will be removed before the 1.0 release. */ + @Deprecated JwtBuilder setHeaderParams(Map params); /** - * Applies the specified name/value pair to the header. If a header does not yet exist at the time this method - * is called, one will be created automatically before applying the name/value pair. + * Adds the specified name/value pair to the header. * * @param name the header parameter name * @param value the header parameter value * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} + * {@link io.jsonwebtoken.lang.MapMutator#set(Object, Object) set(name, value)}{@code .}{@link Header#and() and()}. This + * method will be removed before the 1.0 release. */ + @Deprecated JwtBuilder setHeaderParam(String name, Object value); + /** + * Removes the specified named parameter from the JWT Claims payload. + * + * @param key the key for the map entry to remove. + * @return the builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + @Override + // for better/targeted JavaDoc + JwtBuilder delete(String key); + + /** + * Removes all Claims and payload {@link #content(byte[], String) content}. + * + * @return the builder for method chaining. + */ + @Override + // for better/targeted JavaDoc + JwtBuilder empty(); + + /** + * Sets the specified named parameter in the JWT Claims payload. A {@code null} value will remove the Claims + * entry. + * + *

    This method is mutually exclusive of the {@link #content(byte[])} and {@link #content(byte[], String)} + * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    + * + * @param key the Claim name (map key) + * @param value the value to set for the specified claim name + * @return the builder for method chaining. + */ + @Override + // for better/targeted JavaDoc + JwtBuilder set(String key, Object value); + + /** + * Sets the specified named entries in the JWT Claims payload. Any entry with an empty or null value will + * remove the entry from the JWT Claims payload. + * + *

    This method is mutually exclusive of the {@link #content(byte[])} and {@link #content(byte[], String)} + * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    + * + * @param m map of Claim name/value pairs to apply to the JWT Claims payload. + * @return the builder for method chaining. + */ + @Override + // for better/targeted JavaDoc + JwtBuilder set(Map m); + /** * Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the * {@link Header#contentType(String) contentType} header value so the JWT recipient may inspect that value to @@ -131,10 +198,10 @@ public interface JwtBuilder extends ClaimsMutator { *
          * {@link #content(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));
    * - *

    If you want the JWT payload to be JSON, use the - * {@link #setClaims(Claims)} or {@link #setClaims(java.util.Map)} methods instead.

    + *

    If you want the JWT payload to be JSON, use the {@link #set(Map)} method instead.

    * - *

    The payload and claims properties are mutually exclusive - only one of the two may be used.

    + *

    This method is mutually exclusive of the {@link #set(String, Object)} and {@link #set(Map)} + * methods. Either {@code set} or {@code content}/{@code payload} method variants may be used, but not both.

    * * @param payload the string used to set UTF-8-encoded bytes as the JWT payload. * @return the builder for method chaining. @@ -151,6 +218,9 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets the JWT payload to be the specified content byte array. * + *

    This method is mutually exclusive of the {@link #set(String, Object)} and {@link #set(Map)} + * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    + * *

    Content Type Recommendation

    * *

    Unless you are confident that the JWT recipient will always know how to use @@ -172,6 +242,9 @@ public interface JwtBuilder extends ClaimsMutator { * identifier to indicate the data format of the byte array. The JWT recipient can inspect the * {@code cty} value to determine how to convert the byte array to the final content type as desired. * + *

    This method is mutually exclusive of the {@link #set(String, Object)} and {@link #set(Map)} + * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    + * *

    Compact Media Type Identifier

    * *

    As a convenience, this method will automatically trim any application/ prefix from the @@ -203,14 +276,23 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder content(byte[] content, String cty) throws IllegalArgumentException; /** - * Sets the JWT payload to be a JSON Claims instance. If you do not want the JWT payload to be JSON claims and - * instead want it to be a byte array representing any type of content, use the {@link #content(byte[])} - * method instead. + * Sets (and replaces) any existing claims with the specified name/value pairs. This is a convenience method + * equivalent to calling {@link #empty()}{@code .}{@link #set(Map) set(map)}. * - *

    The payload and claims properties are mutually exclusive - only one of the two may be used.

    + *
      + *
    • If you do not want to replace the existing claims and only want to append to them, call + * {@link #set(Map) set(map)} instead.
    • + *
    • If you do not want the JWT payload to be JSON claims and instead want it to be a byte array + * representing any type of content, use the {@link #content(byte[], String)} method instead.
    • + *
    + * + *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * * @param claims the JWT claims to be set as the JWT payload. * @return the builder for method chaining. + * @see #content(byte[], String) + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #empty()}{@code .}{@link #set(Map) set(map)}. This + * method will be removed before the 1.0 release. */ JwtBuilder setClaims(Claims claims); @@ -219,7 +301,7 @@ public interface JwtBuilder extends ClaimsMutator { * want the JWT payload to be JSON claims and instead want it to be a byte array for any content, use the * {@link #content(byte[])} or {@link #content(byte[], String)} methods instead. * - *

    The payload and claims properties are mutually exclusive - only one of the two may be used.

    + *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * * @param claims the JWT Claims to be set as the JWT payload. * @return the builder for method chaining. @@ -227,15 +309,17 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder setClaims(Map claims); /** - * Adds all given name/value pairs to the JSON Claims in the payload. If a Claims instance does not yet exist at the - * time this method is called, one will be created automatically before applying the name/value pairs. + * Adds/appends all given name/value pairs to the JSON Claims in the payload. * - *

    The payload and claims properties are mutually exclusive - only one of the two may be used.

    + *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * * @param claims the JWT Claims to be added to the JWT payload. * @return the builder for method chaining. * @since 0.8 + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #set(Map)}. This method will be removed before the + * 1.0 release. */ + @Deprecated JwtBuilder addClaims(Map claims); /** @@ -247,12 +331,12 @@ public interface JwtBuilder extends ClaimsMutator { * code like this:

    * *
    -     * String jwt = Jwts.builder().setIssuer("Joe").compact();
    +     * String jwt = Jwts.builder().issuer("Joe").compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setIssuer("Joe").build();
    +     * Claims claims = Jwts.claims().issuer("Joe").build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -263,7 +347,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setIssuer(String iss); + JwtBuilder issuer(String iss); /** * Sets the JWT Claims @@ -274,11 +358,11 @@ public interface JwtBuilder extends ClaimsMutator { * code like this:

    * *
    -     * String jwt = Jwts.builder().setSubject("Me").compact();
    + * String jwt = Jwts.builder().subject("Me").compact();
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setSubject("Me").build();
    +     * Claims claims = Jwts.claims().subject("Me").build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
    *

    if desired.

    * @@ -288,7 +372,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setSubject(String sub); + JwtBuilder subject(String sub); /** * Sets the JWT Claims
    @@ -299,12 +383,12 @@ public interface JwtBuilder extends ClaimsMutator { * code like this:

    * *
    -     * String jwt = Jwts.builder().setAudience("You").compact();
    +     * String jwt = Jwts.builder().audience("You").compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setAudience("You");
    +     * Claims claims = Jwts.claims().audience("You").build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -315,7 +399,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setAudience(String aud); + JwtBuilder audience(String aud); /** * Sets the JWT Claims
    @@ -328,12 +412,12 @@ public interface JwtBuilder extends ClaimsMutator { * you to write code like this:

    * *
    -     * String jwt = Jwts.builder().setExpiration(new Date(System.currentTimeMillis() + 3600000)).compact();
    +     * String jwt = Jwts.builder().expiration(new Date(System.currentTimeMillis() + 3600000)).compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setExpiration(new Date(System.currentTimeMillis() + 3600000));
    +     * Claims claims = Jwts.claims().expiration(new Date(System.currentTimeMillis() + 3600000)).build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -344,7 +428,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setExpiration(Date exp); + JwtBuilder expiration(Date exp); /** * Sets the JWT Claims
    @@ -357,12 +441,12 @@ public interface JwtBuilder extends ClaimsMutator { * you to write code like this:

    * *
    -     * String jwt = Jwts.builder().setNotBefore(new Date()).compact();
    +     * String jwt = Jwts.builder().notBefore(new Date()).compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setNotBefore(new Date());
    +     * Claims claims = Jwts.claims().notBefore(new Date()).build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -373,7 +457,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setNotBefore(Date nbf); + JwtBuilder notBefore(Date nbf); /** * Sets the JWT Claims
    @@ -386,12 +470,12 @@ public interface JwtBuilder extends ClaimsMutator { * you to write code like this:

    * *
    -     * String jwt = Jwts.builder().setIssuedAt(new Date()).compact();
    +     * String jwt = Jwts.builder().issuedAt(new Date()).compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setIssuedAt(new Date());
    +     * Claims claims = Jwts.claims().issuedAt(new Date()).build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -402,7 +486,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setIssuedAt(Date iat); + JwtBuilder issuedAt(Date iat); /** * Sets the JWT Claims
    @@ -417,12 +501,12 @@ public interface JwtBuilder extends ClaimsMutator { * you to write code like this:

    * *
    -     * String jwt = Jwts.builder().setId(UUID.randomUUID().toString()).compact();
    +     * String jwt = Jwts.builder().id(UUID.randomUUID().toString()).compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().setId(UUID.randomUUID().toString());
    +     * Claims claims = Jwts.claims().id(UUID.randomUUID().toString()).build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -433,22 +517,20 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override //only for better/targeted JavaDoc - JwtBuilder setId(String jti); + JwtBuilder id(String jti); /** * Sets a custom JWT Claims parameter value. A {@code null} value will remove the property from the Claims. * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set the - * named property on the Claims instance using the Claims {@link Claims#put(Object, Object) put} method. This allows - * you to write code like this:

    + *

    This is a convenience method that allows you to write code like this:

    * *
    -     * String jwt = Jwts.builder().claim("aName", "aValue").compact();
    +     * String jwt = Jwts.builder().claim("aName", aValue).compact();
          * 
    * *

    instead of this:

    *
    -     * Claims claims = Jwts.claims().put("aName", "aValue");
    +     * Claims claims = Jwts.claims().set("aName", aValue).build();
          * String jwt = Jwts.builder().setClaims(claims).compact();
          * 
    *

    if desired.

    @@ -841,7 +923,7 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder); /** - * Performs object-to-JSON serialization with the specified Serializer. This is used by the builder to convert + * Performs Map-to-JSON serialization with the specified Serializer. This is used by the builder to convert * JWT/JWS/JWE headers and claims Maps to JSON strings as required by the JWT specification. * *

    If this method is not called, JJWT will use whatever serializer it can find at runtime, checking for the @@ -856,7 +938,7 @@ public interface JwtBuilder extends ClaimsMutator { /** * Actually builds the JWT and serializes it to a compact, URL-safe string according to the - * JWT Compact Serialization + * JWT Compact Serialization * rules. * * @return A compact URL-safe JWT string. @@ -864,7 +946,7 @@ public interface JwtBuilder extends ClaimsMutator { String compact(); /** - * Editable header for use with a {@link JwtBuilder} that supports method chaining for any/all + * Header for use with a {@link JwtBuilder} that supports method chaining for * standard JWT, JWS and JWE header parameters. Once header parameters are configured, the associated * {@link JwtBuilder} may be obtained with the {@link #and() and()} method for continued configuration. * diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index d6e226c50..090957f81 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -23,8 +23,11 @@ import io.jsonwebtoken.security.KeyAlgorithm; import io.jsonwebtoken.security.SecureDigestAlgorithm; +import javax.crypto.SecretKey; import java.security.Key; +import java.security.PrivateKey; import java.security.Provider; +import java.security.PublicKey; import java.util.Collection; import java.util.Date; import java.util.Map; @@ -45,11 +48,11 @@ public interface JwtParserBuilder extends Builder { /** - * Enables parsing of Unsecured JWSs (JWTs with an 'alg' (Algorithm) header value of - * 'none'). Be careful when calling this method - one should fully understand + * Enables parsing of Unsecured JWTs (JWTs with an 'alg' (Algorithm) header value of + * 'none' or missing the 'alg' header entirely). Be careful when calling this method - one should fully understand * Unsecured JWS Security Considerations * before enabling this feature. - *

    If this method is not called, Unsecured JWSs are disabled by default as mandated by + *

    If this method is not called, Unsecured JWTs are disabled by default as mandated by * RFC 7518, Section * 3.6.

    * @@ -60,23 +63,23 @@ public interface JwtParserBuilder extends Builder { * @see #enableUnsecuredDecompression() * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder enableUnsecuredJws(); + JwtParserBuilder enableUnsecured(); /** - * If {@link #enableUnsecuredJws() enabledUnsecuredJws} is enabled, calling this method additionally enables - * payload decompression of Unsecured JWSs (JWTs with an 'alg' (Algorithm) header value of 'none') that also have + * If {@link #enableUnsecured() enabledUnsecuredJws} is enabled, calling this method additionally enables + * payload decompression of Unsecured JWTs (JWTs with an 'alg' (Algorithm) header value of 'none') that also have * a 'zip' (Compression) header. This behavior is disabled by default because using compression * algorithms with data from unverified (unauthenticated) parties can be susceptible to Denial of Service attacks * and other data integrity problems as described in * In the * Compression Hornet’s Nest: A Security Study of Data Compression in Network Services. * - *

    Because this behavior is only relevant if {@link #enableUnsecuredJws() enabledUnsecuredJws} is specified, - * calling this method without also calling {@code enableUnsecuredJws()} will result in a build exception, as the + *

    Because this behavior is only relevant if {@link #enableUnsecured() enabledUnsecured} is specified, + * calling this method without also calling {@code enableUnsecured()} will result in a build exception, as the * incongruent state could reflect a misunderstanding of both behaviors which should be remedied by the * application developer.

    * - * As is the case for {@link #enableUnsecuredJws()}, be careful when calling this method - one should fully + * As is the case for {@link #enableUnsecured()}, be careful when calling this method - one should fully * understand * Unsecured JWS Security Considerations * before enabling this feature. @@ -86,7 +89,7 @@ public interface JwtParserBuilder extends Builder { * @see In the * Compression Hornet’s Nest: A Security Study of Data Compression in Network Services * @see Jwts.SIG#NONE - * @see #enableUnsecuredJws() + * @see #enableUnsecured() * @since JJWT_RELEASE_VERSION */ JwtParserBuilder enableUnsecuredDecompression(); @@ -253,7 +256,7 @@ public interface JwtParserBuilder extends Builder { *

    This method has been deprecated since JJWT_RELEASE_VERSION and will be removed before 1.0. It was not * readily obvious to many JJWT users that this method was for bytes that pertained only to HMAC * {@code SecretKey}s, and could be confused with keys of other types. It is better to obtain a type-safe - * {@link Key} instance and call the {@link #verifyWith(Key)} instead.

    + * {@link SecretKey} instance and call {@link #verifyWith(SecretKey)} instead.

    * *

    Previous Documentation

    * @@ -268,8 +271,8 @@ public interface JwtParserBuilder extends Builder { * @param key the algorithm-specific signature verification key used to validate any discovered JWS digital * signature. * @return the parser builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(Key)} for type safety and name congruence - * with the {@link #decryptWith(Key)} method. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(SecretKey)} for type safety and name + * congruence with the {@link #decryptWith(SecretKey)} method. */ @Deprecated JwtParserBuilder setSigningKey(byte[] key); @@ -295,7 +298,7 @@ public interface JwtParserBuilder extends Builder { * StackOverflow answer explaining why raw (non-base64-encoded) strings are almost always incorrect for * signature operations.

    * - *

    Finally, please use the {@link #verifyWith(Key)} method instead, as this method (and likely + *

    Finally, please use the {@link #verifyWith(SecretKey)} method instead, as this method (and likely * {@link #setSigningKey(byte[])}) will be removed before the 1.0.0 release.

    * *

    Previous JavaDoc

    @@ -305,12 +308,12 @@ public interface JwtParserBuilder extends Builder { *
          * byte[] bytes = Decoders.{@link io.jsonwebtoken.io.Decoders#BASE64 BASE64}.decode(base64EncodedSecretKey);
          * Key key = Keys.{@link io.jsonwebtoken.security.Keys#hmacShaKeyFor(byte[]) hmacShaKeyFor}(bytes);
    -     * return {@link #verifyWith(Key) verifyWith}(key);
    + * return {@link #verifyWith(SecretKey) verifyWith}(key);
    * * @param base64EncodedSecretKey BASE64-encoded HMAC-SHA key bytes used to create a Key which will be used to * verify all encountered JWS digital signatures. * @return the parser builder for method chaining. - * @deprecated in favor of {@link #verifyWith(Key)} as explained in the above Deprecation Notice, + * @deprecated in favor of {@link #verifyWith(SecretKey)} as explained in the above Deprecation Notice, * and will be removed in 1.0.0. */ @Deprecated @@ -322,32 +325,31 @@ public interface JwtParserBuilder extends Builder { *

    This method is being renamed to accurately reflect its purpose - the key is not technically a signing key, * it is a signature verification key, and the two concepts can be different, especially with asymmetric key * cryptography. The method has been deprecated since JJWT_RELEASE_VERSION in favor of - * {@link #verifyWith(Key)} for type safety, to reflect accurate naming of the concept, and for name congruence - * with the {@link #decryptWith(Key)} method.

    + * {@link #verifyWith(SecretKey)} for type safety, to reflect accurate naming of the concept, and for name + * congruence with the {@link #decryptWith(SecretKey)} method.

    * - *

    This method merely delegates directly to {@link #verifyWith(Key)}.

    + *

    This method merely delegates directly to {@link #verifyWith(SecretKey)}.

    * * @param key the algorithm-specific signature verification key to use to verify all encountered JWS digital * signatures. * @return the parser builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(Key)} for naming congruence with the - * {@link #decryptWith(Key)} method. + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #verifyWith(SecretKey)} for naming congruence with the + * {@link #decryptWith(SecretKey)} method. */ @Deprecated JwtParserBuilder setSigningKey(Key key); /** - * Sets the signature verification key used to verify all encountered JWS signatures. If the encountered JWT + * Sets the signature verification SecretKey used to verify all encountered JWS signatures. If the encountered JWT * string is not a JWS (e.g. unsigned or a JWE), this key is not used. * *

    This is a convenience method to use in a specific scenario: when the parser will only ever encounter - * JWSs with signatures that can always be verified by a single key. This also implies that this key + * JWSs with signatures that can always be verified by a single SecretKey. This also implies that this key * MUST be a valid key for the signature algorithm ({@code alg} header) used for the JWS.

    * - *

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

    + *

    If there is any chance that the parser will also encounter JWEs, or JWSs that need different signature + * verification keys based on the JWS being parsed, it is strongly recommended to configure your own + * {@link #keyLocator(Locator) keyLocator} instead of calling this method.

    * *

    Calling this method overrides any previously set signature verification key.

    * @@ -355,22 +357,60 @@ public interface JwtParserBuilder extends Builder { * @return the parser builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder verifyWith(Key key); + JwtParserBuilder verifyWith(SecretKey key); /** - * Sets the decryption key used to decrypt all encountered JWEs, overwriting any previously configured - * {@link #keyLocator(Locator) keyLocator}. If the encountered JWT string is not a JWE (e.g. a JWS), - * this key is not used. + * Sets the signature verification PublicKey used to verify all encountered JWS signatures. If the encountered JWT + * string is not a JWS (e.g. unsigned or a JWE), this key is not used. + * + *

    This is a convenience method to use in a specific scenario: when the parser will only ever encounter + * JWSs with signatures that can always be verified by a single PublicKey. This also implies that this key + * MUST be a valid key for the signature algorithm ({@code alg} header) used for the JWS.

    + * + *

    If there is any chance that the parser will also encounter JWEs, or JWSs that need different signature + * verification keys based on the JWS being parsed, it is strongly recommended to configure your own + * {@link #keyLocator(Locator) keyLocator} instead of calling this method.

    + * + *

    Calling this method overrides any previously set signature verification key.

    + * + * @param key the signature verification key to use to verify all encountered JWS digital signatures. + * @return the parser builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtParserBuilder verifyWith(PublicKey key); + + /** + * Sets the decryption SecretKey used to decrypt all encountered JWEs. 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 + * JWEs that can always be decrypted by a single SecretKey. This also implies that this key MUST be a valid * key for both the key management algorithm ({@code alg} header) and the content encryption algorithm * ({@code enc} header) used for the JWE.

    * - *

    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 #keyLocator(Locator) keyLocator} method instead of - * using {@code decryptWith}.

    + *

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

    + * + *

    Calling this method overrides any previously set decryption key.

    + * + * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. + * @return the parser builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtParserBuilder decryptWith(SecretKey key); + + /** + * Sets the decryption PrivateKey used to decrypt all encountered JWEs. 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 PrivateKey. This also implies that this key MUST be a valid + * key for the JWE's key management algorithm ({@code alg} header).

    + * + *

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

    * *

    Calling this method overrides any previously set decryption key.

    * @@ -378,7 +418,7 @@ public interface JwtParserBuilder extends Builder { * @return the parser builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder decryptWith(Key key); + JwtParserBuilder decryptWith(PrivateKey key); /** * Sets the {@link Locator} used to acquire any signature verification or decryption key needed during parsing. @@ -388,8 +428,8 @@ public interface JwtParserBuilder extends Builder { *
  • If the parsed String is a JWE, it will be called to find the appropriate decryption key.
  • * * - *

    Specifying a key {@code Locator} is necessary when the signing or decryption key is not already known before - * parsing the JWT and the JWT header must be inspected first to determine how to + *

    Specifying a key {@code Locator} is necessary when the signature verification or decryption key is not + * already known before parsing the JWT and the JWT header must be inspected first to determine how to * look up the verification or decryption key. Once returned by the locator, the JwtParser will then either * verify the JWS signature or decrypt the JWE payload with the returned key. For example:

    * diff --git a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java index ebad27730..206134b15 100644 --- a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java @@ -30,20 +30,17 @@ public interface ProtectedHeaderMutator> extends HeaderMutator, X509Mutator { /** - * Sets the {@code jku} (JWK Set URL) value that refers to a - * JWK Set - * resource containing JSON-encoded Public Keys, or {@code null} if not present. When set for a - * {@link JwsHeader}, the first public key in the JWK Set must be the public key complement of the - * private key used to sign the JWS. When set for a {@link JweHeader}, the first public key in the JWK Set - * must be the public key used during encryption. + * Sets the header parameter names that use extensions to the JWT or JWA specification that MUST + * be understood and supported by the JWT recipient. A {@code null} value will remove the + * property from the JSON map. * - * @param uri a URI that refers to a JWK Set - * resource containing JSON-encoded Public Keys - * @return the header for method chaining - * @see JWS JWK Set URL - * @see JWE JWK Set URL + * @param crit the header parameter names that use extensions to the JWT or JWA specification that MUST + * be understood and supported by the JWT recipient. + * @return the header for method chaining. + * @see JWS crit (Critical) Header Parameter + * @see JWS crit (Critical) Header Parameter */ - T jwkSetUrl(URI uri); + T critical(Set crit); /** * Sets the {@code jwk} (JSON Web Key) associated with the JWT. When set for a {@link JwsHeader}, the @@ -58,6 +55,22 @@ public interface ProtectedHeaderMutator> ext */ T jwk(PublicJwk jwk); + /** + * Sets the {@code jku} (JWK Set URL) value that refers to a + * JWK Set + * resource containing JSON-encoded Public Keys, or {@code null} if not present. When set for a + * {@link JwsHeader}, the first public key in the JWK Set must be the public key complement of the + * private key used to sign the JWS. When set for a {@link JweHeader}, the first public key in the JWK Set + * must be the public key used during encryption. + * + * @param uri a URI that refers to a JWK Set + * resource containing JSON-encoded Public Keys + * @return the header for method chaining + * @see JWS JWK Set URL + * @see JWE JWK Set URL + */ + T jwkSetUrl(URI uri); + /** * Sets the JWT case-sensitive {@code kid} (Key ID) header value. A {@code null} value will remove the property * from the JSON map. @@ -74,17 +87,4 @@ public interface ProtectedHeaderMutator> ext * @see JWE Key ID */ T keyId(String kid); - - /** - * Sets the header parameter names that use extensions to the JWT or JWA specification that MUST - * be understood and supported by the JWT recipient. A {@code null} value will remove the - * property from the JSON map. - * - * @param crit the header parameter names that use extensions to the JWT or JWA specification that MUST - * be understood and supported by the JWT recipient. - * @return the header for method chaining. - * @see JWS crit (Critical) Header Parameter - * @see JWS crit (Critical) Header Parameter - */ - T critical(Set crit); } diff --git a/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java b/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java index 9a1feef94..869b897ff 100644 --- a/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java +++ b/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java @@ -29,6 +29,16 @@ */ public interface MapMutator> { + /** + * Removes the map entry with the specified key. + *

    This method is the same as {@link Map#remove Map.remove}, but instead returns the mutator instance for + * method chaining.

    + * + * @param key the key for the map entry to remove. + * @return the mutator/builder for method chaining. + */ + T delete(K key); + /** * Removes all entries from the map. The map will be empty after this call returns. *

    This method is the same as {@link Map#clear Map.clear}, but instead returns the mutator instance for @@ -39,8 +49,9 @@ public interface MapMutator> { T empty(); /** - * Sets the specified name/value pair in the map. A {@code null} or empty value will remove the property - * from the map entirely. + * Sets the specified key/value pair in the map, overwriting any existing entry with the same key. + * A {@code null} or empty value will remove the entry from the map entirely. + * *

    This method is the same as {@link Map#put Map.put}, but instead returns the mutator instance for * method chaining.

    * @@ -51,8 +62,9 @@ public interface MapMutator> { T set(K key, V value); /** - * Sets the specified name/value pairs in the map. If any name has a {@code null} or empty value, that - * map entry will be removed from the map entirely. + * Sets the specified key/value pairs in the map, overwriting any existing entries with the same keys. + * If any pair has a {@code null} or empty value, that pair will be removed from the map entirely. + * *

    This method is the same as {@link Map#putAll Map.putAll}, but instead returns the mutator instance for * method chaining.

    * @@ -60,14 +72,4 @@ public interface MapMutator> { * @return the mutator/builder for method chaining. */ T set(Map m); - - /** - * Removes the map entry with the specified key. - *

    This method is the same as {@link Map#remove Map.remove}, but instead returns the mutator instance for - * method chaining.

    - * - * @param key the key for the map entry to remove. - * @return the mutator/builder for method chaining. - */ - T delete(K key); } diff --git a/api/src/main/java/io/jsonwebtoken/security/Keys.java b/api/src/main/java/io/jsonwebtoken/security/Keys.java index 024dd94e5..225cdde21 100644 --- a/api/src/main/java/io/jsonwebtoken/security/Keys.java +++ b/api/src/main/java/io/jsonwebtoken/security/Keys.java @@ -264,7 +264,7 @@ public static KeyPair keyPairFor(io.jsonwebtoken.SignatureAlgorithm alg) throws * @see Password#toCharArray() * @since JJWT_RELEASE_VERSION */ - public static Password forPassword(char[] password) { - return Classes.invokeStatic(BRIDGE_CLASS, "forPassword", FOR_PASSWORD_ARG_TYPES, new Object[]{password}); + public static Password password(char[] password) { + return Classes.invokeStatic(BRIDGE_CLASS, "password", FOR_PASSWORD_ARG_TYPES, new Object[]{password}); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 2bcd2010d..f4c2f6a3a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -322,13 +322,36 @@ public JwtBuilder setClaims(Claims claims) { public JwtBuilder setClaims(Map claims) { Assert.notNull(claims, "Claims map cannot be null."); this.claimsBuilder.empty(); - this.claimsBuilder.set(claims); - return this; + return set(claims); } @Override public JwtBuilder addClaims(Map claims) { - this.claimsBuilder.set(claims); + return set(claims); + } + + @Override + public JwtBuilder delete(String key) { + this.claimsBuilder.delete(key); + return this; + } + + @Override + public JwtBuilder empty() { + this.claimsBuilder.empty(); + this.content = null; + return this; + } + + @Override + public JwtBuilder set(String key, Object value) { + this.claimsBuilder.set(key, value); + return this; + } + + @Override + public JwtBuilder set(Map m) { + this.claimsBuilder.set(m); return this; } @@ -411,8 +434,7 @@ public JwtBuilder id(String jti) { @Override public JwtBuilder claim(String name, Object value) { - this.claimsBuilder.set(name, value); - return this; + return set(name, value); } @Override @@ -425,7 +447,7 @@ public String compact() { throw new IllegalStateException(msg); } - final Claims claims = this.claimsBuilder.build(); + final io.jsonwebtoken.Claims claims = this.claimsBuilder.build(); if (Objects.isEmpty(content) && Collections.isEmpty(claims)) { if (jwe) { // JWE payload can never be empty: diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index 50c6ea6b9..b1ad063f8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -105,7 +105,7 @@ public class DefaultJwtParser implements JwtParser { private static final String UNSECURED_DISABLED_MSG_PREFIX = "Unsecured JWSs (those with an " + DefaultHeader.ALGORITHM + " header value of '" + Jwts.SIG.NONE.getId() + "') are disallowed by " + "default as mandated by https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6. If you wish to " + - "allow them to be parsed, call the JwtParserBuilder.enableUnsecuredJws() method (but please read the " + + "allow them to be parsed, call the JwtParserBuilder.enableUnsecured() method (but please read the " + "security considerations covered in that method's JavaDoc before doing so). Header: "; private static final String JWE_NONE_MSG = "JWEs do not support key management " + DefaultHeader.ALGORITHM + @@ -129,7 +129,7 @@ public class DefaultJwtParser implements JwtParser { @SuppressWarnings("deprecation") private final SigningKeyResolver signingKeyResolver; - private final boolean enableUnsecuredJws; + private final boolean enableUnsecured; private final boolean enableUnsecuredDecompression; @@ -157,7 +157,7 @@ public class DefaultJwtParser implements JwtParser { @SuppressWarnings("deprecation") DefaultJwtParser(Provider provider, SigningKeyResolver signingKeyResolver, - boolean enableUnsecuredJws, + boolean enableUnsecured, boolean enableUnsecuredDecompression, Locator keyLocator, Clock clock, @@ -171,7 +171,7 @@ public class DefaultJwtParser implements JwtParser { Collection> extraKeyAlgs, Collection extraEncAlgs) { this.provider = provider; - this.enableUnsecuredJws = enableUnsecuredJws; + this.enableUnsecured = enableUnsecured; this.enableUnsecuredDecompression = enableUnsecuredDecompression; this.signingKeyResolver = signingKeyResolver; this.keyLocator = Assert.notNull(keyLocator, "Key Locator cannot be null."); @@ -376,7 +376,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe throw new MalformedJwtException(JWE_NONE_MSG); } // Unsecured JWTs are disabled by default per the RFC: - if (!enableUnsecuredJws) { + if (!enableUnsecured) { String msg = UNSECURED_DISABLED_MSG_PREFIX + header; throw new UnsupportedJwtException(msg); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index 706f935ea..81a1b92e0 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -36,8 +36,11 @@ import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.SecureDigestAlgorithm; +import javax.crypto.SecretKey; import java.security.Key; +import java.security.PrivateKey; import java.security.Provider; +import java.security.PublicKey; import java.util.Collection; import java.util.Date; import java.util.LinkedHashSet; @@ -62,7 +65,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder { private Provider provider; - private boolean enableUnsecuredJws = false; + private boolean enableUnsecured = false; private boolean enableUnsecuredDecompression = false; @@ -96,8 +99,8 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder { private Key decryptionKey; @Override - public JwtParserBuilder enableUnsecuredJws() { - this.enableUnsecuredJws = true; + public JwtParserBuilder enableUnsecured() { + this.enableUnsecured = true; return this; } @@ -230,13 +233,31 @@ public JwtParserBuilder setSigningKey(final Key key) { } @Override - public JwtParserBuilder verifyWith(Key key) { + public JwtParserBuilder verifyWith(SecretKey key) { + return verifyWith((Key) key); + } + + @Override + public JwtParserBuilder verifyWith(PublicKey key) { + return verifyWith((Key) key); + } + + private JwtParserBuilder verifyWith(Key key) { this.signatureVerificationKey = Assert.notNull(key, "signature verification key cannot be null."); return this; } @Override - public JwtParserBuilder decryptWith(final Key key) { + public JwtParserBuilder decryptWith(SecretKey key) { + return decryptWith((Key) key); + } + + @Override + public JwtParserBuilder decryptWith(PrivateKey key) { + return decryptWith((Key) key); + } + + private JwtParserBuilder decryptWith(final Key key) { this.decryptionKey = Assert.notNull(key, "decryption key cannot be null."); return this; } @@ -324,8 +345,8 @@ public JwtParser build() { keyLocator = new ConstantKeyLocator(this.signatureVerificationKey, this.decryptionKey); } - if (!enableUnsecuredJws && enableUnsecuredDecompression) { - String msg = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecuredJws' is also " + + if (!enableUnsecured && enableUnsecuredDecompression) { + String msg = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecured' is also " + "configured. Please read the JavaDoc of both features before enabling either " + "due to their security implications."; throw new IllegalStateException(msg); @@ -344,7 +365,7 @@ public JwtParser build() { return new DefaultJwtParser( provider, signingKeyResolver, - enableUnsecuredJws, + enableUnsecured, enableUnsecuredDecompression, keyLocator, clock, diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java deleted file mode 100644 index 7ad8d9a81..000000000 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTextCodecFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015 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; - -/** - * @deprecated since 0.10.0 - */ -@Deprecated //remove just before 1.0.0 release -public class DefaultTextCodecFactory implements TextCodecFactory { - - protected String getSystemProperty(String key) { - return System.getProperty(key); - } - - protected boolean isAndroid() { - - String name = getSystemProperty("java.vm.name"); - if (name != null) { - String lcase = name.toLowerCase(); - return lcase.contains("dalvik"); - } - - name = getSystemProperty("java.vm.vendor"); - if (name != null) { - String lcase = name.toLowerCase(); - return lcase.contains("android"); - } - - return false; - } - - - @Override - public TextCodec getTextCodec() { - - if (isAndroid()) { - return new AndroidBase64Codec(); - } - - return new Base64Codec(); - } -} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java deleted file mode 100644 index a318060f1..000000000 --- a/impl/src/main/java/io/jsonwebtoken/impl/TextCodecFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 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; - -/** - * @deprecated since 0.10.0 - */ -@Deprecated -public interface TextCodecFactory { - - TextCodec getTextCodec(); -} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java b/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java index de7d5562a..eac7ccb9a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java @@ -30,7 +30,7 @@ public final class KeysBridge { private KeysBridge() { } - public static Password forPassword(char[] password) { + public static Password password(char[] password) { return new PasswordSpec(password); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java index 99e051860..c08e33626 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java @@ -144,7 +144,7 @@ public static int estimateIterations(KeyAlgorithm alg, long for (int i = 0; points.size() < NUM_SAMPLES; i++) { char[] password = randomChars(PASSWORD_LENGTH); - Password key = Keys.forPassword(password); + Password key = Keys.password(password); HEADER.pbes2Count(workFactor); KeyRequest request = new DefaultKeyRequest<>(null, null, key, HEADER, ENC_ALG); diff --git a/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/CustomObjectDeserializationTest.groovy index e5de114a0..a8d1b0d0f 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.parser().enableUnsecuredJws().build().parseClaimsJwt(jwtString) + Jwt jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().deserializeJsonWith(deserializer).build().parseClaimsJwt(jwtString) + jwt = Jwts.parser().enableUnsecured().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/JwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy index 90d7e3965..d994ea58f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy @@ -69,7 +69,7 @@ class JwtParserTest { String bad = base64Url('{"alg":"none"}') + '.' + base64Url(junkPayload) + '.' try { - Jwts.parser().enableUnsecuredJws().build().parse(bad) + Jwts.parser().enableUnsecured().build().parse(bad) fail() } catch (MalformedJwtException expected) { assertEquals 'Unable to read claims JSON: ' + junkPayload, expected.getMessage() @@ -129,7 +129,7 @@ class JwtParserTest { String bad = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(badSig) try { - Jwts.parser().enableUnsecuredJws().setSigningKey(randomKey()).build().parse(bad) + Jwts.parser().enableUnsecured().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() @@ -202,7 +202,7 @@ class JwtParserTest { @Test void testParseNullPayloadWithoutKey() { String compact = Jwts.builder().compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parse(compact) + def jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setClock(fixedClock).build().parse(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) + Jwt jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact) + Jwt jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(1).build().parse(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parseContentJwt(compact) + Jwts.parser().enableUnsecured().build().parseContentJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals e.getMessage(), 'Unprotected Claims JWTs are not supported.' @@ -368,7 +368,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject(subject).compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) assertEquals jwt.getPayload().getSubject(), subject } @@ -381,7 +381,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected content JWTs are not supported.', e.getMessage() @@ -427,7 +427,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(exp).compact() try { - Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) fail() } catch (PrematureJwtException e) { assertTrue e.getMessage().startsWith('JWT must not be accepted before ') @@ -480,7 +480,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setSigningKey(key).build().parseContentJws(compact) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseContentJws(compact) fail() } catch (UnsupportedJwtException e) { assertEquals 'Unprotected Claims JWTs are not supported.', e.getMessage() @@ -593,7 +593,7 @@ class JwtParserTest { String compact = Jwts.builder().setPayload(payload).compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(compact) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setSigningKey(key). + Jwts.parser().enableUnsecured().setSigningKey(key). build(). parseClaimsJws(compact) fail() @@ -1492,7 +1492,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() - Jwts.parser().enableUnsecuredJws().setClock(new FixedClock(beforeExpiry)).build().parse(compact) + Jwts.parser().enableUnsecured().setClock(new FixedClock(beforeExpiry)).build().parse(compact) } @Test @@ -1512,7 +1512,7 @@ class JwtParserTest { String compact = Jwts.builder().setSubject('Joe').setExpiration(expiry).compact() try { - Jwts.parser().enableUnsecuredJws().setClock(new DefaultClock()).build().parse(compact) + Jwts.parser().enableUnsecured().setClock(new DefaultClock()).build().parse(compact) fail() } catch (ExpiredJwtException e) { assertTrue e.getMessage().startsWith('JWT expired at ') @@ -1585,7 +1585,7 @@ class JwtParserTest { String jwtStr = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(sig) try { - Jwts.parser().enableUnsecuredJws().build().parse(jwtStr) + Jwts.parser().enableUnsecured().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 6506bcb91..6d27bcf20 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -166,7 +166,7 @@ class JwtsTest { String s = 'Hello JJWT' String cty = 'text/plain' String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecured().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().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecured().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().content(s.getBytes(StandardCharsets.UTF_8), cty).compact() - def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + def jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(jwt) + def token = Jwts.parser().enableUnsecured().build().parse(jwt) //noinspection GrEqualsBetweenInconvertibleTypes assert token.payload == claims @@ -230,7 +230,7 @@ class JwtsTest { String claims = Encoders.BASE64URL.encode(claimsJson.getBytes(StandardCharsets.UTF_8)) String compact = header + '.' + claims + '.' - def jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + def jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) assertEquals 'none', jwt.header.getAlgorithm() assertEquals 'joe', jwt.payload.getSubject() } @@ -274,7 +274,7 @@ class JwtsTest { @Test void testParseWithHeaderOnly() { String unsecuredJwt = base64Url("{\"alg\":\"none\"}") + ".." - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parse(unsecuredJwt) + Jwt jwt = Jwts.parser().enableUnsecured().build().parse(unsecuredJwt) assertEquals "none", jwt.getHeader().get("alg") } @@ -295,7 +295,7 @@ class JwtsTest { int i = compact.lastIndexOf('.') String missingSig = compact.substring(0, i + 1) try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(missingSig) + Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getIssuer() } @Test void testConvenienceSubject() { String compact = Jwts.builder().setSubject("Joe").compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getSubject() } @Test void testConvenienceAudience() { String compact = Jwts.builder().setAudience("You").compact() - Claims claims = Jwts.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + Claims claims = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build().parse(compact).payload as Claims + claims = Jwts.parser().enableUnsecured().build().parse(compact).payload as Claims assertNull claims.getId() } @@ -759,7 +759,7 @@ class JwtsTest { String notSigned = Jwts.builder().setSubject("Foo").compact() try { - Jwts.parser().enableUnsecuredJws().setSigningKey(key).build().parseClaimsJws(notSigned) + Jwts.parser().enableUnsecured().setSigningKey(key).build().parseClaimsJws(notSigned) fail('parseClaimsJws must fail for unsigned JWTs') } catch (UnsupportedJwtException expected) { assertEquals 'Unprotected Claims JWTs are not supported.', expected.message @@ -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.parser().enableUnsecuredJws().build().parseClaimsJwt(forged).getHeader().get('alg') + assertEquals 'none', Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().setSigningKey(key).build().parse(forged) + Jwts.parser().enableUnsecured().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 @@ -1354,7 +1354,7 @@ class JwtsTest { it instanceof Pbes2HsAkwAlgorithm })// as Collection> - Password key = Keys.forPassword("12345678".toCharArray()) + Password key = Keys.password("12345678".toCharArray()) for (KeyAlgorithm alg : algs) { @@ -1379,7 +1379,7 @@ class JwtsTest { @Test void testPasswordJweWithoutSpecifyingAlg() { - Password key = Keys.forPassword("12345678".toCharArray()) + Password key = Keys.password("12345678".toCharArray()) // encrypt: String jwe = Jwts.builder() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index 39b427b7c..3953c81d8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -23,6 +23,7 @@ import io.jsonwebtoken.impl.lang.Services import io.jsonwebtoken.impl.security.Randoms import io.jsonwebtoken.impl.security.TestKeys import io.jsonwebtoken.io.* +import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.security.* import org.junit.Before import org.junit.Test @@ -46,6 +47,30 @@ class DefaultJwtBuilderTest { this.builder = new DefaultJwtBuilder() } + @Test + void testDeleteClaim() { + builder.subject('Joe') + assertEquals 1, builder.claimsBuilder.size() + + builder.delete('sub') + assertEquals 0, builder.claimsBuilder.size() + } + + @Test + void testEmpty() { + builder.subject('Joe') + assertEquals 1, builder.claimsBuilder.size() + + byte[] content = Strings.utf8("Hello World") + builder.content(content) // can't set subject and content simultaneously + assertArrayEquals content, builder.content + + builder.empty() + + assertEquals 0, builder.claimsBuilder.size() + assertNull builder.content + } + @Test void testSetProvider() { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index 2cd07f6e7..a6ff06408 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -189,7 +189,7 @@ class DefaultJwtParserBuilderTest { builder.enableUnsecuredDecompression().build() fail() } catch (IllegalStateException ise) { - String expected = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecuredJws' " + "is also configured. Please read the JavaDoc of both features before enabling either " + "due to their security implications." + String expected = "'enableUnsecuredDecompression' is only relevant if 'enableUnsecured' " + "is also configured. Please read the JavaDoc of both features before enabling either " + "due to their security implications." assertEquals expected, ise.getMessage() } } @@ -199,7 +199,7 @@ class DefaultJwtParserBuilderTest { def codec = Jwts.ZIP.GZIP String jwt = Jwts.builder().compressWith(codec).setSubject('joe').compact() try { - builder.enableUnsecuredJws().build().parse(jwt) + builder.enableUnsecured().build().parse(jwt) fail() } catch (UnsupportedJwtException e) { String expected = String.format(DefaultJwtParser.UNPROTECTED_DECOMPRESSION_MSG, codec.getId()) @@ -211,7 +211,7 @@ class DefaultJwtParserBuilderTest { void testDecompressUnprotectedJwtEnabled() { def codec = Jwts.ZIP.GZIP String jws = Jwts.builder().compressWith(codec).setSubject('joe').compact() - def jwt = builder.enableUnsecuredJws().enableUnsecuredDecompression().build().parse(jws) + def jwt = builder.enableUnsecured().enableUnsecuredDecompression().build().parse(jws) assertEquals 'joe', ((Claims) jwt.getPayload()).getSubject() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy index 49a374649..13e624db2 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.parser().enableUnsecuredJws().build().parseClaimsJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecured().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').content(bytes).compact() - Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact) + Jwt jwt = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build() + def parser = Jwts.parser().enableUnsecured().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.parser().enableUnsecuredJws().build() + def parser = Jwts.parser().enableUnsecured().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/DefaultTextCodecFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultTextCodecFactoryTest.groovy deleted file mode 100644 index 95ff6211e..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultTextCodecFactoryTest.groovy +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2015 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 org.junit.Test -import org.junit.runner.RunWith -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.PowerMockRunner - -import static org.junit.Assert.* - -@RunWith(PowerMockRunner.class) -@PrepareForTest([System.class]) -class DefaultTextCodecFactoryTest { - - @Test - void testGetSystemProperty() { - def factory = new DefaultTextCodecFactory() - assertNotNull factory.getSystemProperty("java.version") - } - - @Test - void testIsAndroidByVmName() { - - def factory = new DefaultTextCodecFactory() { - @Override - protected String getSystemProperty(String key) { - return 'dalvik' - } - } - - assertTrue factory.getTextCodec() instanceof AndroidBase64Codec - } - - @Test - void testIsAndroidByNullVmName() { - - def factory = new DefaultTextCodecFactory() { - @Override - protected String getSystemProperty(String key) { - if (key == 'java.vm.name') return null; - return 'android' - } - } - - assertTrue factory.getTextCodec() instanceof AndroidBase64Codec - } - - @Test - void testIsAndroidByNullVmNameAndNullVendorName() { - - def factory = new DefaultTextCodecFactory() { - @Override - protected String getSystemProperty(String key) { - return null - } - } - - assertFalse factory.getTextCodec() instanceof AndroidBase64Codec - } -} 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 184466ae9..5850a98fb 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.parser().enableUnsecuredJws().enableUnsecuredDecompression().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown + Jwts.parser().enableUnsecured().enableUnsecuredDecompression().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown } /** diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy index 2c27bd0e3..87aa35cc9 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy @@ -42,7 +42,7 @@ class DefaultMacAlgorithmTest { */ @Test void testWithPasswordSpec() { - def password = Keys.forPassword(passwordChars) + def password = Keys.password(passwordChars) try { newAlg().digest(request(password)) } catch (InvalidKeyException expected) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy index 1cac539d2..e2bbd5846 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/PasswordSpecTest.groovy @@ -91,7 +91,7 @@ class PasswordSpecTest { @Test void testEquals() { - Password key2 = Keys.forPassword(PASSWORD) + Password key2 = Keys.password(PASSWORD) assertArrayEquals KEY.toCharArray(), key2.toCharArray() assertEquals KEY, key2 assertNotEquals KEY, new Object() @@ -99,14 +99,14 @@ class PasswordSpecTest { @Test void testIdentityEquals() { - Password key = Keys.forPassword(PASSWORD) + Password key = Keys.password(PASSWORD) assertTrue key.equals(key) assertNotEquals KEY, new Object() } @Test void testHashCode() { - Password key2 = Keys.forPassword(PASSWORD) + Password key2 = Keys.password(PASSWORD) assertArrayEquals KEY.toCharArray(), key2.toCharArray() assertEquals KEY.hashCode(), key2.hashCode() } @@ -114,7 +114,7 @@ class PasswordSpecTest { @Test void testToString() { assertEquals '', KEY.toString() - Password key2 = Keys.forPassword(PASSWORD) + Password key2 = Keys.password(PASSWORD) assertArrayEquals KEY.toCharArray(), key2.toCharArray() assertEquals KEY.toString(), key2.toString() } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy index b69c7dbdc..33513d5f8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithmTest.groovy @@ -29,7 +29,7 @@ import static org.junit.Assert.fail @SuppressWarnings('SpellCheckingInspection') class Pbes2HsAkwAlgorithmTest { - private static Password KEY = Keys.forPassword("12345678".toCharArray()) + private static Password KEY = Keys.password("12345678".toCharArray()) private static List ALGS = [Jwts.KEY.PBES2_HS256_A128KW, Jwts.KEY.PBES2_HS384_A192KW, Jwts.KEY.PBES2_HS512_A256KW] as List @@ -67,7 +67,7 @@ class Pbes2HsAkwAlgorithmTest { def password = 'hellowor'.toCharArray() def header = new DefaultJweHeader().pbes2Count(iterations) - def key = Keys.forPassword(password) + def key = Keys.password(password) def req = new DefaultKeyRequest(null, null, key, header, Jwts.ENC.A128GCM) int sum = 0 for (int i = 0; i < tries; i++) { 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 bee9f8dab..406419cf6 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy @@ -319,7 +319,7 @@ class RFC7517AppendixCTest { } } - Password key = Keys.forPassword(RFC_SHARED_PASSPHRASE.toCharArray()) + Password key = Keys.password(RFC_SHARED_PASSPHRASE.toCharArray()) String compact = Jwts.builder() .setPayload(RFC_JWK_JSON) 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 848736923..a9641edba 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy @@ -555,7 +555,7 @@ class RFC7520Section5Test { @Test void testSection5_3() { - def key = Keys.forPassword(FIGURE_96.toCharArray()) + def key = Keys.password(FIGURE_96.toCharArray()) String cty = 'jwk-set+json' int p2c = 8192 diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy index 7d3268e7b..bccd8107e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy @@ -276,7 +276,7 @@ class KeysTest { @Test void testForPassword() { def password = "whatever".toCharArray() - Password key = Keys.forPassword(password) + Password key = Keys.password(password) assertArrayEquals password, key.toCharArray() assertTrue key instanceof PasswordSpec } diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index 4ce2db266..eae15542d 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -222,7 +222,7 @@ public void testExampleJweECDHES() { public void testExampleJwePassword() { //DO NOT use this example password in a real app, it is well-known to password crackers String pw = "correct horse battery staple"; - Password password = Keys.forPassword(pw.toCharArray()); + Password password = Keys.password(pw.toCharArray()); // Choose the desired PBES2 key derivation algorithm: KeyAlgorithm alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_HS384... @@ -400,4 +400,15 @@ public void testExampleJwkToString() { String expected = "{kty=oct, k=, kid=HMAC key used in https://www.rfc-editor.org/rfc/rfc7515#appendix-A.1.1 example.}"; assert expected.equals(jwk.toString()); } + + @Test + public void testWhatever() { + Jwts.builder() + .header().keyId("foo").contentType("text/plain").and() + .subject("Joe").audience("You") + .signWith(Jwts.SIG.HS512.keyBuilder().build()) + .compact(); + + + } } From 6d61f86c640e810b3fb9d537b0f05cc4bfac25ff Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Sun, 6 Aug 2023 11:56:10 -0700 Subject: [PATCH 04/24] - Renamed MapMutator `set` methods to `add` methods to avoid Java setter full replacement idiom confusion (as opposed to add/append) --- .../main/java/io/jsonwebtoken/JwtBuilder.java | 80 ++++++++++--------- .../io/jsonwebtoken/JwtParserBuilder.java | 4 + api/src/main/java/io/jsonwebtoken/Jwts.java | 4 +- .../java/io/jsonwebtoken/lang/MapMutator.java | 4 +- .../jsonwebtoken/impl/DefaultJwtBuilder.java | 25 +++--- .../jsonwebtoken/impl/DefaultJwtParser.java | 2 +- .../impl/DefaultJwtParserBuilder.java | 2 +- .../impl/lang/DelegatingMapMutator.java | 4 +- .../impl/security/DefaultJwkParser.java | 2 +- .../impl/security/JwkConverter.java | 2 +- .../groovy/io/jsonwebtoken/JwtsTest.groovy | 8 +- .../impl/DefaultJwtBuilderTest.groovy | 19 +++-- .../impl/DefaultJwtHeaderBuilderTest.groovy | 12 +-- .../impl/DefaultJwtParserBuilderTest.groovy | 2 +- .../impl/DefaultMutableJweHeaderTest.groovy | 4 +- .../io/jsonwebtoken/impl/IdLocatorTest.groovy | 8 +- .../security/AbstractJwkBuilderTest.groovy | 16 ++-- .../impl/security/AbstractJwkTest.groovy | 12 +-- .../security/EcPublicJwkFactoryTest.groovy | 8 +- .../impl/security/EcdhKeyAlgorithmTest.groovy | 10 +-- .../impl/security/JwkSerializationTest.groovy | 6 +- .../impl/security/JwksTest.groovy | 6 +- .../impl/security/OctetJwksTest.groovy | 10 +-- .../security/RFC7516AppendixA1Test.groovy | 2 +- .../security/RFC7516AppendixA2Test.groovy | 2 +- .../security/RFC7516AppendixA3Test.groovy | 2 +- .../security/RFC7517AppendixA1Test.groovy | 4 +- .../security/RFC7517AppendixA2Test.groovy | 4 +- .../security/RFC7517AppendixA3Test.groovy | 4 +- .../impl/security/RFC7517AppendixBTest.groovy | 2 +- .../impl/security/RFC7518AppendixCTest.groovy | 2 +- .../impl/security/RFC8037AppendixATest.groovy | 8 +- .../security/RsaPrivateJwkFactoryTest.groovy | 2 +- .../impl/security/SecretJwkFactoryTest.groovy | 26 +++--- 34 files changed, 165 insertions(+), 143 deletions(-) diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 16e928115..ac08c7b6d 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -78,8 +78,8 @@ public interface JwtBuilder extends ClaimsMutator { * * .header() * .keyId("keyId") - * .set("aName", aValue) - * .set(myHeaderMap) + * .add("aName", aValue) + * .add(myHeaderMap) * // ... etc ... * .{@link JwtBuilder.Header#and() and()} //return back to the JwtBuilder * @@ -96,17 +96,17 @@ public interface JwtBuilder extends ClaimsMutator { * Per standard Java idiom 'setter' conventions, this method sets (and fully replaces) any existing header with the * specified name/value pairs. This method is identical to calling * {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#empty() empty()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}{@code .}{@link Header#and() and()}. + * {@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}{@code .}{@link Header#and() and()}. * *

    If you do not want to replace the existing header and only want to append to it, - * call {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)} instead.

    + * call {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)} instead.

    * * @param map the name/value pairs to set as (and potentially replace) the constructed JWT header. * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} * {@link io.jsonwebtoken.lang.MapMutator#empty() empty()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}{@code .}{@link Header#and() and()} (to replace - * all header parameters) or {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)} + * {@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}{@code .}{@link Header#and() and()} (to replace + * all header parameters) or {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)} * {@code .}{@link Header#and() and()} to only append the {@code map} entries. This * method will be removed before the 1.0 release. */ @@ -120,7 +120,7 @@ public interface JwtBuilder extends ClaimsMutator { * @param params the header name/value pairs to append to the header. * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}{@code .}{@link Header#and() and()}. This + * {@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}{@code .}{@link Header#and() and()}. This * method will be removed before the 1.0 release. */ @Deprecated @@ -133,7 +133,7 @@ public interface JwtBuilder extends ClaimsMutator { * @param value the header parameter value * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#set(Object, Object) set(name, value)}{@code .}{@link Header#and() and()}. This + * {@link io.jsonwebtoken.lang.MapMutator#add(Object, Object) add(name, value)}{@code .}{@link Header#and() and()}. This * method will be removed before the 1.0 release. */ @Deprecated @@ -160,8 +160,8 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder empty(); /** - * Sets the specified named parameter in the JWT Claims payload. A {@code null} value will remove the Claims - * entry. + * Sets the specified named parameter in the JWT Claims payload. A {@code null} or empty value will remove the + * Claims entry. * *

    This method is mutually exclusive of the {@link #content(byte[])} and {@link #content(byte[], String)} * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    @@ -172,7 +172,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override // for better/targeted JavaDoc - JwtBuilder set(String key, Object value); + JwtBuilder add(String key, Object value); /** * Sets the specified named entries in the JWT Claims payload. Any entry with an empty or null value will @@ -186,7 +186,7 @@ public interface JwtBuilder extends ClaimsMutator { */ @Override // for better/targeted JavaDoc - JwtBuilder set(Map m); + JwtBuilder add(Map m); /** * Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the @@ -198,9 +198,9 @@ public interface JwtBuilder extends ClaimsMutator { *
          * {@link #content(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));
    * - *

    If you want the JWT payload to be JSON, use the {@link #set(Map)} method instead.

    + *

    If you want the JWT payload to be JSON, use the {@link #add(Map)} method instead.

    * - *

    This method is mutually exclusive of the {@link #set(String, Object)} and {@link #set(Map)} + *

    This method is mutually exclusive of the {@link #add(String, Object)} and {@link #add(Map)} * methods. Either {@code set} or {@code content}/{@code payload} method variants may be used, but not both.

    * * @param payload the string used to set UTF-8-encoded bytes as the JWT payload. @@ -218,7 +218,7 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets the JWT payload to be the specified content byte array. * - *

    This method is mutually exclusive of the {@link #set(String, Object)} and {@link #set(Map)} + *

    This method is mutually exclusive of the {@link #add(String, Object)} and {@link #add(Map)} * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    * *

    Content Type Recommendation

    @@ -242,7 +242,7 @@ public interface JwtBuilder extends ClaimsMutator { * identifier to indicate the data format of the byte array. The JWT recipient can inspect the * {@code cty} value to determine how to convert the byte array to the final content type as desired. * - *

    This method is mutually exclusive of the {@link #set(String, Object)} and {@link #set(Map)} + *

    This method is mutually exclusive of the {@link #add(String, Object)} and {@link #add(Map)} * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    * *

    Compact Media Type Identifier

    @@ -262,8 +262,8 @@ public interface JwtBuilder extends ClaimsMutator { * ... * .build();
    * - *

    If you want the JWT payload to be JSON claims, use the {@link #setClaims(Claims)} or - * {@link #setClaims(java.util.Map)} methods instead.

    + *

    If you want the JWT payload to be JSON claims, use the {@link #claim(String, Object)} or + * {@link #claims(Map)} methods instead.

    * *

    Note that the content and claims properties are mutually exclusive - only one of the two may be used.

    * @@ -277,11 +277,11 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets (and replaces) any existing claims with the specified name/value pairs. This is a convenience method - * equivalent to calling {@link #empty()}{@code .}{@link #set(Map) set(map)}. + * equivalent to calling {@link #empty()}{@code .}{@link #add(Map) add(map)}. * *
      *
    • If you do not want to replace the existing claims and only want to append to them, call - * {@link #set(Map) set(map)} instead.
    • + * {@link #add(Map) add(map)} instead. *
    • If you do not want the JWT payload to be JSON claims and instead want it to be a byte array * representing any type of content, use the {@link #content(byte[], String)} method instead.
    • *
    @@ -291,23 +291,37 @@ public interface JwtBuilder extends ClaimsMutator { * @param claims the JWT claims to be set as the JWT payload. * @return the builder for method chaining. * @see #content(byte[], String) - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #empty()}{@code .}{@link #set(Map) set(map)}. This + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #empty()}{@code .}{@link #add(Map) add(map)}. This * method will be removed before the 1.0 release. */ JwtBuilder setClaims(Claims claims); /** - * Sets the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. If you do not - * want the JWT payload to be JSON claims and instead want it to be a byte array for any content, use the + * Sets (and replaces) the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. + * If you do not want the JWT payload to be JSON claims and instead want it to be a byte array for any content, use the * {@link #content(byte[])} or {@link #content(byte[], String)} methods instead. * *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * * @param claims the JWT Claims to be set as the JWT payload. * @return the builder for method chaining. + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #claims(Map)} method. */ + @Deprecated JwtBuilder setClaims(Map claims); + /** + * Named alias for {@link #add(Map)} that is likely to be easier to find when searching during code-completion. + *

    For example, when typing:

    + *
    +     * Jwts.builder().// press code-completion hotkeys to suggest methods and you type 'claim'
    + * + * @param claims the claims map to add to the JWT Claims payload. + * @return the builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder claims(Map claims); + /** * Adds/appends all given name/value pairs to the JSON Claims in the payload. * @@ -316,7 +330,7 @@ public interface JwtBuilder extends ClaimsMutator { * @param claims the JWT Claims to be added to the JWT payload. * @return the builder for method chaining. * @since 0.8 - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #set(Map)}. This method will be removed before the + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #add(Map)}. This method will be removed before the * 1.0 release. */ @Deprecated @@ -520,20 +534,10 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder id(String jti); /** - * Sets a custom JWT Claims parameter value. A {@code null} value will remove the property from the Claims. - * - *

    This is a convenience method that allows you to write code like this:

    - * - *
    -     * String jwt = Jwts.builder().claim("aName", aValue).compact();
    -     * 
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().set("aName", aValue).build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + * Named alias of {@link #add(String, Object)} which may be easier to find when searching during code completion. + *

    For example, when typing:

    + *
    +     * Jwts.builder().// press code-completion hotkeys to suggest methods and you type 'claim'
    * * @param name the JWT Claims property name * @param value the value to set for the specified Claims property name diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index 090957f81..a7177c0d9 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -355,6 +355,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the signature verification key to use to verify all encountered JWS digital signatures. * @return the parser builder for method chaining. + * @see #verifyWith(PublicKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder verifyWith(SecretKey key); @@ -375,6 +376,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the signature verification key to use to verify all encountered JWS digital signatures. * @return the parser builder for method chaining. + * @see #verifyWith(SecretKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder verifyWith(PublicKey key); @@ -396,6 +398,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. * @return the parser builder for method chaining. + * @see #decryptWith(PrivateKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder decryptWith(SecretKey key); @@ -416,6 +419,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. * @return the parser builder for method chaining. + * @see #decryptWith(SecretKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder decryptWith(PrivateKey key); diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java index 8c1ca43ac..807c49685 100644 --- a/api/src/main/java/io/jsonwebtoken/Jwts.java +++ b/api/src/main/java/io/jsonwebtoken/Jwts.java @@ -1041,7 +1041,7 @@ public static ClaimsBuilder claims() { /** *

    Deprecated since JJWT_RELEASE_VERSION in favor of - * {@code Jwts.}{@link #claims()}{@code .set(map).build()}. + * {@code Jwts.}{@link #claims()}{@code .add(map).build()}. * This method will be removed before 1.0.

    * *

    Returns a new {@link Claims} instance populated with the specified name/value pairs.

    @@ -1053,7 +1053,7 @@ public static ClaimsBuilder claims() { */ @Deprecated public static Claims claims(Map claims) { - return claims().set(claims).build(); + return claims().add(claims).build(); } /** diff --git a/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java b/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java index 869b897ff..98fa66746 100644 --- a/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java +++ b/api/src/main/java/io/jsonwebtoken/lang/MapMutator.java @@ -59,7 +59,7 @@ public interface MapMutator> { * @param value the value to set for the specified header parameter name * @return the mutator/builder for method chaining. */ - T set(K key, V value); + T add(K key, V value); /** * Sets the specified key/value pairs in the map, overwriting any existing entries with the same keys. @@ -71,5 +71,5 @@ public interface MapMutator> { * @param m the map to add * @return the mutator/builder for method chaining. */ - T set(Map m); + T add(Map m); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index f4c2f6a3a..544263d54 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -322,12 +322,17 @@ public JwtBuilder setClaims(Claims claims) { public JwtBuilder setClaims(Map claims) { Assert.notNull(claims, "Claims map cannot be null."); this.claimsBuilder.empty(); - return set(claims); + return add(claims); } @Override public JwtBuilder addClaims(Map claims) { - return set(claims); + return claims(claims); + } + + @Override + public JwtBuilder claims(Map claims) { + return add(claims); } @Override @@ -344,14 +349,14 @@ public JwtBuilder empty() { } @Override - public JwtBuilder set(String key, Object value) { - this.claimsBuilder.set(key, value); + public JwtBuilder add(String key, Object value) { + this.claimsBuilder.add(key, value); return this; } @Override - public JwtBuilder set(Map m) { - this.claimsBuilder.set(m); + public JwtBuilder add(Map m) { + this.claimsBuilder.add(m); return this; } @@ -434,7 +439,7 @@ public JwtBuilder id(String jti) { @Override public JwtBuilder claim(String name, Object value) { - return set(name, value); + return add(name, value); } @Override @@ -472,7 +477,7 @@ public String compact() { } if (!Objects.isEmpty(payload) && compressionAlgorithm != null) { payload = compressionAlgorithm.compress(payload); - this.headerBuilder.set(DefaultHeader.COMPRESSION_ALGORITHM.getId(), compressionAlgorithm.getId()); + this.headerBuilder.add(DefaultHeader.COMPRESSION_ALGORITHM.getId(), compressionAlgorithm.getId()); } if (jwe) { @@ -494,7 +499,7 @@ private String compact(byte[] payload) { // header = new DefaultJwsHeader(header); // } - this.headerBuilder.set(DefaultHeader.ALGORITHM.getId(), sigAlg.getId()); + this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), sigAlg.getId()); final io.jsonwebtoken.Header header = buildHeader(); @@ -540,7 +545,7 @@ private String encrypt(byte[] payload) { SecretKey cek = Assert.notNull(keyResult.getKey(), "KeyResult must return a content encryption key."); byte[] encryptedCek = Assert.notNull(keyResult.getPayload(), "KeyResult must return an encrypted key byte array, even if empty."); - this.headerBuilder.set(DefaultHeader.ALGORITHM.getId(), keyAlg.getId()); + this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), keyAlg.getId()); this.headerBuilder.put(DefaultJweHeader.ENCRYPTION_ALGORITHM.getId(), enc.getId()); final io.jsonwebtoken.Header header = buildHeader(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index b1ad063f8..4a1d5bebd 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -177,7 +177,7 @@ public class DefaultJwtParser implements JwtParser { this.keyLocator = Assert.notNull(keyLocator, "Key Locator cannot be null."); this.clock = Assert.notNull(clock, "Clock cannot be null."); this.allowedClockSkewMillis = allowedClockSkewMillis; - this.expectedClaims = Jwts.claims().set(expectedClaims); + this.expectedClaims = Jwts.claims().add(expectedClaims); this.base64UrlDecoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); this.deserializer = Assert.notNull(deserializer, "Deserializer cannot be null."); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index 81a1b92e0..c0b2d682a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -186,7 +186,7 @@ public JwtParserBuilder requireNotBefore(Date notBefore) { public JwtParserBuilder require(String claimName, Object value) { Assert.hasText(claimName, "claim name cannot be null or empty."); Assert.notNull(value, "The value cannot be null for claim name: " + claimName); - expectedClaims.set(claimName, value); + expectedClaims.add(claimName, value); return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java index b76c8445a..4a8cb0506 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/lang/DelegatingMapMutator.java @@ -41,13 +41,13 @@ public T empty() { } @Override - public T set(K key, V value) { + public T add(K key, V value) { put(key, value); return self(); } @Override - public T set(Map m) { + public T add(Map m) { putAll(m); return self(); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java index 346d2ccc4..86bdf8a88 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkParser.java @@ -62,6 +62,6 @@ public Jwk parse(String json) throws KeyException { builder.provider(this.provider); } - return builder.set(data).build(); + return builder.add(data).build(); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java b/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java index c1af66e4d..9955c7927 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java @@ -121,7 +121,7 @@ public T applyFrom(Object o) { throw new IllegalArgumentException(msg); } String skey = (String) key; - builder.set(skey, entry.getValue()); + builder.add(skey, entry.getValue()); } Jwk jwk = builder.build(); diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index 6d27bcf20..d0d358158 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -88,7 +88,7 @@ class JwtsTest { @Test void testHeaderWithMapArg() { - def header = Jwts.header().set([alg: "HS256"]).build() + def header = Jwts.header().add([alg: "HS256"]).build() assertTrue header instanceof DefaultJwsHeader assertEquals 'HS256', header.getAlgorithm() assertEquals 'HS256', header.alg @@ -1571,7 +1571,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().setClaims(claims).signWith(privateKey, alg).compact() + String jwt = Jwts.builder().add(claims).signWith(privateKey, alg).compact() def key = publicKey if (verifyWithPrivateKey) { @@ -1591,7 +1591,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().setClaims(claims).signWith(key, alg).compact() + String jwt = Jwts.builder().add(claims).signWith(key, alg).compact() def token = Jwts.parser().verifyWith(key).build().parse(jwt) @@ -1607,7 +1607,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().setClaims(claims).signWith(privateKey, alg).compact() + String jwt = Jwts.builder().add(claims).signWith(privateKey, alg).compact() def key = publicKey if (verifyWithPrivateKey) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index 3953c81d8..b1ac33377 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -157,7 +157,7 @@ class DefaultJwtBuilderTest { @Test void testSetHeader() { - def h = Jwts.header().set('foo', 'bar').build() + def h = Jwts.header().add('foo', 'bar').build() builder.setHeader(h) assertEquals h, builder.buildHeader() } @@ -185,16 +185,25 @@ class DefaultJwtBuilderTest { @Test void testSetClaims() { - Claims c = Jwts.claims().set('foo', 'bar').build() + Claims c = Jwts.claims().add('foo', 'bar').build() builder.setClaims(c) assertEquals c, builder.claimsBuilder } + @Test + void testSetClaimsMap() { + def m = [foo: 'bar'] + builder.setClaims(m) + assertEquals 1, builder.claimsBuilder.size() + assertTrue builder.claimsBuilder.containsKey('foo') + assertTrue builder.claimsBuilder.containsValue('bar') + } + @Test void testAddClaims() { def b = new DefaultJwtBuilder() def c = Jwts.claims([initial: 'initial']) - b.setClaims(c) + b.add(c) def c2 = [foo: 'bar', baz: 'buz'] b.addClaims(c2) assertEquals 'initial', b.claimsBuilder.get('initial') @@ -228,8 +237,8 @@ class DefaultJwtBuilderTest { @Test void testExistingClaimsAndSetClaim() { - Claims c = Jwts.claims().set('foo', 'bar').build() - builder.setClaims(c) + Claims c = Jwts.claims().add('foo', 'bar').build() + builder.add(c) assertEquals c, builder.claimsBuilder assertEquals builder.claimsBuilder.size(), 1 assertEquals c.size(), 1 diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy index 677717758..79422e0d5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy @@ -48,8 +48,8 @@ class DefaultJwtHeaderBuilderTest { private static void assertSymmetry(String propName, def val) { def name = Strings.capitalize(propName) switch (propName) { - case 'algorithm': builder.set('alg', val); break // no setter - case 'compressionAlgorithm': builder.set('zip', val); break // no setter + case 'algorithm': builder.add('alg', val); break // no setter + case 'compressionAlgorithm': builder.add('zip', val); break // no setter default: builder."$propName"(val) } header = builder.build() @@ -196,7 +196,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testPutAll() { def m = ['foo': 'bar', 'baz': 'bat'] - def header = builder.set(m).build() + def header = builder.add(m).build() assertEquals m, header } @@ -212,7 +212,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testClear() { def m = ['foo': 'bar', 'baz': 'bat'] - builder.set(m) + builder.add(m) builder.clear() def header = builder.build() assertTrue header.isEmpty() @@ -221,7 +221,7 @@ class DefaultJwtHeaderBuilderTest { @Test void testEmpty() { def m = ['foo': 'bar', 'baz': 'bat'] - def header = builder.set(m).empty().build() + def header = builder.add(m).empty().build() assertTrue header.isEmpty() } @@ -469,7 +469,7 @@ class DefaultJwtHeaderBuilderTest { assertEquals new DefaultHeader([foo: 'bar']), builder.build() // add JWS-required property: - builder.set(DefaultHeader.ALGORITHM.getId(), 'HS256') + builder.put(DefaultHeader.ALGORITHM.getId(), 'HS256') assertEquals new DefaultJwsHeader([foo: 'bar', alg: 'HS256']), builder.build() // add JWE required property: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index a6ff06408..44f620b51 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -161,7 +161,7 @@ class DefaultJwtParserBuilderTest { void testAddCompressionAlgorithms() { def codec = new TestCompressionCodec(id: 'test') def parser = builder.addCompressionAlgorithms([codec] as Set).build() - def header = Jwts.header().set('zip', codec.getId()).build() + def header = Jwts.header().add('zip', codec.getId()).build() assertSame codec, parser.zipAlgFn.locate(header) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy index 8b9085dad..3961f4564 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultMutableJweHeaderTest.groovy @@ -44,8 +44,8 @@ class DefaultMutableJweHeaderTest { private static void assertSymmetry(String propName, def val) { def name = Strings.capitalize(propName) switch (propName) { - case 'algorithm': header.set('alg', val); break // no setter - case 'compressionAlgorithm': header.set('zip', val); break // no setter + case 'algorithm': header.add('alg', val); break // no setter + case 'compressionAlgorithm': header.add('zip', val); break // no setter default: header."$propName"(val) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy index 63e8fb4ee..0e5f52419 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/IdLocatorTest.groovy @@ -46,7 +46,7 @@ class IdLocatorTest { @Test void unrequiredHeaderValueTest() { locator = new IdLocator(TEST_FIELD, registry, Collections.emptyList(), null) - def header = Jwts.header().set('a', 'b').build() + def header = Jwts.header().add('a', 'b').build() assertNull locator.apply(header) } @@ -63,7 +63,7 @@ class IdLocatorTest { @Test void unlocatableJwtHeaderInstanceTest() { - def header = Jwts.header().set('foo', 'foo').build() + def header = Jwts.header().add('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { @@ -74,7 +74,7 @@ class IdLocatorTest { @Test void unlocatableJwsHeaderInstanceTest() { - def header = Jwts.header().set('alg', 'HS256').set('foo', 'foo').build() + def header = Jwts.header().add('alg', 'HS256').add('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { @@ -85,7 +85,7 @@ class IdLocatorTest { @Test void unlocatableJweHeaderInstanceTest() { - def header = Jwts.header().set('enc', 'A256GCM').set('foo', 'foo').build() + def header = Jwts.header().add('enc', 'A256GCM').add('foo', 'foo').build() try { locator.apply(header) } catch (UnsupportedJwtException expected) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy index ab7dcfcf8..c0e41b3bc 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkBuilderTest.groovy @@ -55,20 +55,20 @@ class AbstractJwkBuilderTest { def foo = UUID.randomUUID() def bar = UUID.randomUUID().toString() //different type def m = [foo: foo, bar: bar] - def jwk = builder().set(m).build() + def jwk = builder().add(m).build() assertEquals foo, jwk.foo assertEquals bar, jwk.bar } @Test void testRemove() { - def jwk = builder().set('foo', 'bar').delete('foo').build() as Jwk + def jwk = builder().add('foo', 'bar').delete('foo').build() as Jwk assertNull jwk.get('foo') } @Test void testClear() { - def builder = builder().set('foo', 'bar') + def builder = builder().add('foo', 'bar') builder.clear() def jwk = builder.build() assertNull jwk.get('foo') @@ -76,7 +76,7 @@ class AbstractJwkBuilderTest { @Test void testEmpty() { - def jwk = builder().set('foo', 'bar').empty().build() as Jwk + def jwk = builder().add('foo', 'bar').empty().build() as Jwk assertNull jwk.get('foo') } @@ -91,7 +91,7 @@ class AbstractJwkBuilderTest { @Test void testAlgorithmByPut() { def alg = 'someAlgorithm' - def jwk = builder().set('alg', alg).build() //ensure direct put still is handled properly + def jwk = builder().add('alg', alg).build() //ensure direct put still is handled properly assertEquals alg, jwk.getAlgorithm() assertEquals alg, jwk.alg //test raw get via JWA member id } @@ -107,7 +107,7 @@ class AbstractJwkBuilderTest { @Test void testIdByPut() { def kid = UUID.randomUUID().toString() - def jwk = builder().set('kid', kid).build() + def jwk = builder().add('kid', kid).build() assertEquals kid, jwk.getId() assertEquals kid, jwk.kid //test raw get via JWA member id } @@ -127,7 +127,7 @@ class AbstractJwkBuilderTest { def a = UUID.randomUUID().toString() def b = UUID.randomUUID().toString() def set = [a, b] as Set - def jwk = builder().set('key_ops', set).build() + def jwk = builder().add('key_ops', set).build() assertEquals set, jwk.getOperations() assertEquals set, jwk.key_ops } @@ -137,7 +137,7 @@ class AbstractJwkBuilderTest { void testOperationsByPutSingleValue() { def a = UUID.randomUUID().toString() def set = [a] as Set - def jwk = builder().set('key_ops', a).build() // <-- put uses single raw value, not a set + def jwk = builder().add('key_ops', a).build() // <-- put uses single raw value, not a set assertEquals set, jwk.getOperations() // <-- still get a set assertEquals set, jwk.key_ops // <-- still get a set } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy index 760ccb600..88a3b7ba6 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractJwkTest.groovy @@ -146,20 +146,20 @@ class AbstractJwkTest { void testPrivateJwkHashCode() { assertEquals jwk.hashCode(), jwk.@context.hashCode() - def secretJwk1 = Jwks.builder().key(TestKeys.HS256).set('hello', 'world').build() - def secretJwk2 = Jwks.builder().key(TestKeys.HS256).set('hello', 'world').build() + def secretJwk1 = Jwks.builder().key(TestKeys.HS256).add('hello', 'world').build() + def secretJwk2 = Jwks.builder().key(TestKeys.HS256).add('hello', 'world').build() assertEquals secretJwk1.hashCode(), secretJwk1.@context.hashCode() assertEquals secretJwk2.hashCode(), secretJwk2.@context.hashCode() assertEquals secretJwk1.hashCode(), secretJwk2.hashCode() - def ecPrivJwk1 = Jwks.builder().key(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() - def ecPrivJwk2 = Jwks.builder().key(TestKeys.ES256.pair.private).set('hello', 'ecworld').build() + def ecPrivJwk1 = Jwks.builder().key(TestKeys.ES256.pair.private).add('hello', 'ecworld').build() + def ecPrivJwk2 = Jwks.builder().key(TestKeys.ES256.pair.private).add('hello', 'ecworld').build() assertEquals ecPrivJwk1.hashCode(), ecPrivJwk2.hashCode() assertEquals ecPrivJwk1.hashCode(), ecPrivJwk1.@context.hashCode() assertEquals ecPrivJwk2.hashCode(), ecPrivJwk2.@context.hashCode() - def rsaPrivJwk1 = Jwks.builder().key(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() - def rsaPrivJwk2 = Jwks.builder().key(TestKeys.RS256.pair.private).set('hello', 'rsaworld').build() + def rsaPrivJwk1 = Jwks.builder().key(TestKeys.RS256.pair.private).add('hello', 'rsaworld').build() + def rsaPrivJwk2 = Jwks.builder().key(TestKeys.RS256.pair.private).add('hello', 'rsaworld').build() assertEquals rsaPrivJwk1.hashCode(), rsaPrivJwk2.hashCode() assertEquals rsaPrivJwk1.hashCode(), rsaPrivJwk1.@context.hashCode() assertEquals rsaPrivJwk2.hashCode(), rsaPrivJwk2.@context.hashCode() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy index 3a628074a..b3b235063 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcPublicJwkFactoryTest.groovy @@ -28,7 +28,7 @@ class EcPublicJwkFactoryTest { @Test void testCurveMissing() { try { - Jwks.builder().set(['kty': 'EC']).build() + Jwks.builder().add(['kty': 'EC']).build() fail() } catch (MalformedKeyException expected) { String msg = "EC JWK is missing required 'crv' (Curve) value." @@ -39,7 +39,7 @@ class EcPublicJwkFactoryTest { @Test void testXMissing() { try { - Jwks.builder().set(['kty': 'EC', 'crv': 'P-256']).build() + Jwks.builder().add(['kty': 'EC', 'crv': 'P-256']).build() fail() } catch (MalformedKeyException expected) { String msg = "EC JWK is missing required 'x' (X Coordinate) value." @@ -51,7 +51,7 @@ class EcPublicJwkFactoryTest { void testYMissing() { try { String encoded = DefaultEcPublicJwk.X.applyTo(BigInteger.ONE) - Jwks.builder().set(['kty': 'EC', 'crv': 'P-256', 'x': encoded]).build() + Jwks.builder().add(['kty': 'EC', 'crv': 'P-256', 'x': encoded]).build() fail() } catch (MalformedKeyException expected) { String msg = "EC JWK is missing required 'y' (Y Coordinate) value." @@ -63,7 +63,7 @@ class EcPublicJwkFactoryTest { void testPointNotOnCurve() { try { String encoded = DefaultEcPublicJwk.X.applyTo(BigInteger.ONE) - Jwks.builder().set(['kty': 'EC', 'crv': 'P-256', 'x': encoded, 'y': encoded]).build() + Jwks.builder().add(['kty': 'EC', 'crv': 'P-256', 'x': encoded, 'y': encoded]).build() fail() } catch (InvalidKeyException expected) { String msg = "EC JWK x,y coordinates do not exist on elliptic curve 'P-256'. " + diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy index 7ba665c4d..ae2c9f637 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcdhKeyAlgorithmTest.groovy @@ -102,7 +102,7 @@ class EcdhKeyAlgorithmTest { // This uses curve P-384 instead, does not match private key, so it's unexpected: def jwk = Jwks.builder().key(TestKeys.ES384.pair.public as ECPublicKey).build() - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader DecryptionKeyRequest req = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, decryptionKey) @@ -137,7 +137,7 @@ class EcdhKeyAlgorithmTest { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.RS256.pair.private as PrivateKey // not an elliptic curve key, must fail def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) @@ -170,7 +170,7 @@ class EcdhKeyAlgorithmTest { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.ES256.pair.private as PrivateKey // valid key def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) @@ -190,7 +190,7 @@ class EcdhKeyAlgorithmTest { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.X25519.pair.private as PrivateKey // valid key def jwk = Jwks.builder().key(TestKeys.RS256.pair.public as RSAPublicKey).build() // invalid epk - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) @@ -210,7 +210,7 @@ class EcdhKeyAlgorithmTest { def alg = new EcdhKeyAlgorithm() PrivateKey key = TestKeys.X25519.pair.private as PrivateKey // valid key def jwk = Jwks.builder().key(TestKeys.X448.pair.public as PublicKey).build() // epk is not on X25519 - JweHeader header = Jwts.header().set('epk', jwk).build() as JweHeader + JweHeader header = Jwts.header().add('epk', jwk).build() as JweHeader def request = new DefaultDecryptionKeyRequest('test'.getBytes(), null, null, header, Jwts.ENC.A128GCM, key) try { alg.getDecryptionKey(request) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy index 07a7112f5..e2479e3c2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwkSerializationTest.groovy @@ -105,7 +105,7 @@ class JwkSerializationTest { //now ensure it deserializes back to a JWK: def map = deserializer.deserialize(data) as Map - def jwk2 = Jwks.builder().set(map).build() + def jwk2 = Jwks.builder().add(map).build() assertTrue jwk.k instanceof Supplier assertEquals jwk, jwk2 assertEquals jwk.k, jwk2.k @@ -136,7 +136,7 @@ class JwkSerializationTest { //now ensure it deserializes back to a JWK: def map = deserializer.deserialize(data) as Map - def jwk2 = Jwks.builder().set(map).build() + def jwk2 = Jwks.builder().add(map).build() assertTrue jwk.d instanceof Supplier assertEquals jwk, jwk2 assertEquals jwk.d, jwk2.d @@ -191,7 +191,7 @@ class JwkSerializationTest { //now ensure it deserializes back to a JWK: def map = deserializer.deserialize(data) as Map - def jwk2 = Jwks.builder().set(map).build() + def jwk2 = Jwks.builder().add(map).build() assertEquals(jwk, jwk2, privateFieldNames) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index be9fa5f6e..4521111b8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -206,7 +206,7 @@ class JwksTest { assertNotNull thumbprint //ensure base64url encoding/decoding of the thumbprint works: - def jwkFromValues = Jwks.builder().set(jwkFromKey).build() as PublicJwk + def jwkFromValues = Jwks.builder().add(jwkFromKey).build() as PublicJwk assertArrayEquals thumbprint, jwkFromValues."getX509CertificateSha${number}Thumbprint"() as byte[] } } @@ -335,7 +335,7 @@ class JwksTest { Map modified = new LinkedHashMap<>(jwk) modified.put('x', Converters.BIGINT.applyTo(x)) try { - Jwks.builder().set(modified).build() + Jwks.builder().add(modified).build() } catch (InvalidKeyException ike) { String expected = EcPublicJwkFactory.jwkContainsErrorMessage(jwk.crv as String, modified) assertEquals(expected, ike.getMessage()) @@ -345,7 +345,7 @@ class JwksTest { Map modified = new LinkedHashMap<>(jwk) modified.put('y', Converters.BIGINT.applyTo(y)) try { - Jwks.builder().set(modified).build() + Jwks.builder().add(modified).build() } catch (InvalidKeyException ike) { String expected = EcPublicJwkFactory.jwkContainsErrorMessage(jwk.crv as String, modified) assertEquals(expected, ike.getMessage()) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy index f07d4214e..0a80d1358 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy @@ -126,13 +126,13 @@ class OctetJwksTest { // test individual keys PublicJwk pubJwk = Jwks.builder().octetKey(pub).publicKeyUse("sig").build() - PublicJwk pubValuesJwk = Jwks.builder().set(pubJwk).build() as PublicJwk // ensure value map symmetry + PublicJwk pubValuesJwk = Jwks.builder().add(pubJwk).build() as PublicJwk // ensure value map symmetry assertEquals pubJwk, pubValuesJwk assertEquals pub, pubJwk.toKey() assertEquals pub, pubValuesJwk.toKey() PrivateJwk privJwk = Jwks.builder().octetKey(priv).publicKey(pub).publicKeyUse("sig").build() - PrivateJwk privValuesJwk = Jwks.builder().set(privJwk).build() as PrivateJwk // ensure value map symmetry + PrivateJwk privValuesJwk = Jwks.builder().add(privJwk).build() as PrivateJwk // ensure value map symmetry assertEquals privJwk, privValuesJwk assertEquals priv, privJwk.toKey() // we can't assert that priv.equals(privValuesJwk.toKey()) here because BouncyCastle uses PKCS8 V2 encoding @@ -160,7 +160,7 @@ class OctetJwksTest { // Test public-to-private builder coercion: privJwk = Jwks.builder().octetKey(pub).privateKey(priv).publicKeyUse('sig').build() - privValuesJwk = Jwks.builder().set(privJwk).build() as PrivateJwk // ensure value map symmetry + privValuesJwk = Jwks.builder().add(privJwk).build() as PrivateJwk // ensure value map symmetry assertEquals privJwk, privValuesJwk assertEquals priv, privJwk.toKey() // see comments above about material equality instead of encoding equality @@ -197,8 +197,8 @@ class OctetJwksTest { @Test void testUnknownCurveId() { def b = Jwks.builder() - .set(AbstractJwk.KTY.getId(), DefaultOctetPublicJwk.TYPE_VALUE) - .set(DefaultOctetPublicJwk.CRV.getId(), 'foo') + .add(AbstractJwk.KTY.getId(), DefaultOctetPublicJwk.TYPE_VALUE) + .add(DefaultOctetPublicJwk.CRV.getId(), 'foo') try { b.build() fail() 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 9f721f9a3..614fb091e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA1Test.groovy @@ -171,7 +171,7 @@ class RFC7516AppendixA1Test { assertArrayEquals TAG, decode(encodedTag) //read the RFC Test JWK to get the private key for decrypting - RsaPrivateJwk jwk = Jwks.builder().set(KEK_VALUES).build() as RsaPrivateJwk + RsaPrivateJwk jwk = Jwks.builder().add(KEK_VALUES).build() as RsaPrivateJwk RSAPrivateKey privKey = jwk.toKey() Jwe jwe = Jwts.parser().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) 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 0734932ac..055e3e073 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA2Test.groovy @@ -165,7 +165,7 @@ class RFC7516AppendixA2Test { assertArrayEquals TAG, decode(encodedTag) //read the RFC Test JWK to get the private key for decrypting - RsaPrivateJwk jwk = Jwks.builder().set(KEK_VALUES).build() as RsaPrivateJwk + RsaPrivateJwk jwk = Jwks.builder().add(KEK_VALUES).build() as RsaPrivateJwk RSAPrivateKey privKey = jwk.toKey() Jwe jwe = Jwts.parser().decryptWith(privKey).build().parseContentJwe(COMPLETE_JWE) 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 7ea4022fe..6f879e00b 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy @@ -105,7 +105,7 @@ class RFC7516AppendixA3Test { assertArrayEquals TAG, decode(encodedTag) //read the RFC Test JWK to get the private key for decrypting - SecretJwk jwk = Jwks.builder().set(KEK_VALUES).build() as SecretJwk + SecretJwk jwk = Jwks.builder().add(KEK_VALUES).build() as SecretJwk SecretKey kek = jwk.toKey() // test decryption per the RFC diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy index 6db0f079e..c27e1373a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA1Test.groovy @@ -58,7 +58,7 @@ class RFC7517AppendixA1Test { void test() { // asserts we can parse and verify RFC values def m = keys[0] - EcPublicJwk ecPubJwk = Jwks.builder().set(m).build() as EcPublicJwk + EcPublicJwk ecPubJwk = Jwks.builder().add(m).build() as EcPublicJwk assertTrue ecPubJwk.toKey() instanceof ECPublicKey assertEquals m.size(), ecPubJwk.size() assertEquals m.kty, ecPubJwk.getType() @@ -69,7 +69,7 @@ class RFC7517AppendixA1Test { assertEquals m.kid, ecPubJwk.getId() m = keys[1] - RsaPublicJwk rsaPublicJwk = Jwks.builder().set(m).build() as RsaPublicJwk + RsaPublicJwk rsaPublicJwk = Jwks.builder().add(m).build() as RsaPublicJwk assertTrue rsaPublicJwk.toKey() instanceof RSAPublicKey assertEquals m.size(), rsaPublicJwk.size() assertEquals m.kty, rsaPublicJwk.getType() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy index 69d2747b6..b3321944b 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA2Test.groovy @@ -88,7 +88,7 @@ class RFC7517AppendixA2Test { void test() { // asserts we can parse and verify RFC values def m = keys[0] - def jwk = Jwks.builder().set(m).build() as EcPrivateJwk + def jwk = Jwks.builder().add(m).build() as EcPrivateJwk def key = jwk.toKey() int fieldSize = key.params.curve.field.fieldSize assertTrue key instanceof ECPrivateKey @@ -105,7 +105,7 @@ class RFC7517AppendixA2Test { assertEquals m.kid, jwk.getId() m = keys[1] - jwk = Jwks.builder().set(m).build() as RsaPrivateJwk + jwk = Jwks.builder().add(m).build() as RsaPrivateJwk key = jwk.toKey() as RSAPrivateCrtKey assertNotNull key assertEquals m.size(), jwk.size() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy index 0658bd8fb..8537c01d8 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixA3Test.groovy @@ -51,7 +51,7 @@ class RFC7517AppendixA3Test { void test() { // asserts we can parse and verify RFC values def m = keys[0] - SecretJwk jwk = Jwks.builder().set(m).build() as SecretJwk + SecretJwk jwk = Jwks.builder().add(m).build() as SecretJwk def key = jwk.toKey() as SecretKey assertNotNull key assertEquals m.size(), jwk.size() @@ -61,7 +61,7 @@ class RFC7517AppendixA3Test { assertEquals m.k, encode(key) m = keys[1] - jwk = Jwks.builder().set(m).build() as SecretJwk + jwk = Jwks.builder().add(m).build() as SecretJwk key = jwk.toKey() as SecretKey assertNotNull key assertEquals m.size(), jwk.size() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy index 1bed3ac9a..fb094de9b 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixBTest.groovy @@ -66,7 +66,7 @@ class RFC7517AppendixBTest { @Test void test() { def m = jwkPairs - RsaPublicJwk jwk = Jwks.builder().set(m).build() as RsaPublicJwk + RsaPublicJwk jwk = Jwks.builder().add(m).build() as RsaPublicJwk RSAPublicKey key = jwk.toKey() assertNotNull key assertEquals m.size(), jwk.size() 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 b4c3b78a8..f312a5332 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7518AppendixCTest.groovy @@ -48,7 +48,7 @@ class RFC7518AppendixCTest { private static EcPrivateJwk readJwk(String json) { Map m = fromJson(json) - return Jwks.builder().set(m).build() as EcPrivateJwk + return Jwks.builder().add(m).build() as EcPrivateJwk } // https://www.rfc-editor.org/rfc/rfc7517.html#appendix-C.1 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 821d446a0..1d472c8ba 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy @@ -128,7 +128,7 @@ class RFC8037AppendixATest { def bobPrivKeyHex = '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb' //convert these two values to a JWK for convenient reference: - def bobPrivJwk = Jwks.builder().set([ + def bobPrivJwk = Jwks.builder().add([ kty: "OKP", crv: "X25519", kid: "Bob", x : bobPubKeyHex.decodeHex().encodeBase64Url() as String, d : bobPrivKeyHex.decodeHex().encodeBase64Url() as String @@ -144,7 +144,7 @@ class RFC8037AppendixATest { 0d bf 3a 0d 26 38 1a f4 eb a4 a9 8e aa 9b 4e 6a''') //Turn these two values into a Java KeyPair, and ensure it is used during key algorithm execution: - final OctetPrivateJwk ephemJwk = Jwks.builder().set([ + final OctetPrivateJwk ephemJwk = Jwks.builder().add([ kty: "OKP", crv: "X25519", x : rfcEphemeralPubKeyHex.decodeHex().encodeBase64Url() as String, @@ -215,7 +215,7 @@ class RFC8037AppendixATest { def bobPrivKeyHex = '1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d' //convert these two values to a JWK for convenient reference: - def bobPrivJwk = Jwks.builder().set([ + def bobPrivJwk = Jwks.builder().add([ kty: "OKP", crv: "X448", kid: "Dave", // "Dave" instead of expected "Bob" x : bobPubKeyHex.decodeHex().encodeBase64Url() as String, d : bobPrivKeyHex.decodeHex().encodeBase64Url() as String @@ -235,7 +235,7 @@ class RFC8037AppendixATest { 17 7f 80 e5 32 c4 1f a0''') //Turn these two values into a Java KeyPair, and ensure it is used during key algorithm execution: - final OctetPrivateJwk ephemJwk = Jwks.builder().set([ + final OctetPrivateJwk ephemJwk = Jwks.builder().add([ kty: "OKP", crv: "X448", x : rfcEphemeralPubKeyHex.decodeHex().encodeBase64Url() as String, diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy index 97389bdd1..ade8312fc 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaPrivateJwkFactoryTest.groovy @@ -200,7 +200,7 @@ class RsaPrivateJwkFactoryTest { def map = new LinkedHashMap(jwk) assertEquals 4, map.size() - def jwkFromValues = Jwks.builder().set(map).build() + def jwkFromValues = Jwks.builder().add(map).build() //ensure they're equal: assertEquals jwk, jwkFromValues diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy index 1a1379f1d..f047f2d25 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/SecretJwkFactoryTest.groovy @@ -33,21 +33,21 @@ class SecretJwkFactoryTest { @Test // if a jwk does not have an 'alg' or 'use' field, we default to an AES key void testNoAlgNoSigJcaName() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).build() as SecretJwk assertEquals 'AES', result.toKey().getAlgorithm() } @Test void testJwkHS256AlgSetsKeyJcaNameCorrectly() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS256').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('alg', 'HS256').build() as SecretJwk assertEquals 'HmacSHA256', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA256() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() - SecretJwk result = Jwks.builder().set(jwk).operations(["sign"] as Set).build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA256', result.toKey().getAlgorithm() @@ -56,14 +56,14 @@ class SecretJwkFactoryTest { @Test void testJwkHS384AlgSetsKeyJcaNameCorrectly() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() - SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS384').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('alg', 'HS384').build() as SecretJwk assertEquals 'HmacSHA384', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA384() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() - SecretJwk result = Jwks.builder().set(jwk).operations(["sign"] as Set).build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA384', result.toKey().getAlgorithm() @@ -72,14 +72,14 @@ class SecretJwkFactoryTest { @Test void testJwkHS512AlgSetsKeyJcaNameCorrectly() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() - SecretJwk result = Jwks.builder().set(jwk).set('alg', 'HS512').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('alg', 'HS512').build() as SecretJwk assertEquals 'HmacSHA512', result.toKey().getAlgorithm() } @Test void testSignOpSetsKeyHmacSHA512() { SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() - SecretJwk result = Jwks.builder().set(jwk).operations(["sign"] as Set).build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).operations(["sign"] as Set).build() as SecretJwk assertNull result.getAlgorithm() assertNull result.get('use') assertEquals 'HmacSHA512', result.toKey().getAlgorithm() @@ -90,7 +90,7 @@ class SecretJwkFactoryTest { SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'sig').build() as SecretJwk assertEquals 'HmacSHA256', result.toKey().getAlgorithm() // jcaName has been changed to a sig algorithm } @@ -99,7 +99,7 @@ class SecretJwkFactoryTest { SecretJwk jwk = Jwks.builder().key(TestKeys.HS384).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'sig').build() as SecretJwk assertEquals 'HmacSHA384', result.toKey().getAlgorithm() } @@ -108,7 +108,7 @@ class SecretJwkFactoryTest { SecretJwk jwk = Jwks.builder().key(TestKeys.HS512).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'sig').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'sig').build() as SecretJwk assertEquals 'HmacSHA512', result.toKey().getAlgorithm() } @@ -117,7 +117,7 @@ class SecretJwkFactoryTest { SecretJwk jwk = Jwks.builder().key(TestKeys.HS256).build() assertFalse jwk.containsKey('alg') assertFalse jwk.containsKey('use') - SecretJwk result = Jwks.builder().set(jwk).set('use', 'foo').build() as SecretJwk + SecretJwk result = Jwks.builder().add(jwk).add('use', 'foo').build() as SecretJwk assertEquals 'AES', result.toKey().getAlgorithm() } @@ -133,8 +133,8 @@ class SecretJwkFactoryTest { //now associate it with an alg identifier that is more than the key is capable of: try { - Jwks.builder().set(validJwk) - .set('alg', 'HS384') + Jwks.builder().add(validJwk) + .add('alg', 'HS384') .build() fail() } catch (MalformedKeyException expected) { From 0de225d778f752e7c87fce97e2d4c0f89372da0d Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Sun, 6 Aug 2023 14:26:52 -0700 Subject: [PATCH 05/24] - Removed MapMutator superinterface from ClaimsBuilder. Generic map mutation methods on the JwtBuilder are a little confusing. - Added JwtBuilder#claims() method that returns a Claims mutator with an and() method to get back to the JwtBuilder --- .../java/io/jsonwebtoken/ClaimsBuilder.java | 3 +- .../java/io/jsonwebtoken/ClaimsMutator.java | 4 +- .../main/java/io/jsonwebtoken/JwtBuilder.java | 384 ++++++------------ .../impl/DefaultClaimsBuilder.java | 83 +--- .../jsonwebtoken/impl/DefaultJwtBuilder.java | 95 ++--- .../impl/DelegatingClaimsMutator.java | 96 +++++ .../groovy/io/jsonwebtoken/JwtsTest.groovy | 10 +- .../impl/DefaultJwtBuilderTest.groovy | 29 +- .../jsonwebtoken/impl/DefaultJwtTest.groovy | 4 +- .../impl/security/RFC7520Section4Test.groovy | 8 +- .../impl/security/RFC7520Section5Test.groovy | 6 +- .../impl/security/RFC8037AppendixATest.groovy | 4 +- .../io/jsonwebtoken/all/JavaReadmeTest.java | 11 - 13 files changed, 291 insertions(+), 446 deletions(-) create mode 100644 impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java diff --git a/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java b/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java index 9877bad36..22e19932c 100644 --- a/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/ClaimsBuilder.java @@ -16,6 +16,7 @@ package io.jsonwebtoken; import io.jsonwebtoken.lang.Builder; +import io.jsonwebtoken.lang.MapMutator; /** * {@link Builder} used to create an immutable {@link Claims} instance. @@ -24,5 +25,5 @@ * @see Claims * @since JJWT_RELEASE_VERSION */ -public interface ClaimsBuilder extends ClaimsMutator, Builder { +public interface ClaimsBuilder extends MapMutator, ClaimsMutator, Builder { } diff --git a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java index 251d62cb1..0c5829ee1 100644 --- a/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ClaimsMutator.java @@ -15,8 +15,6 @@ */ package io.jsonwebtoken; -import io.jsonwebtoken.lang.MapMutator; - import java.util.Date; /** @@ -27,7 +25,7 @@ * @see io.jsonwebtoken.Claims * @since 0.2 */ -public interface ClaimsMutator> extends MapMutator { +public interface ClaimsMutator> { /** * Sets the JWT diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index ac08c7b6d..ae358e2e8 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -20,6 +20,7 @@ import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Encoder; import io.jsonwebtoken.io.Serializer; +import io.jsonwebtoken.lang.MapMutator; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.KeyAlgorithm; @@ -69,7 +70,7 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder random(SecureRandom secureRandom); /** - * Returns the {@link JwtBuilder.Header} to use to modify the constructed JWT's header name/value pairs as desired. + * Returns the {@code Header} to use to modify the constructed JWT's header name/value pairs as desired. * When finished, callers may return to JWT construction via the {@link JwtBuilder.Header#and() and()} method. * For example: * @@ -90,118 +91,77 @@ public interface JwtBuilder extends ClaimsMutator { * @return the {@link JwtBuilder.Header} to use for header construction. * @since JJWT_RELEASE_VERSION */ - JwtBuilder.Header header(); + Header header(); /** * Per standard Java idiom 'setter' conventions, this method sets (and fully replaces) any existing header with the - * specified name/value pairs. This method is identical to calling - * {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#empty() empty()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}{@code .}{@link Header#and() and()}. + * specified name/value pairs. This is a wrapper method for: + * + *
    +     * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()}
    * *

    If you do not want to replace the existing header and only want to append to it, - * call {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)} instead.

    + * call {@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link Header#and() and()} instead.

    * * @param map the name/value pairs to set as (and potentially replace) the constructed JWT header. * @return the builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#empty() empty()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}{@code .}{@link Header#and() and()} (to replace - * all header parameters) or {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)} - * {@code .}{@link Header#and() and()} to only append the {@code map} entries. This - * method will be removed before the 1.0 release. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()} + * (to replace all header parameters) or + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()} + * to only append the {@code map} entries. This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder setHeader(Map map); /** * Adds the specified name/value pairs to the header. Any parameter with an empty or null value will remove the - * entry from the header. + * entry from the header. This is a wrapper method for: + *
    +     * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()}
    * * @param params the header name/value pairs to append to the header. * @return the builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}{@code .}{@link Header#and() and()}. This - * method will be removed before the 1.0 release. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()}. + * This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder setHeaderParams(Map params); /** - * Adds the specified name/value pair to the header. + * Adds the specified name/value pair to the header. If the value is {@code null} or empty, the parameter will + * be removed from the header entirely. This is a wrapper method for: + *
    +     * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Header#and() and()}
    * * @param name the header parameter name * @param value the header parameter value * @return the builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #header()}{@code .} - * {@link io.jsonwebtoken.lang.MapMutator#add(Object, Object) add(name, value)}{@code .}{@link Header#and() and()}. This - * method will be removed before the 1.0 release. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Header#and() and()}. + * This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder setHeaderParam(String name, Object value); - /** - * Removes the specified named parameter from the JWT Claims payload. - * - * @param key the key for the map entry to remove. - * @return the builder for method chaining. - * @since JJWT_RELEASE_VERSION - */ - @Override - // for better/targeted JavaDoc - JwtBuilder delete(String key); - - /** - * Removes all Claims and payload {@link #content(byte[], String) content}. - * - * @return the builder for method chaining. - */ - @Override - // for better/targeted JavaDoc - JwtBuilder empty(); - - /** - * Sets the specified named parameter in the JWT Claims payload. A {@code null} or empty value will remove the - * Claims entry. - * - *

    This method is mutually exclusive of the {@link #content(byte[])} and {@link #content(byte[], String)} - * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    - * - * @param key the Claim name (map key) - * @param value the value to set for the specified claim name - * @return the builder for method chaining. - */ - @Override - // for better/targeted JavaDoc - JwtBuilder add(String key, Object value); - - /** - * Sets the specified named entries in the JWT Claims payload. Any entry with an empty or null value will - * remove the entry from the JWT Claims payload. - * - *

    This method is mutually exclusive of the {@link #content(byte[])} and {@link #content(byte[], String)} - * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    - * - * @param m map of Claim name/value pairs to apply to the JWT Claims payload. - * @return the builder for method chaining. - */ - @Override - // for better/targeted JavaDoc - JwtBuilder add(Map m); - /** * Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the * {@link Header#contentType(String) contentType} header value so the JWT recipient may inspect that value to * determine how to convert the byte array to the final data type as desired. In this case, consider using * {@link #content(byte[], String)} instead. * - *

    This is a convenience method that is effectively the same as:

    + *

    This is a wrapper method for:

    *
          * {@link #content(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));
    * - *

    If you want the JWT payload to be JSON, use the {@link #add(Map)} method instead.

    + *

    If you want the JWT payload to be JSON, use the {@link #claims()} method instead.

    * - *

    This method is mutually exclusive of the {@link #add(String, Object)} and {@link #add(Map)} - * methods. Either {@code set} or {@code content}/{@code payload} method variants may be used, but not both.

    + *

    This method is mutually exclusive of the {@link #claims()} and {@link #claim(String, Object)} + * methods. Either {@code claims} or {@code content}/{@code payload} method variants may be used, but not both.

    * * @param payload the string used to set UTF-8-encoded bytes as the JWT payload. * @return the builder for method chaining. @@ -218,8 +178,8 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets the JWT payload to be the specified content byte array. * - *

    This method is mutually exclusive of the {@link #add(String, Object)} and {@link #add(Map)} - * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    + *

    This method is mutually exclusive of the {@link #claims()} and {@link #claim(String, Object)} + * methods. Either {@code claims} or {@code content} method variants may be used, but not both.

    * *

    Content Type Recommendation

    * @@ -242,8 +202,8 @@ public interface JwtBuilder extends ClaimsMutator { * identifier to indicate the data format of the byte array. The JWT recipient can inspect the * {@code cty} value to determine how to convert the byte array to the final content type as desired. * - *

    This method is mutually exclusive of the {@link #add(String, Object)} and {@link #add(Map)} - * methods. Either {@code set} or {@code content} method variants may be used, but not both.

    + *

    This method is mutually exclusive of the {@link #claim(String, Object)} and {@link #claims()} + * methods. Either {@code claims} or {@code content} method variants may be used, but not both.

    * *

    Compact Media Type Identifier

    * @@ -263,7 +223,7 @@ public interface JwtBuilder extends ClaimsMutator { * .build();
    * *

    If you want the JWT payload to be JSON claims, use the {@link #claim(String, Object)} or - * {@link #claims(Map)} methods instead.

    + * {@link #claims()} methods instead.

    * *

    Note that the content and claims properties are mutually exclusive - only one of the two may be used.

    * @@ -276,276 +236,183 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder content(byte[] content, String cty) throws IllegalArgumentException; /** - * Sets (and replaces) any existing claims with the specified name/value pairs. This is a convenience method - * equivalent to calling {@link #empty()}{@code .}{@link #add(Map) add(map)}. + * Returns the JWT {@code Claims} payload to modify as desired. When finished, callers may + * return to {@code JwtBuilder} configuration via the {@link JwtBuilder.Claims#and() and()} method. + * For example: * - *
      - *
    • If you do not want to replace the existing claims and only want to append to them, call - * {@link #add(Map) add(map)} instead.
    • - *
    • If you do not want the JWT payload to be JSON claims and instead want it to be a byte array - * representing any type of content, use the {@link #content(byte[], String)} method instead.
    • - *
    + *
    +     * String jwt = Jwts.builder()
          *
    -     * 

    The content and claims properties are mutually exclusive - only one of the two may be used.

    + * .claims() + * .subject("Joe") + * .audience("you") + * .issuer("me") + * .add("customClaim", customValue) + * .add(myClaimsMap) + * // ... etc ... + * .{@link JwtBuilder.Claims#and() and()} //return back to the JwtBuilder * - * @param claims the JWT claims to be set as the JWT payload. - * @return the builder for method chaining. - * @see #content(byte[], String) - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #empty()}{@code .}{@link #add(Map) add(map)}. This - * method will be removed before the 1.0 release. + * .signWith(key) // resume JwtBuilder calls + * // ... etc ... + * .compact();
    + * + * @return the {@link JwtBuilder.Header} to use for header construction. + * @since JJWT_RELEASE_VERSION */ - JwtBuilder setClaims(Claims claims); + Claims claims(); /** - * Sets (and replaces) the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. - * If you do not want the JWT payload to be JSON claims and instead want it to be a byte array for any content, use the + * Sets (and replaces) the JWT Claims payload with the specified name/value pairs. If you do not want the JWT + * payload to be JSON claims and instead want it to be a byte array for any content, use the * {@link #content(byte[])} or {@link #content(byte[], String)} methods instead. * *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * * @param claims the JWT Claims to be set as the JWT payload. * @return the builder for method chaining. - * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #claims(Map)} method. + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #claims()} method. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder setClaims(Map claims); /** - * Named alias for {@link #add(Map)} that is likely to be easier to find when searching during code-completion. - *

    For example, when typing:

    - *
    -     * Jwts.builder().// press code-completion hotkeys to suggest methods and you type 'claim'
    + * Adds/appends all given name/value pairs to the JSON Claims in the payload. This is a convenience wrapper for: * - * @param claims the claims map to add to the JWT Claims payload. - * @return the builder for method chaining. - * @since JJWT_RELEASE_VERSION - */ - JwtBuilder claims(Map claims); - - /** - * Adds/appends all given name/value pairs to the JSON Claims in the payload. + *
    +     *{@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link Claims#and() and()}
    * *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * * @param claims the JWT Claims to be added to the JWT payload. * @return the builder for method chaining. * @since 0.8 - * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #add(Map)}. This method will be removed before the - * 1.0 release. + * @deprecated since JJWT_RELEASE_VERSION in favor of + * {@link #claims()}.{@link Claims#add(Map) add(Map)}.{@link Claims#and() and()}. + * This method will be removed before the 1.0 release. */ + @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated JwtBuilder addClaims(Map claims); /** - * Sets the JWT Claims
    - * iss (issuer) value. A {@code null} value will remove the property from the Claims. - * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getIssuer() issuer} field with the specified value. This allows you to write - * code like this:

    - * - *
    -     * String jwt = Jwts.builder().issuer("Joe").compact();
    -     * 
    + * Sets a JWT Claims parameter value. A {@code null} value will remove the property from the Claims. + * This is a convenience wrapper for: + *
    +     * {@link #claims()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Claims#and() and()}
    * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().issuer("Joe").build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + * @param name the JWT Claims property name + * @param value the value to set for the specified Claims property name + * @return the builder instance for method chaining. + * @since 0.2 + */ + JwtBuilder claim(String name, Object value); + + /** + * Sets the JWT Claims + * iss (issuer) value. A {@code null} value will remove the property from the Claims. + * This is a convenience wrapper for: + *
    +     * {@link #claims()}.{@link ClaimsMutator#issuer(String) issuer(iss)}.{@link Claims#and() and()}
    * * @param iss the JWT {@code iss} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc + @Override // for better/targeted JavaDoc JwtBuilder issuer(String iss); /** - * Sets the JWT Claims + * Sets the JWT Claims * sub (subject) value. A {@code null} value will remove the property from the Claims. - * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getSubject() subject} field with the specified value. This allows you to write - * code like this:

    - * + * This is a convenience wrapper for: *
    -     * String jwt = Jwts.builder().subject("Me").compact();
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().subject("Me").build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    - *

    if desired.

    + * {@link #claims()}.{@link ClaimsMutator#subject(String) subject(sub)}.{@link Claims#and() and()}
    * * @param sub the JWT {@code sub} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc + @Override // for better/targeted JavaDoc JwtBuilder subject(String sub); /** - * Sets the JWT Claims + * Sets the JWT Claims * aud (audience) value. A {@code null} value will remove the property from the Claims. - * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getAudience() audience} field with the specified value. This allows you to write - * code like this:

    - * - *
    -     * String jwt = Jwts.builder().audience("You").compact();
    -     * 
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().audience("You").build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + * This is a convenience wrapper for: + *
    +     * {@link #claims()}.{@link ClaimsMutator#audience(String) audience(aud)}.{@link Claims#and() and()}
    * * @param aud the JWT {@code aud} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc + @Override // for better/targeted JavaDoc JwtBuilder audience(String aud); /** - * Sets the JWT Claims + * Sets the JWT Claims * exp (expiration) value. A {@code null} value will remove the property from the Claims. * *

    A JWT obtained after this timestamp should not be used.

    * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getExpiration() expiration} field with the specified value. This allows - * you to write code like this:

    - * - *
    -     * String jwt = Jwts.builder().expiration(new Date(System.currentTimeMillis() + 3600000)).compact();
    -     * 
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().expiration(new Date(System.currentTimeMillis() + 3600000)).build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + *

    This is a convenience wrapper for:

    + *
    +     * {@link #claims()}.{@link ClaimsMutator#expiration(Date) expiration(exp)}.{@link Claims#and() and()}
    * * @param exp the JWT {@code exp} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc + @Override // for better/targeted JavaDoc JwtBuilder expiration(Date exp); /** - * Sets the JWT Claims + * Sets the JWT Claims * nbf (not before) value. A {@code null} value will remove the property from the Claims. * *

    A JWT obtained before this timestamp should not be used.

    * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getNotBefore() notBefore} field with the specified value. This allows - * you to write code like this:

    - * - *
    -     * String jwt = Jwts.builder().notBefore(new Date()).compact();
    -     * 
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().notBefore(new Date()).build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + *

    This is a convenience wrapper for:

    + *
    +     * {@link #claims()}.{@link ClaimsMutator#notBefore(Date) notBefore(nbf)}.{@link Claims#and() and()}
    * * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc - JwtBuilder notBefore(Date nbf); + @Override // for better/targeted JavaDoc + JwtBuilder setNotBefore(Date nbf); /** - * Sets the JWT Claims + * Sets the JWT Claims * iat (issued at) value. A {@code null} value will remove the property from the Claims. * *

    The value is the timestamp when the JWT was created.

    * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getIssuedAt() issuedAt} field with the specified value. This allows - * you to write code like this:

    - * - *
    -     * String jwt = Jwts.builder().issuedAt(new Date()).compact();
    -     * 
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().issuedAt(new Date()).build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + *

    This is a convenience wrapper for:

    + *
    +     * {@link #claims()}.{@link ClaimsMutator#issuedAt(Date) issuedAt(iat)}.{@link Claims#and() and()}
    * * @param iat the JWT {@code iat} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc + @Override // for better/targeted JavaDoc JwtBuilder issuedAt(Date iat); /** - * Sets the JWT Claims + * Sets the JWT Claims * jti (JWT ID) value. A {@code null} value will remove the property from the Claims. * *

    The value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a * manner that ensures that there is a negligible probability that the same value will be accidentally * assigned to a different data object. The ID can be used to prevent the JWT from being replayed.

    * - *

    This is a convenience method. It will first ensure a Claims instance exists as the JWT payload and then set - * the Claims {@link Claims#getId() id} field with the specified value. This allows - * you to write code like this:

    - * - *
    -     * String jwt = Jwts.builder().id(UUID.randomUUID().toString()).compact();
    -     * 
    - * - *

    instead of this:

    - *
    -     * Claims claims = Jwts.claims().id(UUID.randomUUID().toString()).build();
    -     * String jwt = Jwts.builder().setClaims(claims).compact();
    -     * 
    - *

    if desired.

    + *

    This is a convenience wrapper for:

    + *
    +     * {@link #claims()}.{@link ClaimsMutator#id(String) id(jti)}.{@link Claims#and() and()}
    * * @param jti the JWT {@code jti} (id) value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. - * @since 0.2 */ - @Override - //only for better/targeted JavaDoc + @Override // for better/targeted JavaDoc JwtBuilder id(String jti); - /** - * Named alias of {@link #add(String, Object)} which may be easier to find when searching during code completion. - *

    For example, when typing:

    - *
    -     * Jwts.builder().// press code-completion hotkeys to suggest methods and you type 'claim'
    - * - * @param name the JWT Claims property name - * @param value the value to set for the specified Claims property name - * @return the builder instance for method chaining. - * @since 0.2 - */ - JwtBuilder claim(String name, Object value); - /** * Signs the constructed JWT with the specified key using the key's recommended signature algorithm * as defined below, producing a JWS. If the recommended signature algorithm isn't sufficient for your needs, @@ -949,6 +816,23 @@ public interface JwtBuilder extends ClaimsMutator { */ String compact(); + /** + * Claims for use with a {@link JwtBuilder} that supports method chaining for + * standard JWT Claims parameters. Once claims are configured, the associated + * {@link JwtBuilder} may be obtained with the {@link #and() and()} method for continued configuration. + * + * @since JJWT_RELEASE_VERSION + */ + interface Claims extends MapMutator, ClaimsMutator { + + /** + * Returns the associated JwtBuilder for continued configuration. + * + * @return the associated JwtBuilder for continued configuration. + */ + JwtBuilder and(); + } + /** * Header for use with a {@link JwtBuilder} that supports method chaining for * standard JWT, JWS and JWE header parameters. Once header parameters are configured, the associated diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java index 2b53cdd2a..0b45ea73f 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java @@ -17,95 +17,16 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.ClaimsBuilder; -import io.jsonwebtoken.impl.lang.DelegatingMapMutator; -import io.jsonwebtoken.impl.lang.Field; - -import java.util.Date; /** * @since JJWT_RELEASE_VERSION */ @SuppressWarnings("unused") // used via reflection via Jwts.claims() -public final class DefaultClaimsBuilder extends DelegatingMapMutator +public final class DefaultClaimsBuilder extends DelegatingClaimsMutator implements ClaimsBuilder { public DefaultClaimsBuilder() { - super(new FieldMap(DefaultClaims.FIELDS)); - } - - ClaimsBuilder put(Field field, Object value) { - this.DELEGATE.put(field, value); - return self(); - } - - @Override - public ClaimsBuilder setIssuer(String iss) { - return issuer(iss); - } - - @Override - public ClaimsBuilder issuer(String iss) { - return put(DefaultClaims.ISSUER, iss); - } - - @Override - public ClaimsBuilder setSubject(String sub) { - return subject(sub); - } - - @Override - public ClaimsBuilder subject(String sub) { - return put(DefaultClaims.SUBJECT, sub); - } - - @Override - public ClaimsBuilder setAudience(String aud) { - return audience(aud); - } - - @Override - public ClaimsBuilder audience(String aud) { - return put(DefaultClaims.AUDIENCE, aud); - } - - @Override - public ClaimsBuilder setExpiration(Date exp) { - return expiration(exp); - } - - @Override - public ClaimsBuilder expiration(Date exp) { - return put(DefaultClaims.EXPIRATION, exp); - } - - @Override - public ClaimsBuilder setNotBefore(Date nbf) { - return notBefore(nbf); - } - - @Override - public ClaimsBuilder notBefore(Date nbf) { - return put(DefaultClaims.NOT_BEFORE, nbf); - } - - @Override - public ClaimsBuilder setIssuedAt(Date iat) { - return issuedAt(iat); - } - - @Override - public ClaimsBuilder issuedAt(Date iat) { - return put(DefaultClaims.ISSUED_AT, iat); - } - - @Override - public ClaimsBuilder setId(String jti) { - return id(jti); - } - - @Override - public ClaimsBuilder id(String jti) { - return put(DefaultClaims.JTI, jti); + super(); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 544263d54..428886829 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -15,8 +15,6 @@ */ package io.jsonwebtoken.impl; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ClaimsBuilder; import io.jsonwebtoken.JweHeader; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; @@ -38,6 +36,7 @@ import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Objects; +import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.AeadRequest; import io.jsonwebtoken.security.AeadResult; @@ -68,9 +67,9 @@ public class DefaultJwtBuilder implements JwtBuilder { protected Provider provider; protected SecureRandom secureRandom; - private final DefaultJwtBuilderHeader headerBuilder = new DefaultJwtBuilderHeader(this); + private final BuilderHeader headerBuilder = new BuilderHeader(this); - private final ClaimsBuilder claimsBuilder = new DefaultClaimsBuilder(); + private final BuilderClaims claimsBuilder = new BuilderClaims(this); protected byte[] content; @@ -97,6 +96,11 @@ public JwtBuilder.Header header() { return this.headerBuilder; } + @Override + public JwtBuilder.Claims claims() { + return this.claimsBuilder; + } + @Override public JwtBuilder provider(Provider provider) { this.provider = provider; @@ -146,21 +150,17 @@ public JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder) @Override public JwtBuilder setHeader(Map map) { - this.headerBuilder.clear(); - this.headerBuilder.putAll(map); - return this; + return this.headerBuilder.empty().add(map).and(); } @Override public JwtBuilder setHeaderParams(Map params) { - this.headerBuilder.putAll(params); - return this; + return this.headerBuilder.add(params).and(); } @Override public JwtBuilder setHeaderParam(String name, Object value) { - this.headerBuilder.put(name, value); - return this; + return this.headerBuilder.add(name, value).and(); } @SuppressWarnings("unchecked") // TODO: remove for 1.0 @@ -293,8 +293,7 @@ public JwtBuilder compressWith(CompressionAlgorithm alg) { @Override public JwtBuilder setPayload(String payload) { - byte[] bytes = payload != null ? payload.getBytes(StandardCharsets.UTF_8) : null; - return content(bytes); + return content(Strings.utf8(payload)); } @Override @@ -312,52 +311,20 @@ public JwtBuilder content(byte[] content, String cty) { return content(content); } - @Override - public JwtBuilder setClaims(Claims claims) { - Assert.notNull(claims, "Claims argument cannot be null."); - return setClaims((Map) claims); - } - @Override public JwtBuilder setClaims(Map claims) { Assert.notNull(claims, "Claims map cannot be null."); - this.claimsBuilder.empty(); - return add(claims); + return this.claimsBuilder.empty().add(claims).and(); } @Override public JwtBuilder addClaims(Map claims) { - return claims(claims); - } - - @Override - public JwtBuilder claims(Map claims) { - return add(claims); - } - - @Override - public JwtBuilder delete(String key) { - this.claimsBuilder.delete(key); - return this; + return claims().add(claims).and(); } @Override - public JwtBuilder empty() { - this.claimsBuilder.empty(); - this.content = null; - return this; - } - - @Override - public JwtBuilder add(String key, Object value) { - this.claimsBuilder.add(key, value); - return this; - } - - @Override - public JwtBuilder add(Map m) { - this.claimsBuilder.add(m); - return this; + public JwtBuilder claim(String name, Object value) { + return claims().add(name, value).and(); } @Override @@ -437,11 +404,6 @@ public JwtBuilder id(String jti) { return this; } - @Override - public JwtBuilder claim(String name, Object value) { - return add(name, value); - } - @Override public String compact() { @@ -569,12 +531,31 @@ private String encrypt(byte[] payload) { return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedTag; } - private static class DefaultJwtBuilderHeader extends DefaultJweHeaderBuilder
    - implements JwtBuilder.Header { + private static class BuilderClaims extends DelegatingClaimsMutator + implements JwtBuilder.Claims { + + private final JwtBuilder builder; + + private BuilderClaims(JwtBuilder builder) { + super(); + this.builder = builder; + } + + @Override + public JwtBuilder and() { + return this.builder; + } + + public io.jsonwebtoken.Claims build() { + return new DefaultClaims(this.DELEGATE); + } + } + + private static class BuilderHeader extends DefaultJweHeaderBuilder
    implements JwtBuilder.Header { private final JwtBuilder builder; - public DefaultJwtBuilderHeader(JwtBuilder builder) { + private BuilderHeader(JwtBuilder builder) { super(); this.builder = Assert.notNull(builder, "JwtBuilder cannot be null."); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java new file mode 100644 index 000000000..899ec1256 --- /dev/null +++ b/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java @@ -0,0 +1,96 @@ +package io.jsonwebtoken.impl; + +import io.jsonwebtoken.ClaimsMutator; +import io.jsonwebtoken.impl.lang.DelegatingMapMutator; +import io.jsonwebtoken.impl.lang.Field; +import io.jsonwebtoken.lang.MapMutator; + +import java.util.Date; + +/** + * @param subclass type + * @since JJWT_RELEASE_VERSION + */ +public class DelegatingClaimsMutator & ClaimsMutator> + extends DelegatingMapMutator + implements ClaimsMutator { + + protected DelegatingClaimsMutator() { + super(new FieldMap(DefaultClaims.FIELDS)); + } + + T put(Field field, Object value) { + this.DELEGATE.put(field, value); + return self(); + } + + @Override + public T setIssuer(String iss) { + return issuer(iss); + } + + @Override + public T issuer(String iss) { + return put(DefaultClaims.ISSUER, iss); + } + + @Override + public T setSubject(String sub) { + return subject(sub); + } + + @Override + public T subject(String sub) { + return put(DefaultClaims.SUBJECT, sub); + } + + @Override + public T setAudience(String aud) { + return audience(aud); + } + + @Override + public T audience(String aud) { + return put(DefaultClaims.AUDIENCE, aud); + } + + @Override + public T setExpiration(Date exp) { + return expiration(exp); + } + + @Override + public T expiration(Date exp) { + return put(DefaultClaims.EXPIRATION, exp); + } + + @Override + public T setNotBefore(Date nbf) { + return notBefore(nbf); + } + + @Override + public T notBefore(Date nbf) { + return put(DefaultClaims.NOT_BEFORE, nbf); + } + + @Override + public T setIssuedAt(Date iat) { + return issuedAt(iat); + } + + @Override + public T issuedAt(Date iat) { + return put(DefaultClaims.ISSUED_AT, iat); + } + + @Override + public T setId(String jti) { + return id(jti); + } + + @Override + public T id(String jti) { + return put(DefaultClaims.JTI, jti); + } +} diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index d0d358158..3ba0f2c83 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -198,7 +198,7 @@ class JwtsTest { def claims = [iss: 'joe', exp: later(), 'https://example.com/is_root': true] - String jwt = Jwts.builder().setClaims(claims).compact() + String jwt = Jwts.builder().claims().add(claims).and().compact() def token = Jwts.parser().enableUnsecured().build().parse(jwt) @@ -306,7 +306,7 @@ class JwtsTest { @Test void testWithInvalidCompressionAlgorithm() { try { - Jwts.builder().setHeaderParam(DefaultHeader.COMPRESSION_ALGORITHM.getId(), "CUSTOM").setId("andId").compact() + Jwts.builder().header().add('zip', 'CUSTOM').and().id("andId").compact() } catch (CompressionException e) { assertEquals "Unsupported compression algorithm 'CUSTOM'", e.getMessage() } @@ -1571,7 +1571,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().add(claims).signWith(privateKey, alg).compact() + String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact() def key = publicKey if (verifyWithPrivateKey) { @@ -1591,7 +1591,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().add(claims).signWith(key, alg).compact() + String jwt = Jwts.builder().claims().add(claims).and().signWith(key, alg).compact() def token = Jwts.parser().verifyWith(key).build().parse(jwt) @@ -1607,7 +1607,7 @@ class JwtsTest { def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) - String jwt = Jwts.builder().add(claims).signWith(privateKey, alg).compact() + String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact() def key = publicKey if (verifyWithPrivateKey) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index b1ac33377..c9576a182 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -23,7 +23,6 @@ import io.jsonwebtoken.impl.lang.Services import io.jsonwebtoken.impl.security.Randoms import io.jsonwebtoken.impl.security.TestKeys import io.jsonwebtoken.io.* -import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.security.* import org.junit.Before import org.junit.Test @@ -47,30 +46,6 @@ class DefaultJwtBuilderTest { this.builder = new DefaultJwtBuilder() } - @Test - void testDeleteClaim() { - builder.subject('Joe') - assertEquals 1, builder.claimsBuilder.size() - - builder.delete('sub') - assertEquals 0, builder.claimsBuilder.size() - } - - @Test - void testEmpty() { - builder.subject('Joe') - assertEquals 1, builder.claimsBuilder.size() - - byte[] content = Strings.utf8("Hello World") - builder.content(content) // can't set subject and content simultaneously - assertArrayEquals content, builder.content - - builder.empty() - - assertEquals 0, builder.claimsBuilder.size() - assertNull builder.content - } - @Test void testSetProvider() { @@ -203,7 +178,7 @@ class DefaultJwtBuilderTest { void testAddClaims() { def b = new DefaultJwtBuilder() def c = Jwts.claims([initial: 'initial']) - b.add(c) + b.claims().add(c) def c2 = [foo: 'bar', baz: 'buz'] b.addClaims(c2) assertEquals 'initial', b.claimsBuilder.get('initial') @@ -238,7 +213,7 @@ class DefaultJwtBuilderTest { @Test void testExistingClaimsAndSetClaim() { Claims c = Jwts.claims().add('foo', 'bar').build() - builder.add(c) + builder.claims().add(c) assertEquals c, builder.claimsBuilder assertEquals builder.claimsBuilder.size(), 1 assertEquals c.size(), 1 diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy index 13e624db2..89927a0e2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtTest.groovy @@ -29,7 +29,7 @@ class DefaultJwtTest { @Test void testToString() { - String compact = Jwts.builder().setHeaderParam('foo', 'bar').setAudience('jsmith').compact() + String compact = Jwts.builder().header().add('foo', 'bar').and().audience('jsmith').compact() Jwt jwt = Jwts.parser().enableUnsecured().build().parseClaimsJwt(compact) assertEquals 'header={foo=bar, alg=none},payload={aud=jsmith}', jwt.toString() } @@ -38,7 +38,7 @@ class DefaultJwtTest { void testByteArrayPayloadToString() { byte[] bytes = 'hello JJWT'.getBytes(StandardCharsets.UTF_8) String encoded = Encoders.BASE64URL.encode(bytes) - String compact = Jwts.builder().setHeaderParam('foo', 'bar').content(bytes).compact() + String compact = Jwts.builder().header().add('foo', 'bar').and().content(bytes).compact() Jwt jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact) assertEquals "header={foo=bar, alg=none},payload=$encoded" as String, jwt.toString() } 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 953f65525..84285174f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy @@ -258,7 +258,7 @@ class RFC7520Section4Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', kid) + .header().keyId(kid).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -304,7 +304,7 @@ class RFC7520Section4Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -349,7 +349,7 @@ class RFC7520Section4Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() @@ -387,7 +387,7 @@ class RFC7520Section4Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) .compact() 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 a9641edba..cf76d8177 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy @@ -473,7 +473,7 @@ class RFC7520Section5Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(key, alg, enc) .compact() @@ -537,7 +537,7 @@ class RFC7520Section5Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(key, alg, enc) .compact() @@ -660,7 +660,7 @@ class RFC7520Section5Test { String result = Jwts.builder() .serializeToJsonWith(serializer) // assert input, return RFC ordered string - .setHeaderParam('kid', jwk.getId()) + .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(encKey, alg, enc) .compact() 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 1d472c8ba..8a2773426 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC8037AppendixATest.groovy @@ -165,7 +165,7 @@ class RFC8037AppendixATest { // Create the test case JWE with the 'kid' header to ensure the output matches the RFC expected value: String jwe = Jwts.builder() - .setHeaderParam('kid', bobPrivJwk.getId()) + .header().keyId(bobPrivJwk.getId()).and() .setIssuer(issuer) .encryptWith(bobPrivJwk.toPublicJwk().toKey() as PublicKey, alg, Jwts.ENC.A128GCM) .compact() @@ -256,7 +256,7 @@ class RFC8037AppendixATest { // Create the test case JWE with the 'kid' header to ensure the output matches the RFC expected value: String jwe = Jwts.builder() - .setHeaderParam('kid', bobPrivJwk.getId()) //value will be "Dave" as noted above + .header().keyId(bobPrivJwk.getId()).and() //value will be "Dave" as noted above .setIssuer(issuer) .encryptWith(bobPrivJwk.toPublicJwk().toKey() as PublicKey, alg, Jwts.ENC.A256GCM) .compact() diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index eae15542d..fd4cb43dc 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -400,15 +400,4 @@ public void testExampleJwkToString() { String expected = "{kty=oct, k=, kid=HMAC key used in https://www.rfc-editor.org/rfc/rfc7515#appendix-A.1.1 example.}"; assert expected.equals(jwk.toString()); } - - @Test - public void testWhatever() { - Jwts.builder() - .header().keyId("foo").contentType("text/plain").and() - .subject("Joe").audience("You") - .signWith(Jwts.SIG.HS512.keyBuilder().build()) - .compact(); - - - } } From 8fbdc2137e489c1115779512faff420aa138b0ed Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Sun, 6 Aug 2023 15:00:46 -0700 Subject: [PATCH 06/24] - Added a convenience JwtBuilder#claims(Map) method (modern builder-style name) - Added a new JwtBuilder#encoder to eventually replace the now-deprecated JwtBuilder#base64UrlEncodeWith method - Added a new JwtBuilder#serializer to eventually replace the now-deprecated JwtBuilder#serializeToJsonWith method --- .../main/java/io/jsonwebtoken/JwtBuilder.java | 80 ++++++++++++++++--- .../jsonwebtoken/impl/DefaultJwtBuilder.java | 41 +++++++--- .../impl/DefaultJwtBuilderTest.groovy | 6 +- .../impl/security/RFC7517AppendixCTest.groovy | 2 +- .../impl/security/RFC7520Section4Test.groovy | 10 +-- .../impl/security/RFC7520Section5Test.groovy | 8 +- 6 files changed, 109 insertions(+), 38 deletions(-) diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index ae358e2e8..2226a33db 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -277,10 +277,12 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder setClaims(Map claims); /** - * Adds/appends all given name/value pairs to the JSON Claims in the payload. This is a convenience wrapper for: + * Adds/appends all given name/value pairs to the JSON Claims in the payload. + *

    + * This is a convenience wrapper for: * *

    -     *{@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link Claims#and() and()}
    + * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link Claims#and() and()}
    * *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    * @@ -296,8 +298,8 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder addClaims(Map claims); /** - * Sets a JWT Claims parameter value. A {@code null} value will remove the property from the Claims. - * This is a convenience wrapper for: + * Sets a JWT claim, overwriting any existing claim with the same name. A {@code null} or empty + * value will remove the claim entirely. This is a convenience wrapper for: *
          * {@link #claims()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Claims#and() and()}
    * @@ -308,6 +310,21 @@ public interface JwtBuilder extends ClaimsMutator { */ JwtBuilder claim(String name, Object value); + /** + * Adds all given name/value pairs to the JSON Claims in the payload, overwriting any existing claims + * with the same names. If any name has a {@code null} or empty value, that claim will be removed from the + * Claims. This is a convenience wrapper for: + *
    +     * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link Claims#and() and()}
    + * + *

    The content and claims properties are mutually exclusive - only one of the two may be used.

    + * + * @param claims the JWT Claims to be added to the JWT payload. + * @return the builder instance for method chaining + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder claims(Map claims); + /** * Sets the JWT Claims * iss (issuer) value. A {@code null} value will remove the property from the Claims. @@ -318,7 +335,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param iss the JWT {@code iss} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder issuer(String iss); /** @@ -331,7 +349,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param sub the JWT {@code sub} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder subject(String sub); /** @@ -344,7 +363,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param aud the JWT {@code aud} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder audience(String aud); /** @@ -360,7 +380,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param exp the JWT {@code exp} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder expiration(Date exp); /** @@ -376,7 +397,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder setNotBefore(Date nbf); /** @@ -392,7 +414,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param iat the JWT {@code iat} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder issuedAt(Date iat); /** @@ -410,7 +433,8 @@ public interface JwtBuilder extends ClaimsMutator { * @param jti the JWT {@code jti} (id) value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. */ - @Override // for better/targeted JavaDoc + @Override + // for better/targeted JavaDoc JwtBuilder id(String jti); /** @@ -782,17 +806,32 @@ public interface JwtBuilder extends ClaimsMutator { JwtBuilder compressWith(CompressionAlgorithm alg); /** - * Perform Base64Url encoding with the specified Encoder. + * Perform Base64Url encoding during {@link #compact() compaction} with the specified Encoder. * *

    JJWT uses a spec-compliant encoder that works on all supported JDK versions, but you may call this method * to specify a different encoder if you desire.

    * * @param base64UrlEncoder the encoder to use when Base64Url-encoding * @return the builder for method chaining. + * @see #encoder(Encoder) * @since 0.10.0 + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style + * {@link #encoder(Encoder)} method. */ JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder); + /** + * Perform Base64Url encoding during {@link #compact() compaction} with the specified Encoder. + * + *

    JJWT uses a spec-compliant encoder that works on all supported JDK versions, but you may call this method + * to specify a different encoder if necessar.

    + * + * @param encoder the encoder to use when Base64Url-encoding + * @return the builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder encoder(Encoder encoder); + /** * Performs Map-to-JSON serialization with the specified Serializer. This is used by the builder to convert * JWT/JWS/JWE headers and claims Maps to JSON strings as required by the JWT specification. @@ -804,9 +843,26 @@ public interface JwtBuilder extends ClaimsMutator { * @param serializer the serializer to use when converting Map objects to JSON strings. * @return the builder for method chaining. * @since 0.10.0 + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style + * {@link #serializer(Serializer)} method. */ + @Deprecated JwtBuilder serializeToJsonWith(Serializer> serializer); + /** + * Perform Map-to-JSON serialization with the specified Serializer. This is used by the builder to convert + * JWT/JWS/JWE headers and Claims Maps to JSON strings as required by the JWT specification. + * + *

    If this method is not called, JJWT will use whatever serializer 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 the {@link #compact()} method is invoked.

    + * + * @param serializer the serializer to use when converting Map objects to JSON strings. + * @return the builder for method chaining. + * @since JJWT_RELEASE_VERSION + */ + JwtBuilder serializer(Serializer> serializer); + /** * Actually builds the JWT and serializes it to a compact, URL-safe string according to the * JWT Compact Serialization diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 428886829..061a9dd8a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -88,7 +88,7 @@ public class DefaultJwtBuilder implements JwtBuilder { protected Function, byte[]> headerSerializer; protected Function, byte[]> claimsSerializer; - protected Encoder base64UrlEncoder = Encoders.BASE64URL; + protected Encoder encoder = Encoders.BASE64URL; protected CompressionAlgorithm compressionAlgorithm; @Override @@ -134,6 +134,11 @@ public byte[] apply(Map stringMap) { @Override public JwtBuilder serializeToJsonWith(final Serializer> serializer) { + return serializer(serializer); + } + + @Override + public JwtBuilder serializer(Serializer> serializer) { Assert.notNull(serializer, "Serializer cannot be null."); this.serializer = serializer; this.headerSerializer = wrap(serializer, "header"); @@ -142,9 +147,14 @@ public JwtBuilder serializeToJsonWith(final Serializer> serialize } @Override - public JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder) { - Assert.notNull(base64UrlEncoder, "base64UrlEncoder cannot be null."); - this.base64UrlEncoder = base64UrlEncoder; + public JwtBuilder base64UrlEncodeWith(Encoder encoder) { + return encoder(encoder); + } + + @Override + public JwtBuilder encoder(Encoder encoder) { + Assert.notNull(encoder, "encoder cannot be null."); + this.encoder = encoder; return this; } @@ -319,6 +329,11 @@ public JwtBuilder setClaims(Map claims) { @Override public JwtBuilder addClaims(Map claims) { + return claims(claims); + } + + @Override + public JwtBuilder claims(Map claims) { return claims().add(claims).and(); } @@ -430,7 +445,7 @@ public String compact() { if (this.serializer == null) { // try to find one based on the services available //noinspection unchecked - serializeToJsonWith(Services.loadFirst(Serializer.class)); + serializer(Services.loadFirst(Serializer.class)); } byte[] payload = content; @@ -466,8 +481,8 @@ private String compact(byte[] payload) { final io.jsonwebtoken.Header header = buildHeader(); byte[] headerBytes = headerSerializer.apply(header); - String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes); - String base64UrlEncodedBody = base64UrlEncoder.encode(payload); + String base64UrlEncodedHeader = encoder.encode(headerBytes); + String base64UrlEncodedBody = encoder.encode(payload); String jwt = base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedBody; @@ -477,7 +492,7 @@ private String compact(byte[] payload) { byte[] data = jwt.getBytes(StandardCharsets.US_ASCII); SecureRequest request = new DefaultSecureRequest<>(data, provider, secureRandom, key); byte[] signature = signFunction.apply(request); - String base64UrlSignature = base64UrlEncoder.encode(signature); + String base64UrlSignature = encoder.encode(signature); jwt += DefaultJwtParser.SEPARATOR_CHAR + base64UrlSignature; } else { // no signature (unprotected JWT), but must terminate w/ a period, see @@ -513,7 +528,7 @@ private String encrypt(byte[] payload) { final io.jsonwebtoken.Header header = buildHeader(); byte[] headerBytes = this.headerSerializer.apply(header); - final String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes); + final String base64UrlEncodedHeader = encoder.encode(headerBytes); byte[] aad = base64UrlEncodedHeader.getBytes(StandardCharsets.US_ASCII); AeadRequest encRequest = new DefaultAeadRequest(payload, provider, secureRandom, cek, aad); @@ -523,10 +538,10 @@ private String encrypt(byte[] payload) { byte[] ciphertext = Assert.notEmpty(encResult.getPayload(), "Encryption result must have non-empty ciphertext (result.getData())."); byte[] tag = Assert.notEmpty(encResult.getDigest(), "Encryption result must have a non-empty authentication tag."); - String base64UrlEncodedEncryptedCek = base64UrlEncoder.encode(encryptedCek); - String base64UrlEncodedIv = base64UrlEncoder.encode(iv); - String base64UrlEncodedCiphertext = base64UrlEncoder.encode(ciphertext); - String base64UrlEncodedTag = base64UrlEncoder.encode(tag); + String base64UrlEncodedEncryptedCek = encoder.encode(encryptedCek); + String base64UrlEncodedIv = encoder.encode(iv); + String base64UrlEncodedCiphertext = encoder.encode(ciphertext); + String base64UrlEncodedTag = encoder.encode(tag); return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedTag; } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index c9576a182..975e45ad5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -282,7 +282,7 @@ class DefaultJwtBuilderTest { throw new SerializationException('foo', new Exception()) } } - def b = new DefaultJwtBuilder().serializeToJsonWith(serializer) + def b = new DefaultJwtBuilder().serializer(serializer) try { b.setPayload('foo').compact() fail() @@ -426,8 +426,8 @@ class DefaultJwtBuilderTest { return null } } - def b = new DefaultJwtBuilder().base64UrlEncodeWith(encoder) - assertSame encoder, b.base64UrlEncoder + def b = new DefaultJwtBuilder().encoder(encoder) + assertSame encoder, b.encoder } @Test(expected = IllegalArgumentException) 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 406419cf6..338f59bc3 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy @@ -325,7 +325,7 @@ class RFC7517AppendixCTest { .setPayload(RFC_JWK_JSON) .header().contentType('jwk+json').pbes2Count(RFC_P2C).and() .encryptWith(key, alg, enc) - .serializeToJsonWith(serializer) //ensure header created as expected with an assertion serializer + .serializer(serializer) //ensure header created as expected with an assertion serializer .compact() assertEquals RFC_COMPACT_JWE, compact 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 84285174f..20dc16a59 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section4Test.groovy @@ -218,7 +218,7 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) @@ -257,7 +257,7 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(kid).and() .setPayload(FIGURE_7) .signWith(key, alg) @@ -303,7 +303,7 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) @@ -348,7 +348,7 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) @@ -386,7 +386,7 @@ class RFC7520Section4Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_7) .signWith(key, alg) 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 cf76d8177..98aa58110 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7520Section5Test.groovy @@ -472,7 +472,7 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(key, alg, enc) @@ -536,7 +536,7 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(key, alg, enc) @@ -597,7 +597,7 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().contentType(cty).pbes2Count(p2c).and() .setPayload(FIGURE_95) .encryptWith(key, alg, enc) @@ -659,7 +659,7 @@ class RFC7520Section5Test { } String result = Jwts.builder() - .serializeToJsonWith(serializer) // assert input, return RFC ordered string + .serializer(serializer) // assert input, return RFC ordered string .header().keyId(jwk.getId()).and() .setPayload(FIGURE_72) .encryptWith(encKey, alg, enc) From a7b8e3c6a93e812de79e030c2ecf7cac1e78ff42 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Sun, 6 Aug 2023 17:10:25 -0700 Subject: [PATCH 07/24] - Renamed JwtParserBuilder#base64UrlDecoder to just JwtParserBuilder#decoder - Renamed JwtParserBuilder#jsonDeserializer to just JwtParserBuilder#deserializer - Lots of README.md updates to reflect builder api name changes --- README.md | 484 ++++++++---------- .../main/java/io/jsonwebtoken/JwtBuilder.java | 3 +- .../io/jsonwebtoken/JwtParserBuilder.java | 8 +- .../impl/DefaultJwtParserBuilder.java | 16 +- 4 files changed, 236 insertions(+), 275 deletions(-) diff --git a/README.md b/README.md index 4ff87d64a..ec29d5a4d 100644 --- a/README.md +++ b/README.md @@ -698,7 +698,7 @@ import java.security.Key; // the key would be read from your application configuration instead. SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); -String jws = Jwts.builder().setSubject("Joe").signWith(key).compact(); +String jws = Jwts.builder().subject("Joe").signWith(key).compact(); ``` How easy was that!? @@ -755,27 +755,31 @@ Now that we've had a quickstart 'taste' of how to create and parse JWTs, let's c You create a JWT as follows: 1. Use the `Jwts.builder()` method to create a `JwtBuilder` instance. -2. Call builder methods to set the `payload` [content](#jwt-content) or [claims](#jwt-claims) and any - [`header` parameters](#jwt-header-builder) as desired. -3. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT, respectively. -4. Call the `compact()` method to produce the resulting compact JWT string. +2. Set any [`header` parameters](#jwt-header) as desired. +3. Call builder methods to set the `payload` [content](#jwt-content) or [claims](#jwt-claims). +4. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT, respectively. +5. Call the `compact()` method to produce the resulting compact JWT string. For example: ```java String jwt = Jwts.builder() // (1) - .setSubject("Bob") // (2) JSON Claims, or - //.setContent(aByteArray, "text/plain") // any byte[] content, with media type + .header() // (2) + .keyId("aKeyId") + .and() - .signWith(signingKey) // (3) if signing, or + .subject("Bob") // (3) JSON Claims, or + //.content(aByteArray, "text/plain") // any byte[] content, with media type + + .signWith(signingKey) // (4) if signing, or //.encryptWith(key, keyAlg, encryptionAlg) // if encrypting - .compact(); // (4) + .compact(); // (5) ``` -* The JWT `payload` may be either `byte[]` content (via `setContent`) _or_ JSON Claims -(such as `setSubject`, `setClaims`, etc), but not both. +* The JWT `payload` may be either `byte[]` content (via `content`) _or_ JSON Claims +(such as `subject`, `claims`, etc), but not both. * Either digital signatures (`signWith`) or encryption (`encryptWith`) may be used, but not both. > **Warning** @@ -792,91 +796,120 @@ relevant to the JWT `payload`. JJWT provides a number of ways of setting the en header parameters (name/value pairs). -#### Header Builder +#### JwtBuilder `header()` -The easiest and recommended way to set one or more JWT header parameters (name/value pairs) is to call -`JwtBuilder` `setHeader` with `Jwts.headerBuilder()`. For example: +The easiest and recommended way to set one or more JWT header parameters (name/value pairs) is to use the +`JwtBuilder`'s `header()` builder as desired, and then call its `and()` method to return back +to the `JwtBuilder` for further configuration. For example: ```java String jwt = Jwts.builder() - .setHeader(Jwts.headerBuilder() // <---- - .setKeyId("aKeyId") - .setX509Url(aUri) - .put("someName", "anyValue") - .putAll(anotherMap) + .header() // <---- + .keyId("aKeyId") + .x509Url(aUri) + .add("someName", anyValue) + .add(mapValues) // ... etc ... - ) - // ... etc ... + .and() // return back to the JwtBuilder + + .subject("Joe") // resume JwtBuilder calls... + // ... etc ... .compact(); ``` -In addition to type-safe setter methods, `Jwts.headerBuilder()` can also support arbitrary name/value pairs via -`put` and `putAll` as shown above. It can also support automatically calculating -X.509 thumbprints and other builder-style benefits that the other `JwtBuilder` `setHeader`* methods do not support. -For this reason, `Jwts.headerBuilder()` is the recommended way to set a JWT header and is preferred over the other -approaches listed next. +The `JwtBuilder` `header()` builder also supports automatically calculating X.509 thumbprints and other builder-style benefits that +a simple getter/setter object could not do. > **Note** -> +> > **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically > as needed. -#### Header Parameters - -Another way of setting header parameters is to call `JwtBuilder` `setHeaderParam` one or more times as needed: +##### Individual Header Paramters +In addition to type-safe builder methods, `JwtBuilder.header()` can also support arbitrary name/value pairs via the +`add` method: ```java -String jwt = Jwts.builder() +Jwts.builder().header() + + .add("aHeaderName", aValue) + // ... etc ... + .and() // return to the JwtBuilder + +// ... etc ... +``` - .setHeaderParam("kid", "myKeyId") - - // ... etc ... + +##### Header Parameter Map +The `add` method is also overloaded to support mutltiple header values in a `Map`: +```java +Jwts.builder().header() + + .add(multipleHeaderParamsMap) + // ... etc ... + .and() // return to the JwtBuilder + +// ... etc ... ``` -Each time `setHeaderParam` is called, it simply appends the key-value pair to an internal `Header` instance, -potentially overwriting any existing identically-named key/value pair. +#### Jwts HeaderBuilder -The downside with this approach is that you lose any type-safe setter methods or additional builder utility methods -available on the `Jwts.header()` builder such as `contentType`,`keyId`, `withX509Sha256Thumbprint`, etc. +Using `Jwts.builder().header()` shown above is the preferred way to modify a header when using the `JwtBuilder`. -> **Note** -> -> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically -> as needed. +However, if you would like to create a 'standalone' `Header` outside of the context of using the `JwtBuilder`, you +can use `Jwts.header()` instead to return an independent `Header` builder. For example: - -#### Header Map +```java +Header header = Jwts.header() -If you want to specify the entire header at once, and you don't want to use `Jwts.headerBuilder()`, you can use -`JwtBuilder` `setHeader(Map)` method instead: + .keyId("aKeyId") + .x509Url(aUri) + .add("someName", anyValue) + .add(mapValues) + // ... etc ... + + .build() // <---- not 'and()' +``` -```java +There are only two differences between `Jwts.header()` and `Jwts.builder().header()`: +1. `Jwts.header()` builds a 'detached' `Header` that is not associated with any particular JWT, whereas + `Jwts.builder().header()` always modifies the header of the immediate JWT being constructed by its parent + `JwtBuilder`. -Map header = getMyHeaderMap(); //implement me -String jwt = Jwts.builder() +2. `Jwts.header()` has a `build()` method to produce an explicit `Header` instance and + `Jwts.builder().header()` does not (it has an `and()` method instead) because its parent `JwtBuilder` will implicitly + create the header instance when necessary. - .setHeader(header) - + +A standalone header might be useful if you want to aggregate common header parameters in a single 'template' +instance so you don't have to repeat them for each `JwtBuilder` usage. Then this 'template' `Header` can be used to +populate `JwtBuilder` usages by just appending it to the `JwtBuilder` header, for example: + +```java +// perhaps somewhere in application configuration: +Header commonHeaders = Jwts.header() + .issuer("My Company") // ... etc ... + .build(); -``` +// -------------------------------- -> **Warning** -> -> Per standard Java `setter` idioms, `setHeader` is a _full replacement_ operation - it will replace any -> and all existing header name/value pairs. +// somewhere else during actual Jwt construction: +String jwt = Jwts.builder() -The downside with this approach is that you lose any type-safe setter methods or additional builder utility methods -available on the `Jwts.headerBuilder()` such as `setContentType`,`setKeyId`, `withX509Sha256Thumbprint`, etc. + .header() + .add(commonHeaders) // <---- + .add("specificHeader", specificValue) // jwt-specific headers... + .and() -> **Note** -> -> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically -> as needed. + .subject("whatever") + // ... etc ... + .compact(); +``` ### JWT Payload @@ -887,15 +920,15 @@ especially for representing identity claims. As a result, the `JwtBuilder` supports two distinct payload options: -* `setContent` if you would like the `payload` to be arbitrary byte array content, and -* `setClaims` (and supporting helper methods) if you would like the `payload` to be a JSON Claims `Object`. +* `content` if you would like the `payload` to be arbitrary byte array content, and +* `claims` (and supporting helper methods) if you would like the `payload` to be a JSON Claims `Object`. Either option may be used, but not both. Using both will cause `build()` to throw an exception. #### Arbitrary Content -You can set the JWT `payload` to be any arbitrary byte array content by using the `JwtBuilder` `setContent` method. +You can set the JWT `payload` to be any arbitrary byte array content by using the `JwtBuilder` `content` method. For example: ```java @@ -903,27 +936,27 @@ byte[] content = "Hello World".getBytes(StandardCharsets.UTF_8); String jwt = Jwts.builder() - .setContent(content, "text/plain") // <--- + .content(content, "text/plain") // <--- // ... etc ... .build(); ``` -Notice this particular example of `setContent` uses the two-argument convenience variant: +Notice this particular example of `content` uses the two-argument convenience variant: 1. The first argument is the actual byte content to set as the JWT payload 2. The second argument is a String identifier of an IANA Media Type. The second argument will cause the `JwtBuilder` to automatically set the `cty` (Content Type) header according to the JWT specification's [recommended compact format](https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.10). -This two-argument variant is typically recommended over the single-argument `setContent(byte[])` method because it +This two-argument variant is typically recommended over the single-argument `content(byte[])` method because it guarantees the JWT recipient can inspect the `cty` header to determine how to convert the `payload` byte array into a final form that the application can use. Without setting the `cty` header, the JWT recipient _must_ know via out-of-band (external) information how to process the byte array, which is usually less convenient and always requires code changes if the content format ever changes. -For these reasons, it is strongly recommended to use the two-argument `setContent` method variant. +For these reasons, it is strongly recommended to use the two-argument `content` method variant. #### JWT Claims @@ -934,16 +967,16 @@ this case, the `payload` is a 'claims' JSON `Object`, and JJWT supports this wit ##### Standard Claims -The `JwtBuilder` provides convenient setter methods for standard registered Claim names defined in the JWT +The `JwtBuilder` provides convenient builder methods for standard registered Claim names defined in the JWT specification. They are: -* `setIssuer`: sets the [`iss` (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1) -* `setSubject`: sets the [`sub` (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2) -* `setAudience`: sets the [`aud` (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3) -* `setExpiration`: sets the [`exp` (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4) -* `setNotBefore`: sets the [`nbf` (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5) -* `setIssuedAt`: sets the [`iat` (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6) -* `setId`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7) +* `issuer`: sets the [`iss` (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1) +* `subject`: sets the [`sub` (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2) +* `audience`: sets the [`aud` (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3) +* `expiration`: sets the [`exp` (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4) +* `notBefore`: sets the [`nbf` (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5) +* `issuedAt`: sets the [`iat` (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6) +* `id`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7) For example: @@ -951,13 +984,13 @@ For example: String jws = Jwts.builder() - .setIssuer("me") - .setSubject("Bob") - .setAudience("you") - .setExpiration(expiration) //a java.util.Date - .setNotBefore(notBefore) //a java.util.Date - .setIssuedAt(new Date()) // for example, now - .setId(UUID.randomUUID().toString()) //just an example id + .issuer("me") + .subject("Bob") + .audience("you") + .expiration(expiration) //a java.util.Date + .notBefore(notBefore) //a java.util.Date + .issuedAt(new Date()) // for example, now + .id(UUID.randomUUID().toString()) //just an example id /// ... etc ... ``` @@ -974,7 +1007,6 @@ String jws = Jwts.builder() .claim("hello", "world") // ... etc ... - ``` Each time `claim` is called, it simply appends the key-value pair to an internal `Claims` instance, potentially @@ -983,56 +1015,24 @@ overwriting any existing identically-named key/value pair. Obviously, you do not need to call `claim` for any [standard claim name](#jws-create-claims-standard), and it is recommended instead to call the standard respective type-safe setter method as this enhances readability. - -##### Claims Instance - -If you want to specify all claims at once, you can use the `Jwts.claims()` method and build up the claims -with it: - -```java - -Claims claims = Jwts.claims(); - -populate(claims); //implement me - -String jws = Jwts.builder() - - .setClaims(claims) - - // ... etc ... - -``` - -> **Warning** -> -> Per standard Java `setter` idioms, calling `setClaims` will fully replace all existing claim name/value -pairs with the specified values. If you want to add (append) claims in bulk, and not fully replace them, use the -> `JwtBuilder`'s `addClaims` method instead. - + + ##### Claims Map -If you want to specify all claims at once, and you don't want to use `Jwts.claims()`, you can use `JwtBuilder` -`setClaims(Map)` method instead: +If you want to specify all claims at once, you can use `JwtBuilder` `claims(Map)` method: ```java -Map claims = getMyClaimsMap(); //implement me +Map claims = getMyClaimsMap(); //implement me String jws = Jwts.builder() - .setClaims(claims) + .claims(claims) // ... etc ... - ``` -> **Warning** -> -> Per standard Java `setter` idioms, calling `setClaims` will fully replace all existing claim name/value -pairs with the specified values. If you want to add (append) claims in bulk, and not fully replace them, use the -> `JwtBuilder`'s `addClaims` method instead. - ### JWT Compression @@ -1048,7 +1048,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.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. +2. Optionally call `keyLocator`, `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. 5. Wrap the `parse*` call in a try/catch block in case parsing, signature verification, or decryption fails. @@ -1059,19 +1059,19 @@ For example: Jwt jwt; try { - jwt = Jwts.parser() // (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 - //.decryptWith(key) // or a static key used to decrypt all encrypted JWTs + .keyLocator(keyLocator) // (2) dynamically locate signing or encryption keys + //.verifyWith(key) // or a static key used to verify all signed JWTs + //.decryptWith(key) // or a static key used to decrypt all encrypted JWTs - .build() // (3) + .build() // (3) - .parse(compact); // (4) or parseClaimsJws, parseClaimsJwe, parseContentJws, etc + .parse(compact); // (4) or parseClaimsJws, parseClaimsJwe, parseContentJws, etc // we can safely trust the JWT -catch (JwtException ex) { // (5) +catch (JwtException ex) { // (5) // we *cannot* use the JWT as intended by its creator } @@ -1166,7 +1166,7 @@ received, at parse time, so you can't 'hard code' any verification or decryption #### Key Locator If you need to support dynamic key lookup when encountering JWTs, you'll need to implement -the `Locator` interface and specify an instance on the `JwtParserBuilder` via the `setKeyLocator` method. For +the `Locator` interface and specify an instance on the `JwtParserBuilder` via the `keyLocator` method. For example: ```java @@ -1174,7 +1174,7 @@ Locator keyLocator = getMyKeyLocator(); Jwts.parser() - .setKeyLocator(keyLocator) // <---- + .keyLocator(keyLocator) // <---- .build() // ... etc ... @@ -1214,7 +1214,7 @@ String keyId = getKeyId(key); //any mechanism you have to associate a key with a String jws = Jwts.builder() - .header().setKeyId(keyId).and() // <--- add `kid` header + .header().keyId(keyId).and() // <--- add `kid` header .signWith(key) // for JWS //.encryptWith(key, keyAlg, encryptionAlg) // for JWE @@ -1342,14 +1342,14 @@ obvious problems since `exp` and `nbf` are time-based assertions, and clock time assertions. You can account for these differences (usually no more than a few minutes) when parsing using the `JwtParserBuilder`'s -`setAllowedClockSkewSeconds`. For example: +`clockSkewSeconds`. For example: ```java long seconds = 3 * 60; //3 minutes Jwts.parser() - .setAllowedClockSkewSeconds(seconds) // <---- + .clockSkewSeconds(seconds) // <---- // ... etc ... .build() @@ -1362,14 +1362,14 @@ atomic clocks around the world. #### Custom Clock Support -If the above `setAllowedClockSkewSeconds` isn't sufficient for your needs, the timestamps created +If the above `clockSkewSeconds` isn't sufficient for your needs, the timestamps created during parsing for timestamp comparisons can be obtained via a custom time source. Call the `JwtParserBuilder`'s -`setClock` method with an implementation of the `io.jsonwebtoken.Clock` interface. For example: +`clock` method with an implementation of the `io.jsonwebtoken.Clock` interface. For example: ```java Clock clock = new MyClock(); -Jwts.parser().setClock(myClock) //... etc ... +Jwts.parser().clock(myClock) //... etc ... ``` The `JwtParser`'s default `Clock` implementation simply returns `new Date()` to reflect the time when parsing occurs, @@ -1578,7 +1578,7 @@ For example: ```java String jws = Jwts.builder() // (1) - .setSubject("Bob") // (2) + .subject("Bob") // (2) .signWith(key) // (3) <--- @@ -1693,7 +1693,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.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. +2. Call either [keyLocator](#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. 5. The entire call is wrapped in a try/catch block in case parsing or signature validation fails. We'll cover @@ -1705,9 +1705,9 @@ For example: Jws jws; try { - jws = Jwts.parser() // (1) + jws = Jwts.parser() // (1) - .setKeyLocator(keyLocator) // (2) dynamically lookup verification keys based on each JWS + .keyLocator(keyLocator) // (2) dynamically lookup verification keys based on each JWS //.verifyWith(key) // or a static key used to verify all encountered JWSs .build() // (3) @@ -2145,7 +2145,7 @@ For example: ```java String jwe = Jwts.builder() // (1) - .setSubject("Bob") // (2) + .subject("Bob") // (2) .encryptWith(key, keyAlgorithm, encryptionAlgorithm) // (3) @@ -2167,7 +2167,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.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. +2. Call either [keyLocator](#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. 6. Wrap the entire call is in a try/catch block in case decryption or integrity verification fails. @@ -2178,9 +2178,9 @@ For example: Jwe jwe; try { - jwe = Jwts.parser() // (1) + jwe = Jwts.parser() // (1) - .setKeyLocator(keyLocator) // (2) dynamically lookup decryption keys based on each JWE + .keyLocator(keyLocator) // (2) dynamically lookup decryption keys based on each JWE //.decryptWith(key) // or a static key used to decrypt all encountered JWEs .build() // (3) @@ -2261,7 +2261,7 @@ If a JWE is compressed using the `DEF` ([DEFLATE](https://www.rfc-editor.org/rfc after decryption, and there is nothing you need to configure. If, however, a custom compression algorithm was used to compress the JWE, you will need to tell the -`JwtParserBuilder` how to resolve your `CompressionCodec` to decompress the JWT. +`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT. Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing. @@ -2287,7 +2287,7 @@ seen for JWTs. You create a JWK as follows: 1. Use the `Jwks.builder()` method to create a `JwkBuilder` instance. -2. Call the `forKey` method with the Java key you wish to represent as a JWK. +2. Call the `key` method with the Java key you wish to represent as a JWK. 3. Call builder methods to set any additional key fields or metadata, such as a `kid` (Key ID), X509 Certificates, etc as desired. 4. Call the `build()` method to produce the resulting JWK. @@ -2295,13 +2295,13 @@ You create a JWK as follows: For example: ```java -SecretKey key = getSecretKey(); // or RSA or EC PublicKey or PrivateKey -SecretJwk = Jwts.builder().forKey(key) // (1) and (2) +SecretKey key = getSecretKey(); // or RSA or EC PublicKey or PrivateKey +SecretJwk = Jwks.builder().key(key) // (1) and (2) - .setId("mySecretKeyId") // (3) + .id("mySecretKeyId") // (3) // ... etc ... - .build(); // (4) + .build(); // (4) ``` @@ -2312,12 +2312,12 @@ You can read/parse a JWK by building a `JwkParser` and parsing the JWK JSON stri ```java String json = getJwkJsonString(); Jwk jwk = Jwks.parser() - //.provider(aJcaProvider) // optional - //.deserializeJsonWith(deserializer) // optional - .build() // create the parser - .parse(json); // actually parse the JSON + //.provider(aJcaProvider) // optional + //.deserializer(deserializer) // optional + .build() // create the parser + .parse(json); // actually parse the JSON -Key key = jwk.toKey(); // convert to a Java Key instance +Key key = jwk.toKey(); // convert to a Java Key instance ``` As shown above you can specify a custom JCA Provider or [JSON deserializer](#json) in the same way as the `JwtBuilder`. @@ -2344,9 +2344,9 @@ For example: ```java RSAPrivateKey rsaPrivateKey = getRSAPrivateKey(); // or ECPrivateKey -RsaPrivateJwk jwk = Jwks.builder().forKey(rsaPrivateKey) +RsaPrivateJwk jwk = Jwks.builder().key(rsaPrivateKey) - //.setPublicKey(rsaPublicKey) // optional, but recommended to avoid extra computation work + //.publicKey(rsaPublicKey) // optional, but recommended to avoid extra computation work .build(); ``` @@ -2359,22 +2359,22 @@ If you have a Java `KeyPair` instance, then you have both the public and private ```java KeyPair rsaKeyPair = getRSAKeyPair(); -RsaPrivateJwk rsaPrivJwk = Jwks.builder().forRsaKeyPair(rsaKeyPair).build(); +RsaPrivateJwk rsaPrivJwk = Jwks.builder().rsaKeyPair(rsaKeyPair).build(); KeyPair ecKeyPair = getECKeyPair(); -EcPrivateJwk ecPrivJwk = Jwks.builder().forEcKeyPair(ecKeyPair).build(); +EcPrivateJwk ecPrivJwk = Jwks.builder().ecKeyPair(ecKeyPair).build(); KeyPair edEcKeyPair = getEdECKeyPair(); -OctetPrivateJwk edEcPrivJwk = Jwks.builder().forOctetKeyPair(edEcKeyPair).build(); +OctetPrivateJwk edEcPrivJwk = Jwks.builder().octetKeyPair(edEcKeyPair).build(); ``` Note that: -* An exception will thrown when calling `forRsaKeyPair` if the specified `KeyPair` instance does not contain +* An exception will thrown when calling `rsaKeyPair` if the specified `KeyPair` instance does not contain `RSAPublicKey` and `RSAPrivateKey` instances. -* Similarly, an exception will be thrown when calling `forEcKeyPair` if +* Similarly, an exception will be thrown when calling `ecKeyPair` if the `KeyPair` instance does not contain `ECPublicKey` and `ECPrivateKey` instances. * Finally, an exception will be -thrown when calling `forOctetKeyPair` if the `KeyPair` instance does not contain X25519, X448, Ed25519, or Ed448 keys +thrown when calling `octetKeyPair` if the `KeyPair` instance does not contain X25519, X448, Ed25519, or Ed448 keys (introduced in JDK 11 and 15 or when using BouncyCastle). @@ -2384,7 +2384,7 @@ Because private JWKs contain public key material, you can always obtain the priv Java `PublicKey` or `KeyPair`. For example: ```java -RsaPrivateJwk privateJwk = Jwks.builder().forKey(rsaPrivateKey).build(); // or ecPrivateKey or edEcPrivateKey +RsaPrivateJwk privateJwk = Jwks.builder().key(rsaPrivateKey).build(); // or ecPrivateKey or edEcPrivateKey // Get the matching public JWK and/or PublicKey: RsaPublicJwk pubJwk = privateJwk.toPublicJwk(); // JWK instance @@ -2444,17 +2444,17 @@ String kid = jwk.thumbprint().toString(); jwk.setId(kid) // Jwks are immutable - there is no `setId` method ``` -Instead, you may use the `setIdFromThumbprint` methods on the `JwkBuilder` when creating a `Jwk`: +Instead, you may use the `idFromThumbprint` methods on the `JwkBuilder` when creating a `Jwk`: ```java -Jwk jwk = Jwks.builder().forKey(aKey) +Jwk jwk = Jwks.builder().key(aKey) - .setIdFromThumbprint() // or setIdFromThumbprint(hashAlgorithm) + .idFromThumbprint() // or idFromThumbprint(hashAlgorithm) .build(); ``` -Calling either `setIdFromThumbprint` method will ensure that calling `jwk.getId()` equals `thumbprint.toString()` +Calling either `idFromThumbprint` method will ensure that calling `jwk.getId()` equals `thumbprint.toString()` (which is `Encoders.BASE64URL.encode(thumbprint.toByteArray())`). @@ -2550,12 +2550,12 @@ example: ```java Jwts.builder() - .compressWith(CompressionCodecs.DEFLATE) // or CompressionCodecs.GZIP + .compressWith(Jwts.ZIP.DEF) // or Jwts.ZIP.GZIP // .. etc ... ``` -If you use the `DEFLATE` or `GZIP` Compression Codecs - that's it, you're done. You don't have to do anything during +If you use the `DEF`LATE or `GZIP` Compression Codecs - that's it, you're done. You don't have to do anything during parsing or configure the `JwtParserBuilder` for compression - JJWT will automatically decompress the payload as expected. @@ -2565,79 +2565,37 @@ expected. > vulnerability attacks (memory exhaustion, denial of service, etc.). -### Custom Compression Codec +### Custom Compression Algorithm -If the default `DEFLATE` or `GZIP` compression codecs are not suitable for your needs, you can create your own -`CompressionCodec` implementation(s). +If the default `DEF` or `GZIP` compression algorithms are not suitable for your needs, you can create your own +`CompressionAlgorithm` implementation(s). -Just as you would with the default codecs, you may specify that you want a JWT compressed by calling the `JwtBuilder`'s -`compressWith` method, supplying your custom implementation instance. When you call `compressWith`, the JWT `payload` -will be compressed with your algorithm, and the +Just as you would with the default algorithms, you may specify that you want a JWT compressed by calling the +`JwtBuilder`'s `compressWith` method, supplying your custom implementation instance. When you call `compressWith`, +the JWT `payload` will be compressed with your algorithm, and the [`zip` (Compression Algorithm)](https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3) -header will automatically be set to the value returned by your codec's `getId()` method as specified in the JWT -specification. +header will automatically be set to the value returned by your algorithm's `algorithm.getId()` method as +required by the JWT specification. -However, the `JwtParser` needs to be aware of this custom codec as well, so it can use it while parsing. You do this -by calling the `JwtParserBuilder`'s `addCompressionCodecs` method. For example: +However, the `JwtParser` needs to be aware of this custom algorithm as well, so it can use it while parsing. You do this +by calling the `JwtParserBuilder`'s `addCompressionAlgorithms` method. For example: ```java -CompressionCodec myCodec = new MyCompressionCodec(); +CompressionAlgorithm myAlg = new MyCompressionAlgorithm(); Jwts.parser() - .addCompressionCodecs(Collections.of(myCodec)) // <---- + .addCompressionAlgorithms(Collections.of(myAlg)) // <---- // .. etc ... ``` -This adds additional `CompressionCodec` implementations to the parser's overall total set of supported codecs (which -already includes the `DEFLATE` and `GZIP` codecs by default). - -The parser will then automatically check to see if the JWT `zip` header has been set to see if a compression codec -algorithm has been used to compress the JWT. If set, the parser will automatically look up your `CompressionCodec` by -its `getId()` value, and use it to decompress the JWT. - - -### Compression Codec Locator - -If for some reason the default `addCompressionCodecs` method and lookup-by-id behavior already supported by the -`JwtParserBuilder` is not sufficient for your needs, you can implement your own `Locator` to look -up the codec. - -Typically, a `Locator` implementation will inspect the `zip` header to find out what algorithm was -used and then return a codec instance that supports that algorithm. For example: - -```java -public class MyCompressionCodecLocator implements Locator { - - @Override - public CompressionCodec locate(Header header) { - - String id = header.getCompressionAlgorithm(); // 'zip' header - - CompressionCodec codec = getCompressionCodec(id); //implement me - - return codec; - } -} -``` - -Your custom `Locator` can then inspect any other header as necessary. - -You then provide your custom `Locator` to the `JwtParserBuilder` as follows: - -```java -Locator myCodecLocator = new MyCompressionCodecLocator(); - -Jwts.parser() - - .setCompressionCodecLocator(myCodecLocator) // <---- - - // .. etc ... -``` +This adds additional `CompressionAlgorithm` implementations to the parser's overall total set of supported compression +algorithms (which already includes the `DEF` and `GZIP` codecs by default). -Again, this is only necessary if the JWT-standard `zip` header lookup default behavior already supported by the -`JwtParser` is not sufficient. +The parser will then automatically check to see if the JWT `zip` header has been set to see if a compression +algorithm has been used to compress the JWT. If set, the parser will automatically look up your +`CompressionAlgorithm` by its `getId()` value, and use it to decompress the JWT. ## JSON Support @@ -2684,7 +2642,7 @@ Serializer> serializer = getMySerializer(); //implement me Jwts.builder() - .serializeToJsonWith(serializer) + .serializer(serializer) // ... etc ... ``` @@ -2696,7 +2654,7 @@ Deserializer> deserializer = getMyDeserializer(); //implement me Jwts.parser() - .deserializeJsonWith(deserializer) + .deserializer(deserializer) // ... etc ... ``` @@ -2744,7 +2702,7 @@ ObjectMapper objectMapper = getMyObjectMapper(); //implement me String jws = Jwts.builder() - .serializeToJsonWith(new JacksonSerializer(objectMapper)) + .serializer(new JacksonSerializer(objectMapper)) // ... etc ... ``` @@ -2756,7 +2714,7 @@ ObjectMapper objectMapper = getMyObjectMapper(); //implement me Jwts.parser() - .deserializeJsonWith(new JacksonDeserializer(objectMapper)) + .deserializer(new JacksonDeserializer(objectMapper)) // ... etc ... ``` @@ -2764,7 +2722,9 @@ Jwts.parser() #### Parsing of Custom Claim Types -By default JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte. If you need to deserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in through a constructor. For example: +By default JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte. If you need to +deserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in +through a constructor. For example: ```java new JacksonDeserializer(Maps.of("user", User.class).build()) @@ -2788,7 +2748,7 @@ The `User` object could be retrieved from the `user` claim with the following co ```java Jwts.parser() - .deserializeJsonWith(new JacksonDeserializer(Maps.of("user", User.class).build())) // <----- + .deserializer(new JacksonDeserializer(Maps.of("user", User.class).build())) // <----- .build() @@ -2863,7 +2823,7 @@ Gson gson = new GsonBuilder() String jws = Jwts.builder() - .serializeToJsonWith(new GsonSerializer(gson)) + .serializer(new GsonSerializer(gson)) // ... etc ... ``` @@ -2875,7 +2835,7 @@ Gson gson = getGson(); //implement me Jwts.parser() - .deserializeJsonWith(new GsonDeserializer(gson)) + .deserializer(new GsonDeserializer(gson)) // ... etc ... ``` @@ -3010,26 +2970,26 @@ information. ### Custom Base64 If for some reason you want to specify your own Base64Url encoder and decoder, you can use the `JwtBuilder` -`base64UrlEncodeWith` method to set the encoder: +`encoder` method to set the encoder: ```java -Encoder base64UrlEncoder = getMyBase64UrlEncoder(); //implement me +Encoder encoder = getMyBase64UrlEncoder(); //implement me String jws = Jwts.builder() - .base64UrlEncodeWith(base64UrlEncoder) + .encoder(encoder) // ... etc ... ``` -and the `JwtParserBuilder`'s `base64UrlDecodeWith` method to set the decoder: +and the `JwtParserBuilder`'s `decoder` method to set the decoder: ```java -Decoder base64UrlDecoder = getMyBase64UrlDecoder(); //implement me +Decoder decoder = getMyBase64UrlDecoder(); //implement me Jwts.parser() - .base64UrlDecodeWith(base64UrlEncoder) + .decoder(decoder) // ... etc ... ``` @@ -3075,7 +3035,7 @@ String message = "Hello World!"; byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWS: -String jws = Jwts.builder().setContent(content, "text/plain").signWith(key, alg).compact(); +String jws = Jwts.builder().content(content, "text/plain").signWith(key, alg).compact(); // Parse the compact JWS: content = Jwts.parser().verifyWith(key).build().parseContentJws(jws).getPayload(); @@ -3099,7 +3059,7 @@ SignatureAlgorithm alg = Jwts.SIG.RS512; //or PS512, RS256, etc... KeyPair pair = alg.keyPairBuilder().build(); // Bob creates the compact JWS with his RSA private key: -String jws = Jwts.builder().setSubject("Alice") +String jws = Jwts.builder().subject("Alice") .signWith(pair.getPrivate(), alg) // <-- Bob's RSA private key .compact(); @@ -3130,7 +3090,7 @@ SignatureAlgorithm alg = Jwts.SIG.ES512; //or ES256 or ES384 KeyPair pair = alg.keyPairBuilder().build(); // Bob creates the compact JWS with his EC private key: -String jws = Jwts.builder().setSubject("Alice") +String jws = Jwts.builder().subject("Alice") .signWith(pair.getPrivate(), alg) // <-- Bob's EC private key .compact(); @@ -3174,7 +3134,7 @@ SignatureAlgorithm alg = Jwts.SIG.Ed25519; //or Ed448 KeyPair pair = alg.keyPairBuilder().build(); // Bob creates the compact JWS with his Edwards Curve private key: -String jws = Jwts.builder().setSubject("Alice") +String jws = Jwts.builder().subject("Alice") .signWith(pair.getPrivate(), alg) // <-- Bob's Edwards Curve private key .compact(); @@ -3217,7 +3177,7 @@ String message = "Live long and prosper."; byte[] content = message.getBytes(StandardCharsets.UTF_8); // Create the compact JWE: -String jwe = Jwts.builder().setContent(content, "text/plain").encryptWith(key, enc).compact(); +String jwe = Jwts.builder().content(content, "text/plain").encryptWith(key, enc).compact(); // Parse the compact JWE: content = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe).getPayload(); @@ -3247,7 +3207,7 @@ KeyAlgorithm alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP o AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Bob creates the compact JWE with Alice's RSA public key so only she may read it: -String jwe = Jwts.builder().setAudience("Alice") +String jwe = Jwts.builder().audience("Alice") .encryptWith(pair.getPublic(), alg, enc) // <-- Alice's RSA public key .compact(); @@ -3282,7 +3242,7 @@ SecretKey key = alg.keyBuilder().build(); AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Create the compact JWE: -String jwe = Jwts.builder().setIssuer("me").encryptWith(key, alg, enc).compact(); +String jwe = Jwts.builder().issuer("me").encryptWith(key, alg, enc).compact(); // Parse the compact JWE: String issuer = Jwts.parser().decryptWith(key).build() @@ -3315,7 +3275,7 @@ KeyAlgorithm alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A19 AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Bob creates the compact JWE with Alice's EC public key so only she may read it: -String jwe = Jwts.builder().setAudience("Alice") +String jwe = Jwts.builder().audience("Alice") .encryptWith(pair.getPublic(), alg, enc) // <-- Alice's EC public key .compact(); @@ -3360,9 +3320,9 @@ KeyAlgorithm alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_H AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... // Create the compact JWE: -String jwe = Jwts.builder().setIssuer("me") +String jwe = Jwts.builder().issuer("me") // Optional work factor is specified in the header: - //.header().setPbes2Count(pbkdf2Iterations)).and() + //.header().pbes2Count(pbkdf2Iterations)).and() .encryptWith(password, alg, enc) .compact(); @@ -3380,7 +3340,7 @@ Example creating and parsing a secret JWK: ```java SecretKey key = Jwts.SIG.HS512.keyBuilder().build(); // or HS384 or HS256 -SecretJwk jwk = Jwks.builder().forKey(key).setIdFromThumbprint().build(); +SecretJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3400,7 +3360,7 @@ Example creating and parsing an RSA Public JWK: ```java RSAPublicKey key = (RSAPublicKey)Jwts.SIG.RS512.keyPairBuilder().build().getPublic(); -RsaPublicJwk jwk = Jwks.builder().forKey(key).setIdFromThumbprint().build(); +RsaPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3423,7 +3383,7 @@ KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate(); -RsaPrivateJwk privJwk = Jwks.builder().forKey(privKey).setIdFromThumbprint().build(); +RsaPrivateJwk privJwk = Jwks.builder().key(privKey).idFromThumbprint().build(); RsaPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -3446,7 +3406,7 @@ Example creating and parsing an Elliptic Curve Public JWK: ```java ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPairBuilder().build().getPublic(); -EcPublicJwk jwk = Jwks.builder().forKey(key).setIdFromThumbprint().build(); +EcPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3469,7 +3429,7 @@ KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); ECPublicKey pubKey = (ECPublicKey) pair.getPublic(); ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate(); -EcPrivateJwk privJwk = Jwks.builder().forKey(privKey).setIdFromThumbprint().build(); +EcPrivateJwk privJwk = Jwks.builder().key(privKey).idFromThumbprint().build(); EcPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); @@ -3494,7 +3454,7 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, ```java PublicKey key = Jwts.SIG.Ed25519.keyPairBuilder().build().getPublic(); -OctetPublicJwk jwk = builder().forOctetKey(key).setIdFromThumbprint().build(); +OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); assert key.equals(jwk.toKey()); @@ -3519,7 +3479,7 @@ KeyPair pair = Jwts.SIG.Ed448.keyPairBuilder().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); -OctetPrivateJwk privJwk = builder().forOctetKey(privKey).setIdFromThumbprint().build(); +OctetPrivateJwk privJwk = builder().octetKey(privKey).idFromThumbprint().build(); OctetPublicJwk pubJwk = privJwk.toPublicJwk(); assert privJwk.getId().equals(privJwk.thumbprint().toString()); diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 2226a33db..08ac6e1ca 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -256,7 +256,7 @@ public interface JwtBuilder extends ClaimsMutator { * // ... etc ... * .compact(); * - * @return the {@link JwtBuilder.Header} to use for header construction. + * @return the {@link JwtBuilder.Claims} to use for Claims construction. * @since JJWT_RELEASE_VERSION */ Claims claims(); @@ -818,6 +818,7 @@ public interface JwtBuilder extends ClaimsMutator { * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style * {@link #encoder(Encoder)} method. */ + @Deprecated JwtBuilder base64UrlEncodeWith(Encoder base64UrlEncoder); /** diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index a7177c0d9..20e0468bb 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -616,7 +616,7 @@ public interface JwtParserBuilder extends Builder { * @param base64UrlDecoder the decoder to use when Base64Url-decoding * @return the parser builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named - * {@link #base64UrlDecoder(Decoder)}. This method will be removed before the JJWT 1.0 release. + * {@link #decoder(Decoder)}. This method will be removed before the JJWT 1.0 release. */ @Deprecated JwtParserBuilder base64UrlDecodeWith(Decoder base64UrlDecoder); @@ -630,7 +630,7 @@ public interface JwtParserBuilder extends Builder { * @param base64UrlDecoder the decoder to use when Base64Url-decoding * @return the parser builder for method chaining. */ - JwtParserBuilder base64UrlDecoder(Decoder base64UrlDecoder); + JwtParserBuilder decoder(Decoder base64UrlDecoder); /** * Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is @@ -645,7 +645,7 @@ public interface JwtParserBuilder extends Builder { * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects. * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named - * {@link #jsonDeserializer(Deserializer)}. This method will be removed before the JJWT 1.0 release. + * {@link #deserializer(Deserializer)}. This method will be removed before the JJWT 1.0 release. */ @Deprecated JwtParserBuilder deserializeJsonWith(Deserializer> deserializer); @@ -663,7 +663,7 @@ public interface JwtParserBuilder extends Builder { * @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects. * @return the builder for method chaining. */ - JwtParserBuilder jsonDeserializer(Deserializer> deserializer); + JwtParserBuilder deserializer(Deserializer> deserializer); /** * Returns an immutable/thread-safe {@link JwtParser} created from the configuration from this JwtParserBuilder. diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index c0b2d682a..c67431ea6 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -85,7 +85,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder { @SuppressWarnings("deprecation") private CompressionCodecResolver compressionCodecResolver; - private Decoder base64UrlDecoder = Decoders.BASE64URL; + private Decoder decoder = Decoders.BASE64URL; private Deserializer> deserializer; @@ -118,11 +118,11 @@ public JwtParserBuilder provider(Provider provider) { @Override public JwtParserBuilder deserializeJsonWith(Deserializer> deserializer) { - return jsonDeserializer(deserializer); + return deserializer(deserializer); } @Override - public JwtParserBuilder jsonDeserializer(Deserializer> deserializer) { + public JwtParserBuilder deserializer(Deserializer> deserializer) { Assert.notNull(deserializer, "deserializer cannot be null."); this.deserializer = deserializer; return this; @@ -130,13 +130,13 @@ public JwtParserBuilder jsonDeserializer(Deserializer> deserializ @Override public JwtParserBuilder base64UrlDecodeWith(Decoder decoder) { - return base64UrlDecoder(decoder); + return decoder(decoder); } @Override - public JwtParserBuilder base64UrlDecoder(Decoder decoder) { - Assert.notNull(decoder, "base64UrlDecoder cannot be null."); - this.base64UrlDecoder = decoder; + public JwtParserBuilder decoder(Decoder decoder) { + Assert.notNull(decoder, "decoder cannot be null."); + this.decoder = decoder; return this; } @@ -371,7 +371,7 @@ public JwtParser build() { clock, allowedClockSkewMillis, expClaims, - base64UrlDecoder, + decoder, new JwtDeserializer<>(deserializer), compressionCodecResolver, extraZipAlgs, From 982bc8838b879f5134b30f612092a7dfab8ff3dd Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 11:31:38 -0700 Subject: [PATCH 08/24] minor code example formatting fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec29d5a4d..c644a2aa5 100644 --- a/README.md +++ b/README.md @@ -770,7 +770,7 @@ String jwt = Jwts.builder() // (1) .and() .subject("Bob") // (3) JSON Claims, or - //.content(aByteArray, "text/plain") // any byte[] content, with media type + //.content(aByteArray, "text/plain") // any byte[] content, with media type .signWith(signingKey) // (4) if signing, or //.encryptWith(key, keyAlg, encryptionAlg) // if encrypting From 1296310d280daf03034c48caeed9a6597a5b132e Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:21:53 -0700 Subject: [PATCH 09/24] minor readability changes --- README.md | 48 ++++++++++--------- .../jsonwebtoken/impl/DefaultJwtParser.java | 37 +++++++------- .../impl/DefaultJwtParserTest.groovy | 2 +- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index c644a2aa5..83224e441 100644 --- a/README.md +++ b/README.md @@ -149,13 +149,13 @@ enforcement. ## Features - * Fully functional on all JDKs and Android + * Fully functional on all Java 7+ JDKs and Android * Automatic security best practices and assertions * Easy to learn and read API * Convenient and readable [fluent](http://en.wikipedia.org/wiki/Fluent_interface) interfaces, great for IDE auto-completion to write code quickly * Fully RFC specification compliant on all implemented functionality, tested against RFC-specified test vectors - * Stable implementation with over 1,200+ tests and enforced 100% test code coverage. Every single method, statement + * Stable implementation with over 1,100+ tests and enforced 100% test code coverage. Every single method, statement and conditional branch variant in the entire codebase is tested and required to pass on every build. * Creating, parsing and verifying digitally signed compact JWTs (aka JWSs) with all standard JWS algorithms: @@ -796,7 +796,7 @@ relevant to the JWT `payload`. JJWT provides a number of ways of setting the en header parameters (name/value pairs). -#### JwtBuilder `header()` +#### JwtBuilder Header The easiest and recommended way to set one or more JWT header parameters (name/value pairs) is to use the `JwtBuilder`'s `header()` builder as desired, and then call its `and()` method to return back @@ -805,52 +805,54 @@ to the `JwtBuilder` for further configuration. For example: ```java String jwt = Jwts.builder() - .header() // <---- + .header() // <---- .keyId("aKeyId") .x509Url(aUri) .add("someName", anyValue) .add(mapValues) // ... etc ... - .and() // return back to the JwtBuilder + .and() // go back to the JwtBuilder - .subject("Joe") // resume JwtBuilder calls... + .subject("Joe") // resume JwtBuilder calls... // ... etc ... .compact(); ``` The `JwtBuilder` `header()` builder also supports automatically calculating X.509 thumbprints and other builder-style benefits that -a simple getter/setter object could not do. +a simple property getter/setter object would not do. > **Note** > -> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will set them automatically -> as needed. +> **Automatic Headers**: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will always set them +> automatically as needed. -##### Individual Header Paramters -In addition to type-safe builder methods, `JwtBuilder.header()` can also support arbitrary name/value pairs via the -`add` method: +##### Custom Header Parameters +In addition to type-safe builder methods for standard header parameters, `JwtBuilder.header()` can also support +arbitrary name/value pairs via the `add` method: ```java -Jwts.builder().header() +Jwts.builder() - .add("aHeaderName", aValue) - // ... etc ... - .and() // return to the JwtBuilder + .header() + .add("aHeaderName", aValue) + // ... etc ... + .and() // return to the JwtBuilder // ... etc ... ``` ##### Header Parameter Map -The `add` method is also overloaded to support mutltiple header values in a `Map`: +The `add` method is also overloaded to support multiple parameters in a `Map`: ```java -Jwts.builder().header() +Jwts.builder() - .add(multipleHeaderParamsMap) - // ... etc ... - .and() // return to the JwtBuilder + .header() + .add(multipleHeaderParamsMap) + // ... etc ... + .and() // return to the JwtBuilder // ... etc ... ``` @@ -1009,7 +1011,7 @@ String jws = Jwts.builder() // ... etc ... ``` -Each time `claim` is called, it simply appends the key-value pair to an internal `Claims` instance, potentially +Each time `claim` is called, it simply appends the key-value pair to an internal `Claims` builder, potentially overwriting any existing identically-named key/value pair. Obviously, you do not need to call `claim` for any [standard claim name](#jws-create-claims-standard), and it is @@ -1020,7 +1022,7 @@ recommended instead to call the standard respective type-safe setter method as t ##### Claims Map -If you want to specify all claims at once, you can use `JwtBuilder` `claims(Map)` method: +If you want to add multiple claims at once, you can use `JwtBuilder` `claims(Map)` method: ```java diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index 4a1d5bebd..e10fbbff7 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -95,18 +95,17 @@ public class DefaultJwtParser implements JwtParser { "the compact JWE string is missing the required signature."; public static final String MISSING_JWE_DIGEST_MSG_FMT = "The JWE header references key management algorithm '%s' " + - "but the compact JWE string is missing the " + "required AAD authentication tag."; + "but the compact JWE string is missing the required AAD authentication tag."; - private static final String MISSING_ENC_MSG = "JWE header does not contain a required " + - "'enc' (Encryption Algorithm) header parameter. " + "This header parameter is mandatory per the JWE " + - "Specification, Section 4.1.2. See " + - "https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.2 for more information."; + private static final String MISSING_ENC_MSG = "JWE header does not contain a required 'enc' (Encryption " + + "Algorithm) header parameter. This header parameter is mandatory per the JWE Specification, " + + "Section 4.1.2. See https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.2 for more information."; private static final String UNSECURED_DISABLED_MSG_PREFIX = "Unsecured JWSs (those with an " + DefaultHeader.ALGORITHM + " header value of '" + Jwts.SIG.NONE.getId() + "') are disallowed by " + "default as mandated by https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6. If you wish to " + - "allow them to be parsed, call the JwtParserBuilder.enableUnsecured() method (but please read the " + - "security considerations covered in that method's JavaDoc before doing so). Header: "; + "allow them to be parsed, call the JwtParserBuilder.enableUnsecured() method, but please read the " + + "security considerations covered in that method's JavaDoc before doing so. Header: "; private static final String JWE_NONE_MSG = "JWEs do not support key management " + DefaultHeader.ALGORITHM + " header value '" + Jwts.SIG.NONE.getId() + "' per " + @@ -121,8 +120,8 @@ public class DefaultJwtParser implements JwtParser { "against [Denial of Service attacks](" + "https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf). If you " + "wish to enable Unsecure JWS payload decompression, call the JwtParserBuilder." + - "enableUnsecuredDecompression() method (but please read the security considerations covered in that " + - "method's JavaDoc before doing so)."; + "enableUnsecuredDecompression() method, but please read the security considerations covered in that " + + "method's JavaDoc before doing so."; private final Provider provider; @@ -308,7 +307,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe String jwtWithoutSignature = tokenized.getProtected() + SEPARATOR_CHAR + tokenized.getBody(); byte[] data = jwtWithoutSignature.getBytes(StandardCharsets.US_ASCII); - byte[] signature = base64UrlDecode(tokenized.getDigest(), "JWS signature"); + byte[] signature = decode(tokenized.getDigest(), "JWS signature"); try { VerifySecureDigestRequest request = @@ -346,8 +345,8 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe } // =============== Header ================= - final byte[] headerBytes = base64UrlDecode(base64UrlHeader, "protected header"); - Map m = readValue(headerBytes, "protected header"); + final byte[] headerBytes = decode(base64UrlHeader, "protected header"); + Map m = deserialize(headerBytes, "protected header"); Header header; try { header = tokenized.createHeader(m); @@ -390,7 +389,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe } // =============== Body ================= - byte[] payload = base64UrlDecode(tokenized.getBody(), "payload"); + byte[] payload = decode(tokenized.getBody(), "payload"); if (tokenized instanceof TokenizedJwe && Arrays.length(payload) == 0) { // Only JWS body can be empty per https://github.com/jwtk/jjwt/pull/540 String msg = "Compact JWE strings MUST always contain a payload (ciphertext)."; throw new MalformedJwtException(msg); @@ -406,7 +405,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe byte[] cekBytes = Bytes.EMPTY; //ignored unless using an encrypted key algorithm String base64Url = tokenizedJwe.getEncryptedKey(); if (Strings.hasText(base64Url)) { - cekBytes = base64UrlDecode(base64Url, "JWE encrypted key"); + cekBytes = decode(base64Url, "JWE encrypted key"); if (Arrays.length(cekBytes) == 0) { String msg = "Compact JWE string represents an encrypted key, but the key is empty."; throw new MalformedJwtException(msg); @@ -415,7 +414,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe base64Url = tokenizedJwe.getIv(); if (Strings.hasText(base64Url)) { - iv = base64UrlDecode(base64Url, "JWE Initialization Vector"); + iv = decode(base64Url, "JWE Initialization Vector"); } if (Arrays.length(iv) == 0) { String msg = "Compact JWE strings must always contain an Initialization Vector."; @@ -430,7 +429,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe base64Url = base64UrlDigest; //guaranteed to be non-empty via the `alg` + digest check above: Assert.hasText(base64Url, "JWE AAD Authentication Tag cannot be null or empty."); - tag = base64UrlDecode(base64Url, "JWE AAD Authentication Tag"); + tag = decode(base64Url, "JWE AAD Authentication Tag"); if (Arrays.length(tag) == 0) { String msg = "Compact JWE strings must always contain an AAD Authentication Tag."; throw new MalformedJwtException(msg); @@ -490,7 +489,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe // parameter is performed by the JWS application." // && isLikelyJson(payload)) { // likely to be json, parse it: - Map claimsMap = readValue(payload, "claims"); + Map claimsMap = deserialize(payload, "claims"); try { claims = new DefaultClaims(claimsMap); } catch (Exception e) { @@ -708,7 +707,7 @@ public Jwe onClaimsJwe(Jwe jwe) { }); } - protected byte[] base64UrlDecode(String base64UrlEncoded, String name) { + protected byte[] decode(String base64UrlEncoded, String name) { try { return base64UrlDecoder.decode(base64UrlEncoded); } catch (DecodingException e) { @@ -717,7 +716,7 @@ protected byte[] base64UrlDecode(String base64UrlEncoded, String name) { } } - protected Map readValue(byte[] bytes, final String name) { + protected Map deserialize(byte[] bytes, final String name) { try { return deserializer.deserialize(bytes); } catch (MalformedJwtException | DeserializationException e) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy index 2ed6cdb80..76ce935aa 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy @@ -50,7 +50,7 @@ class DefaultJwtParserTest { @Test(expected = MalformedJwtException) void testBase64UrlDecodeWithInvalidInput() { - newParser().base64UrlDecode('20:SLDKJF;3993;----', 'test') + newParser().decode('20:SLDKJF;3993;----', 'test') } @Test From b24e2f4f774bc6f5c25ec2c1a3ede3dc37658963 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:49:07 -0700 Subject: [PATCH 10/24] - Renamed KeyBuilderSupplier#keyBuilder() to less verbose KeyBuilderSupplier#key() - Renamed KeyPairBuilderSupplier#keyPairBuilder() to less verbose KeyPairBuilderSupplier#keyPair() --- CHANGELOG.md | 10 ++--- README.md | 42 +++++++++---------- .../main/java/io/jsonwebtoken/JwtBuilder.java | 2 +- api/src/main/java/io/jsonwebtoken/Jwts.java | 30 ++++++------- .../jsonwebtoken/security/AeadAlgorithm.java | 2 +- .../security/KeyBuilderSupplier.java | 6 +-- .../security/KeyPairBuilderSupplier.java | 4 +- .../io/jsonwebtoken/security/KeyRequest.java | 3 +- .../java/io/jsonwebtoken/security/Keys.java | 30 ++++++------- .../jsonwebtoken/security/MacAlgorithm.java | 2 +- .../security/SignatureAlgorithm.java | 2 +- .../impl/security/AesAlgorithm.java | 2 +- .../impl/security/CryptoAlgorithm.java | 2 +- .../impl/security/DefaultCurve.java | 2 +- .../impl/security/DefaultMacAlgorithm.java | 6 +-- .../jsonwebtoken/impl/security/ECCurve.java | 2 +- .../impl/security/EcSignatureAlgorithm.java | 2 +- .../impl/security/EcdhKeyAlgorithm.java | 2 +- .../impl/security/EdSignatureAlgorithm.java | 4 +- .../impl/security/EdwardsCurve.java | 2 +- .../security/EdwardsPublicKeyDeriver.java | 2 +- .../impl/security/HmacAesAeadAlgorithm.java | 2 +- .../impl/security/RsaSignatureAlgorithm.java | 2 +- .../groovy/io/jsonwebtoken/JwtsTest.groovy | 42 +++++++++---------- .../jsonwebtoken/impl/DefaultJweTest.groovy | 4 +- .../jsonwebtoken/impl/DefaultJwsTest.groovy | 4 +- .../impl/DefaultJwtBuilderTest.groovy | 12 +++--- .../impl/DefaultJwtParserBuilderTest.groovy | 2 +- .../impl/DefaultJwtParserTest.groovy | 2 +- .../security/AbstractEcJwkFactoryTest.groovy | 4 +- .../AbstractSecureDigestAlgorithmTest.groovy | 6 +-- .../impl/security/AesAlgorithmTest.groovy | 2 +- .../security/AesGcmKeyAlgorithmTest.groovy | 8 ++-- .../impl/security/CurvesTest.groovy | 2 +- .../impl/security/DefaultCurveTest.groovy | 2 +- .../security/DefaultMacAlgorithmTest.groovy | 8 ++-- .../DefaultRsaKeyAlgorithmTest.groovy | 2 +- .../security/DirectKeyAlgorithmTest.groovy | 2 +- .../impl/security/ECCurveTest.groovy | 2 +- .../security/EcSignatureAlgorithmTest.groovy | 18 ++++---- .../security/EdSignatureAlgorithmTest.groovy | 2 +- .../impl/security/EdwardsCurveTest.groovy | 2 +- .../EdwardsPublicKeyDeriverTest.groovy | 2 +- .../security/HmacAesAeadAlgorithmTest.groovy | 4 +- .../impl/security/JwksTest.groovy | 10 ++--- .../impl/security/KeyPairsTest.groovy | 2 +- .../impl/security/OctetJwksTest.groovy | 2 +- .../security/RFC7516AppendixA3Test.groovy | 2 +- .../impl/security/RFC7517AppendixCTest.groovy | 2 +- .../security/RsaSignatureAlgorithmTest.groovy | 2 +- .../impl/security/TestKeys.groovy | 18 ++++---- .../security/EncryptionAlgorithmsTest.groovy | 4 +- .../io/jsonwebtoken/security/KeysTest.groovy | 12 +++--- .../io/jsonwebtoken/all/JavaReadmeTest.java | 28 ++++++------- 54 files changed, 188 insertions(+), 189 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25952bdec..679fe9cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,7 @@ available immediately. For example: ```java AeadAlgorithm enc = Jwts.ENC.A256GCM; -SecretKey key = enc.keyBuilder().build(); +SecretKey key = enc.key().build(); String compact = Jwts.builder().setSubject("Joe").encryptWith(key, enc).compact(); Jwe jwe = Jwts.parser().decryptWith(key).build().parseClaimsJwe(compact); @@ -56,7 +56,7 @@ Private keys - as fully encoded JSON objects according to the JWK specification supported. The new `Jwks` utility class exists to create JWK builders and parsers as desired. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); +SecretKey key = Jwts.SIG.HS256.key().build(); SecretJwk jwk = Jwks.builder().forKey(key).build(); assert key.equals(jwk.toKey()); @@ -92,12 +92,12 @@ interfaces now allow anyone to plug in and support custom algorithms with JJWT a Because the `io.jsonwebtoken.security.Keys#secretKeyFor` and `io.jsonwebtoken.security.Keys#keyPairFor` methods accepted the now-deprecated `io.jsonwebtoken.SignatureAlgorithm` enum, they have also been deprecated in favor of -calling new `keyBuilder()` or `keyPairBuilder()` methods on `MacAlgorithm` and `SignatureAlgorithm` instances directly. +calling new `key()` or `keyPair()` builder methods on `MacAlgorithm` and `SignatureAlgorithm` instances directly. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); -KeyPair pair = Jwts.SIG.RS256.keyPairBuilder().build(); +SecretKey key = Jwts.SIG.HS256.key().build(); +KeyPair pair = Jwts.SIG.RS256.keyPair().build(); ``` The builders allow for customization of the JCA `Provider` and `SecureRandom` during Key or KeyPair generation if desired, whereas diff --git a/README.md b/README.md index 83224e441..6a0b24c0e 100644 --- a/README.md +++ b/README.md @@ -696,7 +696,7 @@ import java.security.Key; // We need a signing key, so we'll create one just for this example. Usually // the key would be read from your application configuration instead. -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); +SecretKey key = Jwts.SIG.HS256.key().build(); String jws = Jwts.builder().subject("Joe").signWith(key).compact(); ``` @@ -1516,10 +1516,10 @@ JWT signature algorithm you might want to use. ##### Secret Keys If you want to generate a sufficiently strong `SecretKey` for use with the JWT HMAC-SHA algorithms, use the respective -algorithm's `keyBuilder()` method: +algorithm's `key()` builder method: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().build(); //or HS384.keyBuilder() or HS512.keyBuilder() +SecretKey key = Jwts.SIG.HS256.key().build(); //or HS384.key() or HS512.key() ``` Under the hood, JJWT uses the JCA default provider's `KeyGenerator` to create a secure-random key with the correct @@ -1529,7 +1529,7 @@ If you want to specify a specific JCA `Provider` or `SecureRandom` to use during as builder arguments. For example: ```java -SecretKey key = Jwts.SIG.HS256.keyBuilder().provider(aProvider).random(aSecureRandom).build(); +SecretKey key = Jwts.SIG.HS256.key().provider(aProvider).random(aSecureRandom).build(); ``` If you need to save this new `SecretKey`, you can Base64 (or Base64URL) encode it: @@ -1546,10 +1546,10 @@ further encrypt it, etc, before saving to disk (for example). ##### Asymmetric Keys If you want to generate sufficiently strong Elliptic Curve or RSA asymmetric key pairs for use with JWT ECDSA or RSA -algorithms, use an algorithm's respective `keyPairBuilder()` method: +algorithms, use an algorithm's respective `keyPair()` builder method: ```java -KeyPair keyPair = Jwts.SIG.RS256.keyPairBuilder().build(); //or RS384, RS512, PS256, etc... +KeyPair keyPair = Jwts.SIG.RS256.keyPair().build(); //or RS384, RS512, PS256, etc... ``` Once you've generated a `KeyPair`, you can use the private key (`keyPair.getPrivate()`) to create a JWS and the @@ -3031,7 +3031,7 @@ Example: ```java // Create a test key suitable for the desired HMAC-SHA algorithm: MacAlgorithm alg = Jwts.SIG.HS512; //or HS384 or HS256 -SecretKey key = alg.keyBuilder().build(); +SecretKey key = alg.key().build(); String message = "Hello World!"; byte[] content = message.getBytes(StandardCharsets.UTF_8); @@ -3058,7 +3058,7 @@ public key: ```java // Create a test key suitable for the desired RSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.RS512; //or PS512, RS256, etc... -KeyPair pair = alg.keyPairBuilder().build(); +KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his RSA private key: String jws = Jwts.builder().subject("Alice") @@ -3089,7 +3089,7 @@ public key: ```java // Create a test key suitable for the desired ECDSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.ES512; //or ES256 or ES384 -KeyPair pair = alg.keyPairBuilder().build(); +KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his EC private key: String jws = Jwts.builder().subject("Alice") @@ -3133,7 +3133,7 @@ using Bob's Edwards Curve public key: ```java // Create a test key suitable for the EdDSA signature algorithm using Ed25519 or Ed448 keys: SignatureAlgorithm alg = Jwts.SIG.Ed25519; //or Ed448 -KeyPair pair = alg.keyPairBuilder().build(); +KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his Edwards Curve private key: String jws = Jwts.builder().subject("Alice") @@ -3173,7 +3173,7 @@ Example: // Create a test key suitable for the desired payload encryption algorithm: // (A*GCM algorithms are recommended, but require JDK >= 8 or BouncyCastle) AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A128GCM, A192GCM, A256CBC-HS512, etc... -SecretKey key = enc.keyBuilder().build(); +SecretKey key = enc.key().build(); String message = "Live long and prosper."; byte[] content = message.getBytes(StandardCharsets.UTF_8); @@ -3201,7 +3201,7 @@ decrypt the JWT using her RSA private key: ```java // Create a test KeyPair suitable for the desired RSA key algorithm: -KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.RS512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP or RSA1_5 @@ -3238,7 +3238,7 @@ efficient than the `A*KW` variants, but they do require JDK 8 or later (or JDK 7 ```java // Create a test SecretKey suitable for the desired AES Key Wrap algorithm: SecretKeyAlgorithm alg = Jwts.KEY.A256GCMKW; //or A192GCMKW, A128GCMKW, A256KW, etc... -SecretKey key = alg.keyBuilder().build(); +SecretKey key = alg.key().build(); // Chooose the Encryption Algorithm used to encrypt the payload: AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... @@ -3269,7 +3269,7 @@ Alice can then decrypt the JWT using her Elliptic Curve private key: ```java // Create a test KeyPair suitable for the desired EC key algorithm: -KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.ES512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc. @@ -3341,7 +3341,7 @@ assert "me".equals(issuer); Example creating and parsing a secret JWK: ```java -SecretKey key = Jwts.SIG.HS512.keyBuilder().build(); // or HS384 or HS256 +SecretKey key = Jwts.SIG.HS512.key().build(); // or HS384 or HS256 SecretJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -3361,7 +3361,7 @@ assert jwk.equals(parsed); Example creating and parsing an RSA Public JWK: ```java -RSAPublicKey key = (RSAPublicKey)Jwts.SIG.RS512.keyPairBuilder().build().getPublic(); +RSAPublicKey key = (RSAPublicKey)Jwts.SIG.RS512.keyPair().build().getPublic(); RsaPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -3381,7 +3381,7 @@ assert jwk.equals(parsed); Example creating and parsing an RSA Private JWK: ```java -KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.RS512.keyPair().build(); RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate(); @@ -3407,7 +3407,7 @@ assert privJwk.equals(parsed); Example creating and parsing an Elliptic Curve Public JWK: ```java -ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPairBuilder().build().getPublic(); +ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPair().build().getPublic(); EcPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -3427,7 +3427,7 @@ assert jwk.equals(parsed); Example creating and parsing an Elliptic Curve Private JWK: ```java -KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.ES512.keyPair().build(); ECPublicKey pubKey = (ECPublicKey) pair.getPublic(); ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate(); @@ -3455,7 +3455,7 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, `OctetPublicJwk` interface names): ```java -PublicKey key = Jwts.SIG.Ed25519.keyPairBuilder().build().getPublic(); +PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic(); OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -3477,7 +3477,7 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, `OctetPrivateJwk` and `OctetPublicJwk` interface names): ```java -KeyPair pair = Jwts.SIG.Ed448.keyPairBuilder().build(); +KeyPair pair = Jwts.SIG.Ed448.keyPair().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 08ac6e1ca..5e77c414a 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -738,7 +738,7 @@ public interface JwtBuilder extends ClaimsMutator { * {@code enc} algorithm. In this case, the {@code key} argument MUST be of sufficient strength to * use with the specified {@code enc} algorithm, otherwise an exception will be thrown during encryption. If * desired, secure-random keys suitable for an {@link AeadAlgorithm} may be generated using the algorithm's - * {@link AeadAlgorithm#keyBuilder() keyBuilder}. + * {@link AeadAlgorithm#key() key()} builder. * * * @param key the symmetric encryption key to use with the {@code enc} algorithm. diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java index 807c49685..84d6d8e6f 100644 --- a/api/src/main/java/io/jsonwebtoken/Jwts.java +++ b/api/src/main/java/io/jsonwebtoken/Jwts.java @@ -365,7 +365,7 @@ public static final class KEY { *

    During JWE creation, this algorithm:

    *
      *
    1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
    2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
    3. Encrypts this newly-generated {@code SecretKey} with a 128-bit shared symmetric key using the * AES Key Wrap algorithm, producing encrypted key ciphertext.
    4. *
    5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -389,7 +389,7 @@ public static final class KEY { *

      During JWE creation, this algorithm:

      *
        *
      1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
      2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
      3. Encrypts this newly-generated {@code SecretKey} with a 192-bit shared symmetric key using the * AES Key Wrap algorithm, producing encrypted key ciphertext.
      4. *
      5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -413,7 +413,7 @@ public static final class KEY { *

        During JWE creation, this algorithm:

        *
          *
        1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
        2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
        3. Encrypts this newly-generated {@code SecretKey} with a 256-bit shared symmetric key using the * AES Key Wrap algorithm, producing encrypted key ciphertext.
        4. *
        5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -437,7 +437,7 @@ public static final class KEY { *

          During JWE creation, this algorithm:

          *
            *
          1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
          2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
          3. Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.
          4. *
          5. Encrypts this newly-generated {@code SecretKey} with a 128-bit shared symmetric key using the * AES GCM Key Wrap algorithm with the generated Initialization Vector, producing encrypted key ciphertext @@ -476,7 +476,7 @@ public static final class KEY { *

            During JWE creation, this algorithm:

            *
              *
            1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
            2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
            3. Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.
            4. *
            5. Encrypts this newly-generated {@code SecretKey} with a 192-bit shared symmetric key using the * AES GCM Key Wrap algorithm with the generated Initialization Vector, producing encrypted key ciphertext @@ -515,7 +515,7 @@ public static final class KEY { *

              During JWE creation, this algorithm:

              *
                *
              1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              3. Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.
              4. *
              5. Encrypts this newly-generated {@code SecretKey} with a 256-bit shared symmetric key using the * AES GCM Key Wrap algorithm with the generated Initialization Vector, producing encrypted key ciphertext @@ -564,7 +564,7 @@ public static final class KEY { *
              6. Derives a 128-bit Key Encryption Key with the PBES2-HS256 password-based key derivation algorithm, * using the provided password, iteration count, and input salt as arguments.
              7. *
              8. Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              9. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              10. Encrypts this newly-generated Content Encryption {@code SecretKey} with the {@code A128KW} key wrap * algorithm using the 128-bit derived password-based Key Encryption Key from step {@code #3}, * producing encrypted key ciphertext.
              11. @@ -609,7 +609,7 @@ public static final class KEY { *
              12. Derives a 192-bit Key Encryption Key with the PBES2-HS384 password-based key derivation algorithm, * using the provided password, iteration count, and input salt as arguments.
              13. *
              14. Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              15. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              16. Encrypts this newly-generated Content Encryption {@code SecretKey} with the {@code A192KW} key wrap * algorithm using the 192-bit derived password-based Key Encryption Key from step {@code #3}, * producing encrypted key ciphertext.
              17. @@ -654,7 +654,7 @@ public static final class KEY { *
              18. Derives a 256-bit Key Encryption Key with the PBES2-HS512 password-based key derivation algorithm, * using the provided password, iteration count, and input salt as arguments.
              19. *
              20. Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
              21. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
              22. Encrypts this newly-generated Content Encryption {@code SecretKey} with the {@code A256KW} key wrap * algorithm using the 256-bit derived password-based Key Encryption Key from step {@code #3}, * producing encrypted key ciphertext.
              23. @@ -690,7 +690,7 @@ public static final class KEY { *

                During JWE creation, this algorithm:

                *
                  *
                1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                3. Encrypts this newly-generated {@code SecretKey} with the RSA key wrap algorithm, using the JWE * recipient's RSA Public Key, producing encrypted key ciphertext.
                4. *
                5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -715,7 +715,7 @@ public static final class KEY { *

                  During JWE creation, this algorithm:

                  *
                    *
                  1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                  2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                  3. Encrypts this newly-generated {@code SecretKey} with the RSA OAEP with SHA-1 and MGF1 key wrap algorithm, * using the JWE recipient's RSA Public Key, producing encrypted key ciphertext.
                  4. *
                  5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -740,7 +740,7 @@ public static final class KEY { *

                    During JWE creation, this algorithm:

                    *
                      *
                    1. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    2. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    3. Encrypts this newly-generated {@code SecretKey} with the RSA OAEP with SHA-256 and MGF1 key wrap * algorithm, using the JWE recipient's RSA Public Key, producing encrypted key ciphertext.
                    4. *
                    5. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -818,7 +818,7 @@ public static final class KEY { * "epk" * (Ephemeral Public Key) Header Parameter to be transmitted in the JWE.
                    6. *
                    7. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    8. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    9. Encrypts this newly-generated {@code SecretKey} with the {@code A128KW} key wrap * algorithm using the derived symmetric Key Encryption Key from step {@code #3}, producing encrypted key ciphertext.
                    10. *
                    11. Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated @@ -866,7 +866,7 @@ public static final class KEY { * "epk" * (Ephemeral Public Key) Header Parameter to be transmitted in the JWE.
                    12. *
                    13. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    14. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    15. Encrypts this newly-generated {@code SecretKey} with the {@code A192KW} key wrap * algorithm using the derived symmetric Key Encryption Key from step {@code #3}, producing encrypted key * ciphertext.
                    16. @@ -915,7 +915,7 @@ public static final class KEY { * "epk" * (Ephemeral Public Key) Header Parameter to be transmitted in the JWE. *
                    17. Generates a new secure-random content encryption {@link SecretKey} suitable for use with a - * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).
                    18. + * specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}). *
                    19. Encrypts this newly-generated {@code SecretKey} with the {@code A256KW} key wrap * algorithm using the derived symmetric Key Encryption Key from step {@code #3}, producing encrypted key * ciphertext.
                    20. diff --git a/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java b/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java index 7fd6f8b4e..5c7f0a595 100644 --- a/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java +++ b/api/src/main/java/io/jsonwebtoken/security/AeadAlgorithm.java @@ -51,7 +51,7 @@ * and algorithm parameters required by that algorithm. For example:

                      * *
                      
                      - *     SecretKey key = aeadAlgorithm.keyBuilder().build();
                      + *     SecretKey key = aeadAlgorithm.key().build();
                        * 
                      * *

                      The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java index 29c1e53d2..97b3eb02a 100644 --- a/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java +++ b/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java @@ -22,8 +22,8 @@ * their associated cryptographic algorithm implementation. * * @param type of {@link Key} created by the builder - * @param type of builder to create each time {@link #keyBuilder()} is called. - * @see #keyBuilder() + * @param type of builder to create each time {@link #key()} is called. + * @see #key() * @see KeyBuilder * @since JJWT_RELEASE_VERSION */ @@ -36,5 +36,5 @@ public interface KeyBuilderSupplier> { * @return a new {@link KeyBuilder} instance that will produce new secure-random keys with a length sufficient * to be used by the component's associated cryptographic algorithm. */ - B keyBuilder(); + B key(); } diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java index a93bc5760..a6b79bda3 100644 --- a/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java +++ b/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java @@ -21,7 +21,7 @@ * Interface implemented by components that support building/creating new {@link KeyPair}s suitable for use with their * associated cryptographic algorithm implementation. * - * @see #keyPairBuilder() + * @see #keyPair() * @see KeyPairBuilder * @since JJWT_RELEASE_VERSION */ @@ -34,5 +34,5 @@ public interface KeyPairBuilderSupplier { * @return a new {@link KeyPairBuilder} that will create new secure-random {@link KeyPair}s with a length and * parameters sufficient for use with the component's associated cryptographic algorithm. */ - KeyPairBuilder keyPairBuilder(); + KeyPairBuilder keyPair(); } diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java b/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java index 050d784c6..f9fe51f0f 100644 --- a/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java +++ b/api/src/main/java/io/jsonwebtoken/security/KeyRequest.java @@ -49,8 +49,7 @@ public interface KeyRequest extends Request { * {@code KeyRequest}. {@link KeyAlgorithm} implementations that generate an ephemeral {@code SecretKey} to use * as what the JWE specification calls a * "Content Encryption Key (CEK)" should call the {@code AeadAlgorithm}'s - * {@link AeadAlgorithm#keyBuilder() keyBuilder()} to obtain a builder that will create a key suitable for that - * exact {@code AeadAlgorithm}. + * {@link AeadAlgorithm#key() key()} builder to create a key suitable for that exact {@code AeadAlgorithm}. * * @return the {@link AeadAlgorithm} that will be called for encryption or decryption after processing the * {@code KeyRequest}. diff --git a/api/src/main/java/io/jsonwebtoken/security/Keys.java b/api/src/main/java/io/jsonwebtoken/security/Keys.java index 225cdde21..e0eeaa979 100644 --- a/api/src/main/java/io/jsonwebtoken/security/Keys.java +++ b/api/src/main/java/io/jsonwebtoken/security/Keys.java @@ -68,8 +68,8 @@ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException { "is not secure enough for any JWT HMAC-SHA algorithm. The JWT " + "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " + "size >= 256 bits (the key size must be greater than or equal to the hash " + - "output size). Consider using the Jwts.SIG.HS256.keyBuilder() method (or HS384.keyBuilder() " + - "or HS512.keyBuilder()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA " + + "output size). Consider using the Jwts.SIG.HS256.key() builder (or HS384.key() " + + "or HS512.key()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA " + "algorithm. See https://tools.ietf.org/html/rfc7518#section-3.2 for more information."; throw new WeakKeyException(msg); } @@ -78,12 +78,12 @@ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException { *

                      Deprecation Notice

                      * *

                      As of JJWT JJWT_RELEASE_VERSION, symmetric (secret) key algorithm instances can generate a key of suitable - * length for that specific algorithm by calling their {@code keyBuilder()} method directly. For example:

                      + * length for that specific algorithm by calling their {@code key()} builder method directly. For example:

                      * *
                      
                      -     * {@link Jwts.SIG#HS256}.keyBuilder().build();
                      -     * {@link Jwts.SIG#HS384}.keyBuilder().build();
                      -     * {@link Jwts.SIG#HS512}.keyBuilder().build();
                      +     * {@link Jwts.SIG#HS256}.key().build();
                      +     * {@link Jwts.SIG#HS384}.key().build();
                      +     * {@link Jwts.SIG#HS512}.key().build();
                            * 
                      * *

                      Call those methods as needed instead of this static {@code secretKeyFor} helper method - the returned @@ -124,7 +124,7 @@ public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException { * @throws IllegalArgumentException for any input value other than {@link io.jsonwebtoken.SignatureAlgorithm#HS256}, * {@link io.jsonwebtoken.SignatureAlgorithm#HS384}, or {@link io.jsonwebtoken.SignatureAlgorithm#HS512} * @deprecated since JJWT_RELEASE_VERSION. Use your preferred {@link MacAlgorithm} instance's - * {@link MacAlgorithm#keyBuilder() keyBuilder()} method directly. + * {@link MacAlgorithm#key() key()} builder method directly. */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -135,21 +135,21 @@ public static SecretKey secretKeyFor(io.jsonwebtoken.SignatureAlgorithm alg) thr String msg = "The " + alg.name() + " algorithm does not support shared secret keys."; throw new IllegalArgumentException(msg); } - return ((MacAlgorithm) salg).keyBuilder().build(); + return ((MacAlgorithm) salg).key().build(); } /** *

                      Deprecation Notice

                      * *

                      As of JJWT JJWT_RELEASE_VERSION, asymmetric key algorithm instances can generate KeyPairs of suitable strength - * for that specific algorithm by calling their {@code keyPairBuilder()} method directly. For example:

                      + * for that specific algorithm by calling their {@code keyPair()} builder method directly. For example:

                      * *
                      -     * Jwts.SIG.{@link Jwts.SIG#RS256 RS256}.keyPairBuilder().build();
                      -     * Jwts.SIG.{@link Jwts.SIG#RS384 RS384}.keyPairBuilder().build();
                      -     * Jwts.SIG.{@link Jwts.SIG#RS512 RS512}.keyPairBuilder().build();
                      +     * Jwts.SIG.{@link Jwts.SIG#RS256 RS256}.keyPair().build();
                      +     * Jwts.SIG.{@link Jwts.SIG#RS384 RS384}.keyPair().build();
                      +     * Jwts.SIG.{@link Jwts.SIG#RS512 RS512}.keyPair().build();
                            * ... etc ...
                      -     * Jwts.SIG.{@link Jwts.SIG#ES512 ES512}.keyPairBuilder().build();
                      + * Jwts.SIG.{@link Jwts.SIG#ES512 ES512}.keyPair().build(); * *

                      Call those methods as needed instead of this static {@code keyPairFor} helper method - the returned * {@link KeyPairBuilder} allows callers to specify a preferred Provider or SecureRandom on the builder if @@ -229,7 +229,7 @@ public static SecretKey secretKeyFor(io.jsonwebtoken.SignatureAlgorithm alg) thr * @throws IllegalArgumentException if {@code alg} is not an asymmetric algorithm * @deprecated since JJWT_RELEASE_VERSION in favor of your preferred * {@link io.jsonwebtoken.security.SignatureAlgorithm} instance's - * {@link SignatureAlgorithm#keyPairBuilder() keyPairBuilder()} method directly. + * {@link SignatureAlgorithm#keyPair() keyPair()} builder method directly. */ @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -241,7 +241,7 @@ public static KeyPair keyPairFor(io.jsonwebtoken.SignatureAlgorithm alg) throws throw new IllegalArgumentException(msg); } SignatureAlgorithm asalg = ((SignatureAlgorithm) salg); - return asalg.keyPairBuilder().build(); + return asalg.keyPair().build(); } /** diff --git a/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java b/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java index bbb1bc0ef..3d04e9747 100644 --- a/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java +++ b/api/src/main/java/io/jsonwebtoken/security/MacAlgorithm.java @@ -47,7 +47,7 @@ * have a sufficient length and any algorithm parameters required by that algorithm. For example:

                      * *
                      - * SecretKey key = macAlgorithm.keyBuilder().build();
                      + * SecretKey key = macAlgorithm.key().build(); * *

                      The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for * that exact {@code MacAlgorithm} instance.

                      diff --git a/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java b/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java index f9d1aa445..b20192e81 100644 --- a/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java +++ b/api/src/main/java/io/jsonwebtoken/security/SignatureAlgorithm.java @@ -38,7 +38,7 @@ * required by that algorithm. For example:

                      * *
                      - * KeyPair pair = signatureAlgorithm.keyPairBuilder().build();
                      + * KeyPair pair = signatureAlgorithm.keyPair().build(); * *

                      The resulting {@code pair} is guaranteed to have the correct algorithm parameters and length/strength necessary * for that exact {@code signatureAlgorithm} instance.

                      diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java index c3301189b..892921897 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AesAlgorithm.java @@ -81,7 +81,7 @@ public int getKeyBitLength() { } @Override - public SecretKeyBuilder keyBuilder() { + public SecretKeyBuilder key() { return new DefaultSecretKeyBuilder(KEY_ALG_NAME, getKeyBitLength()); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java index 55a126e57..8e0785e6c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/CryptoAlgorithm.java @@ -92,7 +92,7 @@ protected Provider getProvider(Request request) { protected SecretKey generateKey(KeyRequest request) { AeadAlgorithm enc = Assert.notNull(request.getEncryptionAlgorithm(), "Request encryptionAlgorithm cannot be null."); - SecretKeyBuilder builder = Assert.notNull(enc.keyBuilder(), "Request encryptionAlgorithm keyBuilder cannot be null."); + SecretKeyBuilder builder = Assert.notNull(enc.key(), "Request encryptionAlgorithm KeyBuilder cannot be null."); SecretKey key = builder.provider(getProvider(request)).random(request.getSecureRandom()).build(); return Assert.notNull(key, "Request encryptionAlgorithm SecretKeyBuilder cannot produce null keys."); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java index af4d2f64c..7e5195897 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java @@ -74,7 +74,7 @@ public String toString() { return ID; } - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder(this.JCA_NAME).provider(this.PROVIDER); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java index d873d8bec..1fd7c0291 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java @@ -81,7 +81,7 @@ private boolean isJwaStandardJcaName(String jcaName) { } @Override - public SecretKeyBuilder keyBuilder() { + public SecretKeyBuilder key() { return new DefaultSecretKeyBuilder(getJcaName(), getKeyBitLength()); } @@ -142,8 +142,8 @@ protected void validateKey(Key k, boolean signing) { msg += " The JWT " + "JWA Specification (RFC 7518, Section 3.2) states that keys used with " + id + " MUST have a " + "size >= " + minKeyBitLength + " bits (the key size must be greater than or equal to the hash " + - "output size). Consider using the Jwts.SIG." + id + ".keyBuilder() " + - "method to create a key guaranteed to be secure enough for " + id + ". See " + + "output size). Consider using the Jwts.SIG." + id + ".key() " + + "builder to create a key guaranteed to be secure enough for " + id + ". See " + "https://tools.ietf.org/html/rfc7518#section-3.2 for more information."; } else { //custom algorithm - just indicate required key length: msg += " The " + id + " algorithm requires keys to have a size >= " + minKeyBitLength + " bits."; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java index 9b580107a..2ad9db553 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/ECCurve.java @@ -61,7 +61,7 @@ public boolean contains(ECPoint point) { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder(KEY_PAIR_GENERATOR_JCA_NAME, toParameterSpec()); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java index 8b40485e0..b5d65603c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java @@ -100,7 +100,7 @@ public EcSignatureAlgorithm(int orderBitLength) { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder(ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, this.KEY_PAIR_GEN_PARAMS) .provider(getProvider()) .random(Randoms.secureRandom()); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java index e763c4e3d..84fdae4eb 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java @@ -98,7 +98,7 @@ protected KeyPair generateKeyPair(final Request request, final ECParameterSpe //visible for testing, for Edwards elliptic curves protected KeyPair generateKeyPair(SecureRandom random, EdwardsCurve curve, Provider provider) { - return curve.keyPairBuilder().provider(provider).random(random).build(); + return curve.keyPair().provider(provider).random(random).build(); } protected byte[] generateZ(final KeyRequest request, final PublicKey pub, final PrivateKey priv) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java index 590b84d74..c9d68b18a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java @@ -64,8 +64,8 @@ protected String getJcaName(Request request) { } @Override - public KeyPairBuilder keyPairBuilder() { - return this.preferredCurve.keyPairBuilder(); + public KeyPairBuilder keyPair() { + return this.preferredCurve.keyPair(); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java index d5a06ed9a..b5cd00ac2 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java @@ -357,7 +357,7 @@ public boolean isSignatureCurve() { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).provider(getProvider()); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java index de257a20a..5fccab1d4 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java @@ -51,7 +51,7 @@ public PublicKey apply(PrivateKey privateKey) { // Since we already have a private key, we provide a RNG that 'generates' the existing private key // instead of a random one, and the corresponding public key will be computed for us automatically. SecureRandom random = new ConstantRandom(pkBytes); - KeyPair pair = curve.keyPairBuilder().random(random).build(); + KeyPair pair = curve.keyPair().random(random).build(); Assert.stateNotNull(pair, "Edwards curve generated keypair cannot be null."); return Assert.stateNotNull(pair.getPublic(), "Edwards curve KeyPair must have a PublicKey"); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java index 9ca92f564..e64527f21 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithm.java @@ -66,7 +66,7 @@ public int getKeyBitLength() { } @Override - public SecretKeyBuilder keyBuilder() { + public SecretKeyBuilder key() { // The Sun JCE KeyGenerator throws an exception if bitLengths are not standard AES 128, 192 or 256 values. // Since the JWA HmacAes algorithms require double that, we use secure-random keys instead: return new RandomSecretKeyBuilder(KEY_ALG_NAME, getKeyBitLength()); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java index 2dc049c6d..8e2f692e8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java @@ -78,7 +78,7 @@ public Signature get() throws Exception { } @Override - public KeyPairBuilder keyPairBuilder() { + public KeyPairBuilder keyPair() { return new DefaultKeyPairBuilder("RSA", this.preferredKeyBitLength) .provider(getProvider()) .random(Randoms.secureRandom()); diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index 3ba0f2c83..cc9b74e0d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -290,7 +290,7 @@ class JwtsTest { @Test void testParseWithMissingRequiredSignature() { - Key key = Jwts.SIG.HS256.keyBuilder().build() + Key key = Jwts.SIG.HS256.key().build() String compact = Jwts.builder().setSubject('foo').signWith(key).compact() int i = compact.lastIndexOf('.') String missingSig = compact.substring(0, i + 1) @@ -428,7 +428,7 @@ class JwtsTest { void testUncompressedJwt() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -450,7 +450,7 @@ class JwtsTest { void testCompressedJwtWithDeflate() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -472,7 +472,7 @@ class JwtsTest { void testCompressedJwtWithGZIP() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -494,7 +494,7 @@ class JwtsTest { void testCompressedWithCustomResolver() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -533,7 +533,7 @@ class JwtsTest { void testCompressedJwtWithUnrecognizedHeader() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String id = UUID.randomUUID().toString() @@ -552,7 +552,7 @@ class JwtsTest { void testCompressStringPayloadWithDeflate() { def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String payload = "this is my test for a payload" @@ -673,8 +673,8 @@ class JwtsTest { void testParseClaimsJwsWithWeakHmacKey() { def alg = Jwts.SIG.HS384 - def key = alg.keyBuilder().build() - def weakKey = Jwts.SIG.HS256.keyBuilder().build() + def key = alg.key().build() + def weakKey = Jwts.SIG.HS256.key().build() String jws = Jwts.builder().setSubject("Foo").signWith(key, alg).compact() @@ -744,7 +744,7 @@ class JwtsTest { def withoutSignature = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ" String jws = withoutSignature + '.' + invalidEncodedSignature - def keypair = Jwts.SIG.ES256.keyPairBuilder().build() + def keypair = Jwts.SIG.ES256.keyPair().build() Jwts.parser().setSigningKey(keypair.public).build().parseClaimsJws(jws) } @@ -754,7 +754,7 @@ class JwtsTest { //create random signing key for testing: def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() String notSigned = Jwts.builder().setSubject("Foo").compact() @@ -1025,8 +1025,8 @@ class JwtsTest { def id = realAlg.getId() + 'X' // custom id def alg = new MacAlgorithm() { @Override - SecretKeyBuilder keyBuilder() { - return realAlg.keyBuilder() + SecretKeyBuilder key() { + return realAlg.key() } @Override @@ -1065,7 +1065,7 @@ class JwtsTest { @Test void testParseJweWithCustomEncryptionAlgorithm() { def realAlg = Jwts.ENC.A128GCM // any alg will do, we're going to wrap it - def key = realAlg.keyBuilder().build() + def key = realAlg.key().build() def enc = realAlg.getId() + 'X' // custom id def encAlg = new AeadAlgorithm() { @Override @@ -1084,8 +1084,8 @@ class JwtsTest { } @Override - SecretKeyBuilder keyBuilder() { - return realAlg.keyBuilder() + SecretKeyBuilder key() { + return realAlg.key() } @Override @@ -1165,7 +1165,7 @@ class JwtsTest { //create random signing key for testing: def alg = Jwts.SIG.HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() //this is a 'real', valid JWT: String compact = Jwts.builder().setSubject("Joe").signWith(key, alg).compact() @@ -1300,8 +1300,8 @@ class JwtsTest { for (AeadAlgorithm enc : Jwts.ENC.get().values()) { SecretKey key = alg instanceof SecretKeyAlgorithm ? - ((SecretKeyAlgorithm) alg).keyBuilder().build() : - enc.keyBuilder().build() + ((SecretKeyAlgorithm) alg).key().build() : + enc.key().build() // encrypt: String jwe = Jwts.builder() @@ -1328,7 +1328,7 @@ class JwtsTest { for (AeadAlgorithm enc : Jwts.ENC.get().values()) { - SecretKey key = enc.keyBuilder().build() + SecretKey key = enc.key().build() // encrypt and compress: String jwe = Jwts.builder() @@ -1587,7 +1587,7 @@ class JwtsTest { static void testHmac(MacAlgorithm alg) { //create random signing key for testing: - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() def claims = new DefaultClaims([iss: 'joe', exp: later(), 'https://example.com/is_root': true]) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy index 67a3f2290..d843995a0 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJweTest.groovy @@ -28,7 +28,7 @@ class DefaultJweTest { @Test void testToString() { def alg = Jwts.ENC.A128CBC_HS256 as AeadAlgorithm - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').encryptWith(key, alg).compact() def jwe = Jwts.parser().decryptWith(key).build().parseClaimsJwe(compact) String encodedIv = Encoders.BASE64URL.encode(jwe.initializationVector) @@ -40,7 +40,7 @@ class DefaultJweTest { @Test void testEqualsAndHashCode() { def alg = Jwts.ENC.A128CBC_HS256 as AeadAlgorithm - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').encryptWith(key, alg).compact() def parser = Jwts.parser().decryptWith(key).build() def jwe1 = parser.parseClaimsJwe(compact) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy index b2393c5f3..179f11d00 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwsTest.groovy @@ -36,7 +36,7 @@ class DefaultJwsTest { void testToString() { //create random signing key for testing: def alg = Jwts.SIG.HS256 - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() int i = compact.lastIndexOf('.') String signature = compact.substring(i + 1) @@ -47,7 +47,7 @@ class DefaultJwsTest { @Test void testEqualsAndHashCode() { def alg = Jwts.SIG.HS256 - def key = alg.keyBuilder().build() + def key = alg.key().build() String compact = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() def parser = Jwts.parser().verifyWith(key).build() def jws1 = parser.parseClaimsJws(compact) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index 975e45ad5..acadf4d78 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -70,7 +70,7 @@ class DefaultJwtBuilderTest { } @Override - KeyPairBuilder keyPairBuilder() { + KeyPairBuilder keyPair() { throw new IllegalStateException("should not be called during build") } @@ -82,7 +82,7 @@ class DefaultJwtBuilderTest { replay provider def b = new DefaultJwtBuilder().provider(provider) - .setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg) + .setSubject('me').signWith(Jwts.SIG.HS256.key().build(), alg) assertSame provider, b.provider b.compact() verify provider @@ -113,7 +113,7 @@ class DefaultJwtBuilderTest { } @Override - KeyPairBuilder keyPairBuilder() { + KeyPairBuilder keyPair() { throw new IllegalStateException("should not be called during build") } @@ -124,7 +124,7 @@ class DefaultJwtBuilderTest { } def b = new DefaultJwtBuilder().random(random) - .setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg) + .setSubject('me').signWith(Jwts.SIG.HS256.key().build(), alg) assertSame random, b.secureRandom b.compact() assertTrue called[0] @@ -483,7 +483,7 @@ class DefaultJwtBuilderTest { @Test void testCompactSimplestPayload() { def enc = Jwts.ENC.A128GCM - def key = enc.keyBuilder().build() + def key = enc.key().build() def jwe = builder.setPayload("me").encryptWith(key, enc).compact() def jwt = Jwts.parser().decryptWith(key).build().parseContentJwe(jwe) assertEquals 'me', new String(jwt.getPayload(), StandardCharsets.UTF_8) @@ -492,7 +492,7 @@ class DefaultJwtBuilderTest { @Test void testCompactSimplestClaims() { def enc = Jwts.ENC.A128GCM - def key = enc.keyBuilder().build() + def key = enc.key().build() def jwe = builder.setSubject('joe').encryptWith(key, enc).compact() 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 44f620b51..6db65e00c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -121,7 +121,7 @@ class DefaultJwtParserBuilderTest { assertSame deserializer, p.deserializer def alg = Jwts.SIG.HS256 - def key = alg.keyBuilder().build() + def key = alg.key().build() String jws = Jwts.builder().claim('foo', 'bar').signWith(key, alg).compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy index 76ce935aa..074eee389 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserTest.groovy @@ -66,7 +66,7 @@ class DefaultJwtParserTest { assertTrue("Expected wrapping deserializer to be instance of JwtDeserializer", p.deserializer instanceof JwtDeserializer ) assertSame deserializer, p.deserializer.deserializer - def key = Jwts.SIG.HS256.keyBuilder().build() + def key = Jwts.SIG.HS256.key().build() String jws = Jwts.builder().claim('foo', 'bar').signWith(key, Jwts.SIG.HS256).compact() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy index 835fffd6f..46a1833a6 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractEcJwkFactoryTest.groovy @@ -83,7 +83,7 @@ class AbstractEcJwkFactoryTest { @Test void testAddSamePointDoublesIt() { - def pair = Jwts.SIG.ES256.keyPairBuilder().build() + def pair = Jwts.SIG.ES256.keyPair().build() def pub = pair.getPublic() as ECPublicKey def spec = pub.getParams() @@ -98,7 +98,7 @@ class AbstractEcJwkFactoryTest { @Test void testDerivePublicFails() { - def pair = Jwts.SIG.ES256.keyPairBuilder().build() + def pair = Jwts.SIG.ES256.keyPair().build() def priv = pair.getPrivate() as ECPrivateKey final def context = new DefaultJwkContext(DefaultEcPrivateJwk.FIELDS) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy index 4fd0b19df..288297779 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithmTest.groovy @@ -32,7 +32,7 @@ class AbstractSecureDigestAlgorithmTest { @Test void testSignAndVerifyWithExplicitProvider() { Provider provider = Security.getProvider('BC') - def pair = Jwts.SIG.RS256.keyPairBuilder().build() + def pair = Jwts.SIG.RS256.keyPair().build() byte[] data = 'foo'.getBytes(StandardCharsets.UTF_8) byte[] signature = Jwts.SIG.RS256.digest(new DefaultSecureRequest(data, provider, null, pair.getPrivate())) assertTrue Jwts.SIG.RS256.verify(new DefaultVerifySecureDigestRequest(data, provider, null, pair.getPublic(), signature)) @@ -40,7 +40,7 @@ class AbstractSecureDigestAlgorithmTest { @Test void testSignFailsWithAnExternalException() { - def pair = Jwts.SIG.RS256.keyPairBuilder().build() + def pair = Jwts.SIG.RS256.keyPair().build() def ise = new IllegalStateException('foo') def alg = new TestAbstractSecureDigestAlgorithm() { @Override @@ -59,7 +59,7 @@ class AbstractSecureDigestAlgorithmTest { @Test void testVerifyFailsWithExternalException() { - def pair = Jwts.SIG.RS256.keyPairBuilder().build() + def pair = Jwts.SIG.RS256.keyPair().build() def ise = new IllegalStateException('foo') def alg = new TestAbstractSecureDigestAlgorithm() { @Override diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy index 831dddbef..5795a689f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesAlgorithmTest.groovy @@ -108,7 +108,7 @@ class AesAlgorithmTest { def secureRandom = new SecureRandom() - def req = new DefaultAeadRequest('data'.getBytes(), null, secureRandom, alg.keyBuilder().build(), 'aad'.getBytes()) + def req = new DefaultAeadRequest('data'.getBytes(), null, secureRandom, alg.key().build(), 'aad'.getBytes()) def returnedSecureRandom = alg.ensureSecureRandom(req) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy index d986a049c..2091fc5da 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/AesGcmKeyAlgorithmTest.groovy @@ -49,8 +49,8 @@ class AesGcmKeyAlgorithmTest { def iv = new byte[12] Randoms.secureRandom().nextBytes(iv) - def kek = alg.keyBuilder().build() - def cek = alg.keyBuilder().build() + def kek = alg.key().build() + def cek = alg.key().build() final String jcaName = "AES/GCM/NoPadding" @@ -102,7 +102,7 @@ class AesGcmKeyAlgorithmTest { def cek = template.generateSecretKey(keyLength) def enc = new GcmAesAeadAlgorithm(keyLength) { @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(cek) } } @@ -140,7 +140,7 @@ class AesGcmKeyAlgorithmTest { def cek = template.generateSecretKey(keyLength) def enc = new GcmAesAeadAlgorithm(keyLength) { @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(cek) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy index 77538b909..76b1a8e79 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/CurvesTest.groovy @@ -51,7 +51,7 @@ class CurvesTest { @Test void testKeyPairBuilders() { Curves.VALUES.each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() if (it instanceof ECCurve) { assertEquals ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, pair.getPublic().getAlgorithm() assertEquals ECCurve.KEY_PAIR_GENERATOR_JCA_NAME, pair.getPrivate().getAlgorithm() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy index f72f877b8..9bf02e14a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultCurveTest.groovy @@ -78,7 +78,7 @@ class DefaultCurveTest { @Test void testKeyPairBuilder() { - def builder = curve.keyPairBuilder() + def builder = curve.keyPair() assertEquals 'bar', builder.jcaName //builder is an instanceof DefaultKeyPairBuilder } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy index 87aa35cc9..b2ace2f1c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy @@ -98,16 +98,16 @@ class DefaultMacAlgorithmTest { @Test(expected = SecurityException) void testKeyGeneratorNoSuchAlgorithm() { DefaultMacAlgorithm alg = new DefaultMacAlgorithm('HS256', 'foo', 256) - alg.keyBuilder().build() + alg.key().build() } @Test void testKeyGeneratorKeyLength() { DefaultMacAlgorithm alg = new DefaultMacAlgorithm('HS256', 'HmacSHA256', 256) - assertEquals 256, alg.keyBuilder().build().getEncoded().length * Byte.SIZE + assertEquals 256, alg.key().build().getEncoded().length * Byte.SIZE alg = new DefaultMacAlgorithm('A128CBC-HS256', 'HmacSHA256', 128) - assertEquals 128, alg.keyBuilder().build().getEncoded().length * Byte.SIZE + assertEquals 128, alg.key().build().getEncoded().length * Byte.SIZE } @Test(expected = IllegalArgumentException) @@ -146,7 +146,7 @@ class DefaultMacAlgorithmTest { String msg = 'The signing key\'s size is 192 bits which is not secure enough for the HS256 algorithm. ' + 'The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HS256 MUST have a ' + 'size >= 256 bits (the key size must be greater than or equal to the hash output size). ' + - 'Consider using the Jwts.SIG.HS256.keyBuilder() method to create a key guaranteed ' + + 'Consider using the Jwts.SIG.HS256.key() builder to create a key guaranteed ' + 'to be secure enough for HS256. See https://tools.ietf.org/html/rfc7518#section-3.2 for more ' + 'information.' assertEquals msg, expected.getMessage() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy index 103671e0a..e243887b4 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy @@ -32,7 +32,7 @@ class DefaultRsaKeyAlgorithmTest { @Test void testValidateNonRSAKey() { - SecretKey key = Jwts.KEY.A128KW.keyBuilder().build() + SecretKey key = Jwts.KEY.A128KW.key().build() for (DefaultRsaKeyAlgorithm alg : algs) { // if RSAKey interface isn't exposed (e.g. PKCS11 or HSM), don't error: alg.validate(key, true) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy index 8e09f6c4e..82a2c08a1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DirectKeyAlgorithmTest.groovy @@ -66,7 +66,7 @@ class DirectKeyAlgorithmTest { void testGetDecryptionKey() { def alg = new DirectKeyAlgorithm() DecryptionKeyRequest req = createMock(DecryptionKeyRequest) - def key = Jwts.ENC.A128GCM.keyBuilder().build() + def key = Jwts.ENC.A128GCM.key().build() expect(req.getKey()).andReturn(key) replay(req) def result = alg.getDecryptionKey(req) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy index 3040acbab..e38293ee7 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/ECCurveTest.groovy @@ -28,7 +28,7 @@ class ECCurveTest { @Test void testContainsTrue() { ECCurve curve = (ECCurve) Curves.P_256 - def pair = curve.keyPairBuilder().build() + def pair = curve.keyPair().build() ECPublicKey ecPub = (ECPublicKey) pair.getPublic() assertTrue(curve.contains(ecPub.getW())) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy index 6363b7d05..8854443aa 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy @@ -112,7 +112,7 @@ class EcSignatureAlgorithmTest { @Test void testSignWithInvalidKeyFieldLength() { - def keypair = Jwts.SIG.ES256.keyPairBuilder().build() + def keypair = Jwts.SIG.ES256.keyPair().build() def data = "foo".getBytes(StandardCharsets.UTF_8) def req = new DefaultSecureRequest(data, null, null, keypair.private) try { @@ -130,7 +130,7 @@ class EcSignatureAlgorithmTest { void testVerifyWithPrivateKey() { byte[] data = 'foo'.getBytes(StandardCharsets.UTF_8) algs().each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() def key = pair.getPrivate() def signRequest = new DefaultSecureRequest(data, null, null, key) byte[] signature = it.digest(signRequest) @@ -280,7 +280,7 @@ class EcSignatureAlgorithmTest { void verifySwarmTest() { algs().each { alg -> def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() assertNotNull keypair assertTrue keypair.getPublic() instanceof ECPublicKey assertTrue keypair.getPrivate() instanceof ECPrivateKey @@ -442,7 +442,7 @@ class EcSignatureAlgorithmTest { void legacySignatureCompatDefaultTest() { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES512 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def signature = Signature.getInstance(alg.jcaName as String) def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) signature.initSign(keypair.private) @@ -469,7 +469,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES512 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def signature = Signature.getInstance(alg.jcaName as String) def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) signature.initSign(keypair.private) @@ -488,7 +488,7 @@ class EcSignatureAlgorithmTest { byte[] forgedSig = new byte[64] def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, forgedSig) assertFalse alg.verify(request) @@ -505,7 +505,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, sig) assertFalse alg.verify(request) @@ -522,7 +522,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, sig) assertFalse alg.verify(request) @@ -534,7 +534,7 @@ class EcSignatureAlgorithmTest { def withoutSignature = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30" def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ" def alg = Jwts.SIG.ES256 - def keypair = alg.keyPairBuilder().build() + def keypair = alg.keyPair().build() def data = withoutSignature.getBytes(StandardCharsets.US_ASCII) def invalidSignature = Decoders.BASE64URL.decode(invalidEncodedSignature) def request = new DefaultVerifySecureDigestRequest(data, null, null, keypair.public, invalidSignature) 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 50465bf6c..6f1f8f65f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy @@ -54,7 +54,7 @@ class EdSignatureAlgorithmTest { @Test void testKeyPairBuilder() { algs.each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() assertNotNull pair.public assertTrue pair.public instanceof PublicKey String alg = pair.public.getAlgorithm() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy index cd156800c..9def66ca5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy @@ -361,7 +361,7 @@ class EdwardsCurveTest { @Test void testDerivePublicKeyFromPrivateKey() { for(def curve : EdwardsCurve.VALUES) { - def pair = curve.keyPairBuilder().build() // generate a standard key pair using the JCA APIs + def pair = curve.keyPair().build() // generate a standard key pair using the JCA APIs def pubKey = pair.getPublic() def derivedPubKey = EdwardsCurve.derivePublic(pair.getPrivate()) // ensure our derived key matches the original JCA one: diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy index 3118451c3..de4640e9e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriverTest.groovy @@ -26,7 +26,7 @@ class EdwardsPublicKeyDeriverTest { @Test void testDeriveWithNonEdwardsKey() { - def rsaPrivKey = Jwts.SIG.RS256.keyPairBuilder().build().getPrivate() + def rsaPrivKey = Jwts.SIG.RS256.keyPair().build().getPrivate() try { EdwardsPublicKeyDeriver.INSTANCE.apply(rsaPrivKey) fail() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy index 4448831f9..f7bc165bf 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/HmacAesAeadAlgorithmTest.groovy @@ -48,7 +48,7 @@ class HmacAesAeadAlgorithmTest { Jwts.ENC.A256CBC_HS512 ] for (AeadAlgorithm alg : algs) { - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() assertEquals alg.getKeyBitLength(), Bytes.bitLength(key.getEncoded()) } } @@ -58,7 +58,7 @@ class HmacAesAeadAlgorithmTest { def alg = Jwts.ENC.A128CBC_HS256 - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() def plaintext = "Hello World! Nice to meet you!".getBytes("UTF-8") diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index 4521111b8..25c9befa4 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -38,8 +38,8 @@ import static org.junit.Assert.* class JwksTest { - private static final SecretKey SKEY = Jwts.SIG.HS256.keyBuilder().build() - private static final java.security.KeyPair EC_PAIR = Jwts.SIG.ES256.keyPairBuilder().build() + private static final SecretKey SKEY = Jwts.SIG.HS256.key().build() + private static final java.security.KeyPair EC_PAIR = Jwts.SIG.ES256.keyPair().build() private static String srandom() { byte[] random = new byte[16] @@ -215,7 +215,7 @@ class JwksTest { void testSecretJwks() { Collection algs = Jwts.SIG.get().values().findAll({ it instanceof MacAlgorithm }) as Collection for (def alg : algs) { - SecretKey secretKey = alg.keyBuilder().build() + SecretKey secretKey = alg.key().build() def jwk = Jwks.builder().key(secretKey).id('id').build() assertEquals 'oct', jwk.getType() assertTrue jwk.containsKey('k') @@ -267,7 +267,7 @@ class JwksTest { for (def alg : algs) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() PublicKey pub = pair.getPublic() PrivateKey priv = pair.getPrivate() @@ -314,7 +314,7 @@ class JwksTest { for (SignatureAlgorithm alg : algs) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() ECPublicKey pubKey = pair.getPublic() as ECPublicKey EcPublicJwk jwk = Jwks.builder().key(pubKey).build() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy index 1975e85d9..3f8ab28a1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/KeyPairsTest.groovy @@ -62,7 +62,7 @@ class KeyPairsTest { @Test void testGetKeyECMismatch() { - KeyPair pair = Jwts.SIG.RS256.keyPairBuilder().build() + KeyPair pair = Jwts.SIG.RS256.keyPair().build() Class clazz = ECPublicKey try { KeyPairs.getKey(pair, clazz) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy index 0a80d1358..5620280fb 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/OctetJwksTest.groovy @@ -120,7 +120,7 @@ class OctetJwksTest { for (EdwardsCurve curve : EdwardsCurve.VALUES) { - def pair = curve.keyPairBuilder().build() + def pair = curve.keyPair().build() PublicKey pub = pair.getPublic() PrivateKey priv = pair.getPrivate() 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 6f879e00b..cf4523aa2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7516AppendixA3Test.groovy @@ -124,7 +124,7 @@ class RFC7516AppendixA3Test { } @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(CEK) } } 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 338f59bc3..f9c711f0e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RFC7517AppendixCTest.groovy @@ -284,7 +284,7 @@ class RFC7517AppendixCTest { //ensure that the KeyAlgorithm reflects test harness values: def enc = new HmacAesAeadAlgorithm(128) { @Override - SecretKeyBuilder keyBuilder() { + SecretKeyBuilder key() { return new FixedSecretKeyBuilder(RFC_CEK) } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy index 4e5ff7444..10e765b01 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy @@ -39,7 +39,7 @@ class RsaSignatureAlgorithmTest { @Test void testKeyPairBuilder() { algs().each { - def pair = it.keyPairBuilder().build() + def pair = it.keyPair().build() assertNotNull pair.public assertTrue pair.public instanceof RSAPublicKey assertEquals it.preferredKeyBitLength, pair.public.modulus.bitLength() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy index 759782984..384d87df0 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy @@ -36,23 +36,23 @@ class TestKeys { // ======================================================= // Secret Keys // ======================================================= - static SecretKey HS256 = Jwts.SIG.HS256.keyBuilder().build() - static SecretKey HS384 = Jwts.SIG.HS384.keyBuilder().build() - static SecretKey HS512 = Jwts.SIG.HS512.keyBuilder().build() + static SecretKey HS256 = Jwts.SIG.HS256.key().build() + static SecretKey HS384 = Jwts.SIG.HS384.key().build() + static SecretKey HS512 = Jwts.SIG.HS512.key().build() static Collection HS = Collections.setOf(HS256, HS384, HS512) static SecretKey A128GCM, A192GCM, A256GCM, A128KW, A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW static Collection AGCM static { - A128GCM = A128KW = A128GCMKW = Jwts.ENC.A128GCM.keyBuilder().build() - A192GCM = A192KW = A192GCMKW = Jwts.ENC.A192GCM.keyBuilder().build() - A256GCM = A256KW = A256GCMKW = Jwts.ENC.A256GCM.keyBuilder().build() + A128GCM = A128KW = A128GCMKW = Jwts.ENC.A128GCM.key().build() + A192GCM = A192KW = A192GCMKW = Jwts.ENC.A192GCM.key().build() + A256GCM = A256KW = A256GCMKW = Jwts.ENC.A256GCM.key().build() AGCM = Collections.setOf(A128GCM, A192GCM, A256GCM) } - static SecretKey A128CBC_HS256 = Jwts.ENC.A128CBC_HS256.keyBuilder().build() - static SecretKey A192CBC_HS384 = Jwts.ENC.A192CBC_HS384.keyBuilder().build() - static SecretKey A256CBC_HS512 = Jwts.ENC.A256CBC_HS512.keyBuilder().build() + static SecretKey A128CBC_HS256 = Jwts.ENC.A128CBC_HS256.key().build() + static SecretKey A192CBC_HS384 = Jwts.ENC.A192CBC_HS384.key().build() + static SecretKey A256CBC_HS512 = Jwts.ENC.A256CBC_HS512.key().build() static Collection ACBC = Collections.setOf(A128CBC_HS256, A192CBC_HS384, A256CBC_HS512) static Collection SECRET = new LinkedHashSet<>() diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy index cd87dcbae..89bca4ac5 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/EncryptionAlgorithmsTest.groovy @@ -108,7 +108,7 @@ class EncryptionAlgorithmsTest { for (AeadAlgorithm alg : registry.values()) { - def key = alg.keyBuilder().build() + def key = alg.key().build() def request = new DefaultAeadRequest(PLAINTEXT_BYTES, key, null) @@ -138,7 +138,7 @@ class EncryptionAlgorithmsTest { for (AeadAlgorithm alg : registry.values()) { - def key = alg.keyBuilder().build() + def key = alg.key().build() def req = new DefaultAeadRequest(PLAINTEXT_BYTES, null, null, key, AAD_BYTES) diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy index bccd8107e..5d1b0778d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy @@ -73,8 +73,8 @@ class KeysTest { "is not secure enough for any JWT HMAC-SHA algorithm. The JWT " + "JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a " + "size >= 256 bits (the key size must be greater than or equal to the hash " + - "output size). Consider using the Jwts.SIG.HS256.keyBuilder() method (or " + - "HS384.keyBuilder() or HS512.keyBuilder()) to create a key guaranteed to be secure enough " + + "output size). Consider using the Jwts.SIG.HS256.key() builder (or " + + "HS384.key() or HS512.key()) to create a key guaranteed to be secure enough " + "for your preferred HMAC-SHA algorithm. See " + "https://tools.ietf.org/html/rfc7518#section-3.2 for more information." as String, expected.message } @@ -131,7 +131,7 @@ class KeysTest { void testSecretKeyFor() { for (SecureDigestAlgorithm alg : Jwts.SIG.get().values()) { if (alg instanceof MacAlgorithm) { - SecretKey key = alg.keyBuilder().build() + SecretKey key = alg.key().build() assertEquals alg.getKeyBitLength(), Bytes.bitLength(key.getEncoded()) assertEquals alg.jcaName, key.algorithm assertEquals alg, DefaultJwtBuilder.forSigningKey(key) // https://github.com/jwtk/jjwt/issues/381 @@ -211,7 +211,7 @@ class KeysTest { if (alg instanceof RsaSignatureAlgorithm) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() assertNotNull pair PublicKey pub = pair.getPublic() @@ -224,7 +224,7 @@ class KeysTest { } else if (alg instanceof EdSignatureAlgorithm) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() assertNotNull pair PublicKey pub = pair.getPublic() @@ -237,7 +237,7 @@ class KeysTest { } else if (alg instanceof EcSignatureAlgorithm) { - def pair = alg.keyPairBuilder().build() + def pair = alg.keyPair().build() assertNotNull pair int len = alg.orderBitLength diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index fd4cb43dc..b846d1252 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -61,7 +61,7 @@ public class JavaReadmeTest { public void testExampleJwsHS() { // Create a test key suitable for the desired HMAC-SHA algorithm: MacAlgorithm alg = Jwts.SIG.HS512; //or HS384 or HS256 - SecretKey key = alg.keyBuilder().build(); + SecretKey key = alg.key().build(); String message = "Hello World!"; byte[] content = message.getBytes(StandardCharsets.UTF_8); @@ -82,7 +82,7 @@ public void testExampleJwsHS() { public void testExampleJwsRSA() { // Create a test key suitable for the desired RSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.RS512; //or PS512, RS256, etc... - KeyPair pair = alg.keyPairBuilder().build(); + KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his RSA private key: String jws = Jwts.builder().setSubject("Alice") @@ -104,7 +104,7 @@ public void testExampleJwsRSA() { public void testExampleJwsECDSA() { // Create a test key suitable for the desired ECDSA signature algorithm: SignatureAlgorithm alg = Jwts.SIG.ES512; //or ES256 or ES384 - KeyPair pair = alg.keyPairBuilder().build(); + KeyPair pair = alg.keyPair().build(); // Bob creates the compact JWS with his EC private key: String jws = Jwts.builder().setSubject("Alice") @@ -127,7 +127,7 @@ public void testExampleJweDir() { // Create a test key suitable for the desired payload encryption algorithm: // (A*GCM algorithms are recommended, but require JDK 8 or later) AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A128GCM, A192GCM, A256CBC-HS512, etc... - SecretKey key = enc.keyBuilder().build(); + SecretKey key = enc.key().build(); String message = "Live long and prosper."; byte[] content = message.getBytes(StandardCharsets.UTF_8); @@ -147,7 +147,7 @@ public void testExampleJweDir() { @Test public void testExampleJweRSA() { // Create a test KeyPair suitable for the desired RSA key algorithm: - KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.RS512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP or RSA1_5 @@ -174,7 +174,7 @@ public void testExampleJweRSA() { public void testExampleJweAESKW() { // Create a test SecretKey suitable for the desired AES Key Wrap algorithm: SecretKeyAlgorithm alg = Jwts.KEY.A256GCMKW; //or A192GCMKW, A128GCMKW, A256KW, etc... - SecretKey key = alg.keyBuilder().build(); + SecretKey key = alg.key().build(); // Chooose the Encryption Algorithm used to encrypt the payload: AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc... @@ -195,7 +195,7 @@ public void testExampleJweAESKW() { @Test public void testExampleJweECDHES() { // Create a test KeyPair suitable for the desired EC key algorithm: - KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.ES512.keyPair().build(); // Choose the key algorithm used encrypt the payload key: KeyAlgorithm alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc... @@ -255,7 +255,7 @@ public void testExampleJwePassword() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleSecretJwk() { - SecretKey key = Jwts.SIG.HS512.keyBuilder().build(); // or HS384 or HS256 + SecretKey key = Jwts.SIG.HS512.key().build(); // or HS384 or HS256 SecretJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -272,7 +272,7 @@ public void testExampleSecretJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleRsaPublicJwk() { - RSAPublicKey key = (RSAPublicKey) Jwts.SIG.RS512.keyPairBuilder().build().getPublic(); + RSAPublicKey key = (RSAPublicKey) Jwts.SIG.RS512.keyPair().build().getPublic(); RsaPublicJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -289,7 +289,7 @@ public void testExampleRsaPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleRsaPrivateJwk() { - KeyPair pair = Jwts.SIG.RS512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.RS512.keyPair().build(); RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic(); RSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate(); @@ -312,7 +312,7 @@ public void testExampleRsaPrivateJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEcPublicJwk() { - ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPairBuilder().build().getPublic(); + ECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPair().build().getPublic(); EcPublicJwk jwk = builder().key(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -329,7 +329,7 @@ public void testExampleEcPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEcPrivateJwk() { - KeyPair pair = Jwts.SIG.ES512.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.ES512.keyPair().build(); ECPublicKey pubKey = (ECPublicKey) pair.getPublic(); ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate(); @@ -352,7 +352,7 @@ public void testExampleEcPrivateJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEdEcPublicJwk() { - PublicKey key = Jwts.SIG.Ed25519.keyPairBuilder().build().getPublic(); + PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic(); OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -369,7 +369,7 @@ public void testExampleEdEcPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEdEcPrivateJwk() { - KeyPair pair = Jwts.SIG.Ed448.keyPairBuilder().build(); + KeyPair pair = Jwts.SIG.Ed448.keyPair().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); From fd89e6f15c0fd59a98c8a041f475a57e03487ddb Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:01:43 -0700 Subject: [PATCH 11/24] - Renamed ProtoJwkBuilder to DynamicJwkBuilder --- ...JwkBuilder.java => DynamicJwkBuilder.java} | 22 +++++++++---------- .../java/io/jsonwebtoken/security/Jwks.java | 4 ++-- ...der.java => DefaultDynamicJwkBuilder.java} | 8 +++---- .../impl/security/EcdhKeyAlgorithm.java | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) rename api/src/main/java/io/jsonwebtoken/security/{ProtoJwkBuilder.java => DynamicJwkBuilder.java} (94%) rename impl/src/main/java/io/jsonwebtoken/impl/security/{DefaultProtoJwkBuilder.java => DefaultDynamicJwkBuilder.java} (96%) diff --git a/api/src/main/java/io/jsonwebtoken/security/ProtoJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java similarity index 94% rename from api/src/main/java/io/jsonwebtoken/security/ProtoJwkBuilder.java rename to api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java index dd934d9aa..d2e6b4151 100644 --- a/api/src/main/java/io/jsonwebtoken/security/ProtoJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java @@ -28,14 +28,14 @@ import java.util.List; /** - * A prototypical {@link JwkBuilder} that coerces to a more type-specific builder based on the {@link Key} that will - * be represented as a JWK. + * A {@link JwkBuilder} that coerces to a more type-specific builder based on the {@link Key} that will be + * represented as a JWK. * * @param the type of Java {@link Key} represented by the created {@link Jwk}. * @param the type of {@link Jwk} created by the builder * @since JJWT_RELEASE_VERSION */ -public interface ProtoJwkBuilder> extends JwkBuilder> { +public interface DynamicJwkBuilder> extends JwkBuilder> { /** * Ensures the builder will create a {@link SecretJwk} for the specified Java {@link SecretKey}. @@ -234,8 +234,8 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link KeyPair#getPrivate() private key} MUST be an Edwards-curve private key as defined by * {@link #octetKey(PrivateKey)}. * - * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. - * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. + * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. + * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. * @param keyPair the Edwards-curve {@link KeyPair} to represent as an {@link OctetPrivateJwk}. * @return the builder coerced as an {@link OctetPrivateJwkBuilder} for continued method chaining. * @throws IllegalArgumentException if the {@code keyPair} does not contain Edwards-curve public and private key @@ -249,9 +249,9 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by * {@link #octetKey(PublicKey)}. * - * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. - * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce - * an {@link OctetPrivateJwk} if desired. + * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. + * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce + * an {@link OctetPrivateJwk} if desired. * @param chain the {@link X509Certificate} chain to inspect to find the Edwards-curve {@code PublicKey} to * represent as an {@link OctetPublicJwk}. * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. @@ -264,9 +264,9 @@ public interface ProtoJwkBuilder> extends JwkBui * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by * {@link #octetKey(PublicKey)}. * - * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. - * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce - * an {@link OctetPrivateJwk} if desired. + * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. + * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce + * an {@link OctetPrivateJwk} if desired. * @param chain the {@link X509Certificate} chain to inspect to find the Edwards-curve {@code PublicKey} to * represent as an {@link OctetPublicJwk}. * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. diff --git a/api/src/main/java/io/jsonwebtoken/security/Jwks.java b/api/src/main/java/io/jsonwebtoken/security/Jwks.java index 3dc9a76ed..22cfc2616 100644 --- a/api/src/main/java/io/jsonwebtoken/security/Jwks.java +++ b/api/src/main/java/io/jsonwebtoken/security/Jwks.java @@ -40,7 +40,7 @@ public final class Jwks { private Jwks() { } //prevent instantiation - private static final String BUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultProtoJwkBuilder"; + private static final String BUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultDynamicJwkBuilder"; private static final String PARSERBUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultJwkParserBuilder"; @@ -152,7 +152,7 @@ private HASH() { * * @return a new JWK builder instance, allowing for type-safe JWK builder coercion based on a provided key or key pair. */ - public static ProtoJwkBuilder builder() { + public static DynamicJwkBuilder builder() { return Classes.newInstance(BUILDER_CLASSNAME); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java similarity index 96% rename from impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java rename to impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java index 709f949fd..b9f5c7c11 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultProtoJwkBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java @@ -18,13 +18,13 @@ import io.jsonwebtoken.lang.Arrays; import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Strings; +import io.jsonwebtoken.security.DynamicJwkBuilder; import io.jsonwebtoken.security.EcPrivateJwkBuilder; import io.jsonwebtoken.security.EcPublicJwkBuilder; import io.jsonwebtoken.security.Jwk; import io.jsonwebtoken.security.OctetPrivateJwkBuilder; import io.jsonwebtoken.security.OctetPublicJwkBuilder; import io.jsonwebtoken.security.PrivateJwkBuilder; -import io.jsonwebtoken.security.ProtoJwkBuilder; import io.jsonwebtoken.security.PublicJwkBuilder; import io.jsonwebtoken.security.RsaPrivateJwkBuilder; import io.jsonwebtoken.security.RsaPublicJwkBuilder; @@ -44,10 +44,10 @@ import java.util.List; @SuppressWarnings("unused") //used via reflection by io.jsonwebtoken.security.Jwks -public class DefaultProtoJwkBuilder> - extends AbstractJwkBuilder> implements ProtoJwkBuilder { +public class DefaultDynamicJwkBuilder> + extends AbstractJwkBuilder> implements DynamicJwkBuilder { - public DefaultProtoJwkBuilder() { + public DefaultDynamicJwkBuilder() { super(new DefaultJwkContext()); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java index 84fdae4eb..3bc33858c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcdhKeyAlgorithm.java @@ -25,6 +25,7 @@ import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.DecryptionKeyRequest; +import io.jsonwebtoken.security.DynamicJwkBuilder; import io.jsonwebtoken.security.EcPublicJwk; import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.Jwks; @@ -33,7 +34,6 @@ import io.jsonwebtoken.security.KeyRequest; import io.jsonwebtoken.security.KeyResult; import io.jsonwebtoken.security.OctetPublicJwk; -import io.jsonwebtoken.security.ProtoJwkBuilder; import io.jsonwebtoken.security.PublicJwk; import io.jsonwebtoken.security.Request; import io.jsonwebtoken.security.SecureRequest; @@ -183,7 +183,7 @@ public KeyResult getEncryptionKey(KeyRequest request) throws Security KeyPair pair; // generated (ephemeral) key pair final SecureRandom random = ensureSecureRandom(request); - ProtoJwkBuilder jwkBuilder = Jwks.builder().random(random); + DynamicJwkBuilder jwkBuilder = Jwks.builder().random(random); if (publicKey instanceof ECKey) { ECKey ecPublicKey = (ECKey) publicKey; From a1fa013d9922839c0dd1ef3a7302b3a045254130 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 14:16:11 -0700 Subject: [PATCH 12/24] minor JavaDoc typo fix --- api/src/main/java/io/jsonwebtoken/JwtBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 5e77c414a..5ae7815bb 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -84,7 +84,7 @@ public interface JwtBuilder extends ClaimsMutator { * // ... etc ... * .{@link JwtBuilder.Header#and() and()} //return back to the JwtBuilder * - * .setSubject("Joe") // resume JwtBuilder calls + * .subject("Joe") // resume JwtBuilder calls * // ... etc ... * .compact(); * From 0f8364dce7980185bcb54a82b47cd3394f0c30cd Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 14:52:09 -0700 Subject: [PATCH 13/24] - Renamed JwtBuilder.Header to JwtBuilder.BuilderHeader to avoid naming/import conflict with io.jsonwebtoken.Header - Renamed JwtBuilder.Claims to JwtBuilder.BuilderClaims to avoid naming/import conflict with io.jsonwebtoken.Claims --- .../main/java/io/jsonwebtoken/JwtBuilder.java | 70 +++++++++---------- .../jsonwebtoken/impl/DefaultJwtBuilder.java | 59 +++++++++------- .../impl/DefaultJwtBuilderTest.groovy | 10 +-- 3 files changed, 74 insertions(+), 65 deletions(-) diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 5ae7815bb..802d64e77 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -71,7 +71,7 @@ public interface JwtBuilder extends ClaimsMutator { /** * Returns the {@code Header} to use to modify the constructed JWT's header name/value pairs as desired. - * When finished, callers may return to JWT construction via the {@link JwtBuilder.Header#and() and()} method. + * When finished, callers may return to JWT construction via the {@link BuilderHeader#and() and()} method. * For example: * *
                      @@ -82,33 +82,33 @@ public interface JwtBuilder extends ClaimsMutator {
                            *         .add("aName", aValue)
                            *         .add(myHeaderMap)
                            *         // ... etc ...
                      -     *         .{@link JwtBuilder.Header#and() and()} //return back to the JwtBuilder
                      +     *         .{@link BuilderHeader#and() and()} //return back to the JwtBuilder
                            *
                            *     .subject("Joe") // resume JwtBuilder calls
                            *     // ... etc ...
                            *     .compact();
                      * - * @return the {@link JwtBuilder.Header} to use for header construction. + * @return the {@link BuilderHeader} to use for header construction. * @since JJWT_RELEASE_VERSION */ - Header header(); + BuilderHeader header(); /** * Per standard Java idiom 'setter' conventions, this method sets (and fully replaces) any existing header with the * specified name/value pairs. This is a wrapper method for: * *
                      -     * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()}
                      + * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} * *

                      If you do not want to replace the existing header and only want to append to it, - * call {@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link Header#and() and()} instead.

                      + * call {@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} instead.

                      * * @param map the name/value pairs to set as (and potentially replace) the constructed JWT header. * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of - * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()} + * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} * (to replace all header parameters) or - * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()} + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} * to only append the {@code map} entries. This method will be removed before the 1.0 release. */ @SuppressWarnings("DeprecatedIsStillUsed") @@ -119,12 +119,12 @@ public interface JwtBuilder extends ClaimsMutator { * Adds the specified name/value pairs to the header. Any parameter with an empty or null value will remove the * entry from the header. This is a wrapper method for: *
                      -     * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()}
                      + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} * * @param params the header name/value pairs to append to the header. * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of - * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link Header#and() and()}. + * {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}. * This method will be removed before the 1.0 release. */ @SuppressWarnings("DeprecatedIsStillUsed") @@ -135,13 +135,13 @@ public interface JwtBuilder extends ClaimsMutator { * Adds the specified name/value pair to the header. If the value is {@code null} or empty, the parameter will * be removed from the header entirely. This is a wrapper method for: *
                      -     * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Header#and() and()}
                      + * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderHeader#and() and()} * * @param name the header parameter name * @param value the header parameter value * @return the builder for method chaining. * @deprecated since JJWT_RELEASE_VERSION in favor of - * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Header#and() and()}. + * {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderHeader#and() and()}
                      . * This method will be removed before the 1.0 release. */ @SuppressWarnings("DeprecatedIsStillUsed") @@ -150,7 +150,7 @@ public interface JwtBuilder extends ClaimsMutator { /** * Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the - * {@link Header#contentType(String) contentType} header value so the JWT recipient may inspect that value to + * {@link BuilderHeader#contentType(String) contentType} header value so the JWT recipient may inspect that value to * determine how to convert the byte array to the final data type as desired. In this case, consider using * {@link #content(byte[], String)} instead. * @@ -198,7 +198,7 @@ public interface JwtBuilder extends ClaimsMutator { /** * Convenience method that sets the JWT payload to be the specified content byte array and also sets the - * {@link Header#contentType(String) contentType} header value to a compact {@code cty} media type + * {@link BuilderHeader#contentType(String) contentType} header value to a compact {@code cty} media type * identifier to indicate the data format of the byte array. The JWT recipient can inspect the * {@code cty} value to determine how to convert the byte array to the final content type as desired. * @@ -213,7 +213,7 @@ public interface JwtBuilder extends ClaimsMutator { * *

                      If for some reason you do not wish to adhere to the JWT specification recommendation, do not call this * method - instead call {@link #content(byte[])} and set the header's - * {@link Header#contentType(String) contentType} independently. For example:

                      + * {@link BuilderHeader#contentType(String) contentType} independently. For example:

                      * *
                            * Jwts.builder()
                      @@ -237,7 +237,7 @@ public interface JwtBuilder extends ClaimsMutator {
                       
                           /**
                            * Returns the JWT {@code Claims} payload to modify as desired. When finished, callers may
                      -     * return to {@code JwtBuilder} configuration via the {@link JwtBuilder.Claims#and() and()} method.
                      +     * return to {@code JwtBuilder} configuration via the {@link BuilderClaims#and() and()} method.
                            * For example:
                            *
                            * 
                      @@ -250,16 +250,16 @@ public interface JwtBuilder extends ClaimsMutator {
                            *         .add("customClaim", customValue)
                            *         .add(myClaimsMap)
                            *         // ... etc ...
                      -     *         .{@link JwtBuilder.Claims#and() and()} //return back to the JwtBuilder
                      +     *         .{@link BuilderClaims#and() and()} //return back to the JwtBuilder
                            *
                            *     .signWith(key) // resume JwtBuilder calls
                            *     // ... etc ...
                            *     .compact();
                      * - * @return the {@link JwtBuilder.Claims} to use for Claims construction. + * @return the {@link BuilderClaims} to use for Claims construction. * @since JJWT_RELEASE_VERSION */ - Claims claims(); + BuilderClaims claims(); /** * Sets (and replaces) the JWT Claims payload with the specified name/value pairs. If you do not want the JWT @@ -282,7 +282,7 @@ public interface JwtBuilder extends ClaimsMutator { * This is a convenience wrapper for: * *
                      -     * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link BuilderClaims#and() and()}
                      * *

                      The content and claims properties are mutually exclusive - only one of the two may be used.

                      * @@ -290,7 +290,7 @@ public interface JwtBuilder extends ClaimsMutator { * @return the builder for method chaining. * @since 0.8 * @deprecated since JJWT_RELEASE_VERSION in favor of - * {@link #claims()}.{@link Claims#add(Map) add(Map)}.{@link Claims#and() and()}. + * {@link #claims()}.{@link BuilderClaims#add(Map) add(Map)}.{@link BuilderClaims#and() and()}. * This method will be removed before the 1.0 release. */ @SuppressWarnings("DeprecatedIsStillUsed") @@ -301,7 +301,7 @@ public interface JwtBuilder extends ClaimsMutator { * Sets a JWT claim, overwriting any existing claim with the same name. A {@code null} or empty * value will remove the claim entirely. This is a convenience wrapper for: *
                      -     * {@link #claims()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderClaims#and() and()} * * @param name the JWT Claims property name * @param value the value to set for the specified Claims property name @@ -315,7 +315,7 @@ public interface JwtBuilder extends ClaimsMutator { * with the same names. If any name has a {@code null} or empty value, that claim will be removed from the * Claims. This is a convenience wrapper for: *
                      -     * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link BuilderClaims#and() and()} * *

                      The content and claims properties are mutually exclusive - only one of the two may be used.

                      * @@ -330,7 +330,7 @@ public interface JwtBuilder extends ClaimsMutator { * iss
                      (issuer) value. A {@code null} value will remove the property from the Claims. * This is a convenience wrapper for: *
                      -     * {@link #claims()}.{@link ClaimsMutator#issuer(String) issuer(iss)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#issuer(String) issuer(iss)}.{@link BuilderClaims#and() and()} * * @param iss the JWT {@code iss} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -344,7 +344,7 @@ public interface JwtBuilder extends ClaimsMutator { * sub (subject) value. A {@code null} value will remove the property from the Claims. * This is a convenience wrapper for: *
                      -     * {@link #claims()}.{@link ClaimsMutator#subject(String) subject(sub)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#subject(String) subject(sub)}.{@link BuilderClaims#and() and()} * * @param sub the JWT {@code sub} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -358,7 +358,7 @@ public interface JwtBuilder extends ClaimsMutator { * aud (audience) value. A {@code null} value will remove the property from the Claims. * This is a convenience wrapper for: *
                      -     * {@link #claims()}.{@link ClaimsMutator#audience(String) audience(aud)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#audience(String) audience(aud)}.{@link BuilderClaims#and() and()} * * @param aud the JWT {@code aud} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -375,7 +375,7 @@ public interface JwtBuilder extends ClaimsMutator { * *

                      This is a convenience wrapper for:

                      *
                      -     * {@link #claims()}.{@link ClaimsMutator#expiration(Date) expiration(exp)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#expiration(Date) expiration(exp)}.{@link BuilderClaims#and() and()} * * @param exp the JWT {@code exp} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -392,7 +392,7 @@ public interface JwtBuilder extends ClaimsMutator { * *

                      This is a convenience wrapper for:

                      *
                      -     * {@link #claims()}.{@link ClaimsMutator#notBefore(Date) notBefore(nbf)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#notBefore(Date) notBefore(nbf)}.{@link BuilderClaims#and() and()} * * @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -409,7 +409,7 @@ public interface JwtBuilder extends ClaimsMutator { * *

                      This is a convenience wrapper for:

                      *
                      -     * {@link #claims()}.{@link ClaimsMutator#issuedAt(Date) issuedAt(iat)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#issuedAt(Date) issuedAt(iat)}.{@link BuilderClaims#and() and()} * * @param iat the JWT {@code iat} value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -428,7 +428,7 @@ public interface JwtBuilder extends ClaimsMutator { * *

                      This is a convenience wrapper for:

                      *
                      -     * {@link #claims()}.{@link ClaimsMutator#id(String) id(jti)}.{@link Claims#and() and()}
                      + * {@link #claims()}.{@link ClaimsMutator#id(String) id(jti)}.{@link BuilderClaims#and() and()} * * @param jti the JWT {@code jti} (id) value or {@code null} to remove the property from the Claims map. * @return the builder instance for method chaining. @@ -874,13 +874,13 @@ public interface JwtBuilder extends ClaimsMutator { String compact(); /** - * Claims for use with a {@link JwtBuilder} that supports method chaining for - * standard JWT Claims parameters. Once claims are configured, the associated - * {@link JwtBuilder} may be obtained with the {@link #and() and()} method for continued configuration. + * Claims for use with a {@link JwtBuilder} that supports method chaining for standard JWT Claims parameters. + * Once claims are configured, the associated {@link JwtBuilder} may be obtained with the {@link #and() and()} + * method for continued configuration. * * @since JJWT_RELEASE_VERSION */ - interface Claims extends MapMutator, ClaimsMutator { + interface BuilderClaims extends MapMutator, ClaimsMutator { /** * Returns the associated JwtBuilder for continued configuration. @@ -897,7 +897,7 @@ interface Claims extends MapMutator, ClaimsMutator, X509Builder
                      { + interface BuilderHeader extends JweHeaderMutator, X509Builder { /** * Returns the associated JwtBuilder for continued configuration. diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 061a9dd8a..b9f6061cc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -15,6 +15,7 @@ */ package io.jsonwebtoken.impl; +import io.jsonwebtoken.Header; import io.jsonwebtoken.JweHeader; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; @@ -62,14 +63,15 @@ public class DefaultJwtBuilder implements JwtBuilder { - public static final String PUB_KEY_SIGN_MSG = "PublicKeys may not be used to create digital signatures. " + "Only PrivateKeys may be used to create digital signatures, and PublicKeys are used to verify " + "digital signatures."; + public static final String PUB_KEY_SIGN_MSG = "PublicKeys may not be used to create digital signatures. " + + "Only PrivateKeys may be used to create digital signatures, and PublicKeys are used to verify " + + "digital signatures."; protected Provider provider; protected SecureRandom secureRandom; - private final BuilderHeader headerBuilder = new BuilderHeader(this); - - private final BuilderClaims claimsBuilder = new BuilderClaims(this); + private final DefaultBuilderHeader headerBuilder; + private final DefaultBuilderClaims claimsBuilder; protected byte[] content; @@ -91,13 +93,18 @@ public class DefaultJwtBuilder implements JwtBuilder { protected Encoder encoder = Encoders.BASE64URL; protected CompressionAlgorithm compressionAlgorithm; + public DefaultJwtBuilder() { + this.headerBuilder = new DefaultBuilderHeader(this); + this.claimsBuilder = new DefaultBuilderClaims(this); + } + @Override - public JwtBuilder.Header header() { + public BuilderHeader header() { return this.headerBuilder; } @Override - public JwtBuilder.Claims claims() { + public BuilderClaims claims() { return this.claimsBuilder; } @@ -237,7 +244,8 @@ public JwtBuilder signWith(Key key, io.jsonwebtoken.SignatureAlgorithm alg) thro public JwtBuilder signWith(io.jsonwebtoken.SignatureAlgorithm alg, byte[] secretKeyBytes) throws InvalidKeyException { Assert.notNull(alg, "SignatureAlgorithm cannot be null."); Assert.notEmpty(secretKeyBytes, "secret key byte array cannot be null or empty."); - Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); + Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. " + + "If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); SecretKey key = new SecretKeySpec(secretKeyBytes, alg.getJcaName()); return signWith(key, alg); } @@ -246,7 +254,8 @@ public JwtBuilder signWith(io.jsonwebtoken.SignatureAlgorithm alg, byte[] secret @Override public JwtBuilder signWith(io.jsonwebtoken.SignatureAlgorithm alg, String base64EncodedSecretKey) throws InvalidKeyException { Assert.hasText(base64EncodedSecretKey, "base64-encoded secret key cannot be null or empty."); - Assert.isTrue(alg.isHmac(), "Base64-encoded key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); + Assert.isTrue(alg.isHmac(), "Base64-encoded key bytes may only be specified for HMAC signatures. " + + "If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead."); byte[] bytes = Decoders.BASE64.decode(base64EncodedSecretKey); return signWith(alg, bytes); } @@ -464,21 +473,13 @@ public String compact() { } } - private io.jsonwebtoken.Header buildHeader() { - return new DefaultJwtHeaderBuilder(this.headerBuilder).build(); - } - private String compact(byte[] payload) { Assert.stateNotNull(sigAlg, "SignatureAlgorithm is required."); // invariant -// if (this.key != null && !(header instanceof JwsHeader)) { -// header = new DefaultJwsHeader(header); -// } - this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), sigAlg.getId()); - final io.jsonwebtoken.Header header = buildHeader(); + final Header header = this.headerBuilder.build(); byte[] headerBytes = headerSerializer.apply(header); String base64UrlEncodedHeader = encoder.encode(headerBytes); @@ -525,7 +526,7 @@ private String encrypt(byte[] payload) { this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), keyAlg.getId()); this.headerBuilder.put(DefaultJweHeader.ENCRYPTION_ALGORITHM.getId(), enc.getId()); - final io.jsonwebtoken.Header header = buildHeader(); + final Header header = this.headerBuilder.build(); byte[] headerBytes = this.headerSerializer.apply(header); final String base64UrlEncodedHeader = encoder.encode(headerBytes); @@ -543,15 +544,19 @@ private String encrypt(byte[] payload) { String base64UrlEncodedCiphertext = encoder.encode(ciphertext); String base64UrlEncodedTag = encoder.encode(tag); - return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR + base64UrlEncodedTag; + return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR + + base64UrlEncodedTag; } - private static class BuilderClaims extends DelegatingClaimsMutator - implements JwtBuilder.Claims { + private static class DefaultBuilderClaims extends DelegatingClaimsMutator + implements BuilderClaims { private final JwtBuilder builder; - private BuilderClaims(JwtBuilder builder) { + private DefaultBuilderClaims(JwtBuilder builder) { super(); this.builder = builder; } @@ -561,16 +566,16 @@ public JwtBuilder and() { return this.builder; } - public io.jsonwebtoken.Claims build() { + private io.jsonwebtoken.Claims build() { return new DefaultClaims(this.DELEGATE); } } - private static class BuilderHeader extends DefaultJweHeaderBuilder
                      implements JwtBuilder.Header { + private static class DefaultBuilderHeader extends DefaultJweHeaderBuilder implements BuilderHeader { private final JwtBuilder builder; - private BuilderHeader(JwtBuilder builder) { + private DefaultBuilderHeader(JwtBuilder builder) { super(); this.builder = Assert.notNull(builder, "JwtBuilder cannot be null."); } @@ -579,5 +584,9 @@ private BuilderHeader(JwtBuilder builder) { public JwtBuilder and() { return builder; } + + private Header build() { + return new DefaultJwtHeaderBuilder(this).build(); + } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index acadf4d78..de39adb9e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -134,28 +134,28 @@ class DefaultJwtBuilderTest { void testSetHeader() { def h = Jwts.header().add('foo', 'bar').build() builder.setHeader(h) - assertEquals h, builder.buildHeader() + assertEquals h, builder.headerBuilder.build() } @Test void testSetHeaderFromMap() { def m = [foo: 'bar'] builder.setHeader(m) - assertEquals builder.buildHeader().foo, 'bar' + assertEquals builder.headerBuilder.build().foo, 'bar' } @Test void testSetHeaderParams() { def m = [a: 'b', c: 'd'] builder.setHeaderParams(m) - assertEquals builder.buildHeader().a, 'b' - assertEquals builder.buildHeader().c, 'd' + assertEquals builder.headerBuilder.build().a, 'b' + assertEquals builder.headerBuilder.build().c, 'd' } @Test void testSetHeaderParam() { builder.setHeaderParam('foo', 'bar') - assertEquals builder.buildHeader().foo, 'bar' + assertEquals builder.headerBuilder.build().foo, 'bar' } @Test From 104769e85329b72d1d8199bde79a3e9e5a191a84 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:30:00 -0700 Subject: [PATCH 14/24] minor cleanup --- api/src/main/java/io/jsonwebtoken/Jwts.java | 18 +++++++++--------- .../java/io/jsonwebtoken/impl/DefaultJwe.java | 4 ++-- .../java/io/jsonwebtoken/impl/DefaultJws.java | 4 ++-- .../io/jsonwebtoken/impl/DefaultJwtParser.java | 10 +++++----- .../jsonwebtoken/impl/DefaultTokenizedJwt.java | 10 +++++----- .../io/jsonwebtoken/impl/TokenizedJwt.java | 2 +- .../jsonwebtoken/impl/JwtTokenizerTest.groovy | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java index 84d6d8e6f..26ae06714 100644 --- a/api/src/main/java/io/jsonwebtoken/Jwts.java +++ b/api/src/main/java/io/jsonwebtoken/Jwts.java @@ -1056,15 +1056,6 @@ public static Claims claims(Map claims) { return claims().add(claims).build(); } - /** - * 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 parser() { - return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder"); - } - /** * Returns a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized * strings. @@ -1076,6 +1067,15 @@ public static JwtBuilder builder() { return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder"); } + /** + * 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 parser() { + return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParserBuilder"); + } + /** * Private constructor, prevent instantiation. */ diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java index 0e543ef15..cdc816a5e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwe.java @@ -29,8 +29,8 @@ public class DefaultJwe

                      extends DefaultProtectedJwt implements private final byte[] iv; - public DefaultJwe(JweHeader header, P body, byte[] iv, byte[] aadTag) { - super(header, body, aadTag, DIGEST_NAME); + public DefaultJwe(JweHeader header, P payload, byte[] iv, byte[] aadTag) { + super(header, payload, aadTag, DIGEST_NAME); this.iv = Assert.notEmpty(iv, "Initialization vector cannot be null or empty."); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java index ce53dcad6..f97dfe0cc 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJws.java @@ -25,8 +25,8 @@ public class DefaultJws

                      extends DefaultProtectedJwt implements private final String signature; - public DefaultJws(JwsHeader header, P body, String signature) { - super(header, body, Decoders.BASE64URL.decode(signature), DIGEST_NAME); + public DefaultJws(JwsHeader header, P payload, String signature) { + super(header, payload, Decoders.BASE64URL.decode(signature), DIGEST_NAME); this.signature = signature; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index e10fbbff7..d12837cf9 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -304,7 +304,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe } //re-create the jwt part without the signature. This is what is needed for signature verification: - String jwtWithoutSignature = tokenized.getProtected() + SEPARATOR_CHAR + tokenized.getBody(); + String jwtWithoutSignature = tokenized.getProtected() + SEPARATOR_CHAR + tokenized.getPayload(); byte[] data = jwtWithoutSignature.getBytes(StandardCharsets.US_ASCII); byte[] signature = decode(tokenized.getDigest(), "JWS signature"); @@ -388,9 +388,9 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe throw new MalformedJwtException(msg); } - // =============== Body ================= - byte[] payload = decode(tokenized.getBody(), "payload"); - if (tokenized instanceof TokenizedJwe && Arrays.length(payload) == 0) { // Only JWS body can be empty per https://github.com/jwtk/jjwt/pull/540 + // =============== Payload ================= + byte[] payload = decode(tokenized.getPayload(), "payload"); + if (tokenized instanceof TokenizedJwe && Arrays.length(payload) == 0) { // Only JWS payload can be empty per https://github.com/jwtk/jjwt/pull/540 String msg = "Compact JWE strings MUST always contain a payload (ciphertext)."; throw new MalformedJwtException(msg); } @@ -466,7 +466,7 @@ private void verifySignature(final TokenizedJwt tokenized, final JwsHeader jwsHe payload = result.getPayload(); } else if (hasDigest && this.signingKeyResolver == null) { //TODO: for 1.0, remove the == null check - // not using a signing key resolver, so we can verify the signature before reading the body, which is + // not using a signing key resolver, so we can verify the signature before reading the payload, which is // always safer: verifySignature(tokenized, ((JwsHeader) header), alg, new LocatingKeyResolver(this.keyLocator), null, null); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java index 7f5887d6b..9a54b9b4e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultTokenizedJwt.java @@ -24,12 +24,12 @@ class DefaultTokenizedJwt implements TokenizedJwt { private final String protectedHeader; - private final String body; + private final String payload; private final String digest; - DefaultTokenizedJwt(String protectedHeader, String body, String digest) { + DefaultTokenizedJwt(String protectedHeader, String payload, String digest) { this.protectedHeader = protectedHeader; - this.body = body; + this.payload = payload; this.digest = digest; } @@ -39,8 +39,8 @@ public String getProtected() { } @Override - public String getBody() { - return this.body; + public String getPayload() { + return this.payload; } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java b/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java index e52cfdd5a..948e4f87f 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/TokenizedJwt.java @@ -33,7 +33,7 @@ public interface TokenizedJwt { * * @return the Payload for a JWS or Ciphertext for a JWE. */ - String getBody(); + String getPayload(); /** * Returns the Signature for JWS or AAD Tag for JWE. diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy index 743071eff..1fec882b1 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/JwtTokenizerTest.groovy @@ -65,7 +65,7 @@ class JwtTokenizerTest { assertEquals 'header', tjwe.getProtected() assertEquals 'encryptedKey', tjwe.getEncryptedKey() assertEquals 'initializationVector', tjwe.getIv() - assertEquals 'body', tjwe.getBody() + assertEquals 'body', tjwe.getPayload() assertEquals 'authenticationTag', tjwe.getDigest() } } From 367e7300dd769b2cc2c5c648888dc476536c0cce Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:01:42 -0700 Subject: [PATCH 15/24] doc/naming updates --- README.md | 66 +++++++++++-------- .../jsonwebtoken/impl/DefaultJwtParser.java | 6 +- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 205c83f03..f51d1606b 100644 --- a/README.md +++ b/README.md @@ -755,9 +755,9 @@ Now that we've had a quickstart 'taste' of how to create and parse JWTs, let's c You create a JWT as follows: 1. Use the `Jwts.builder()` method to create a `JwtBuilder` instance. -2. Set any [`header` parameters](#jwt-header) as desired. +2. Optionally set any [`header` parameters](#jwt-header) as desired. 3. Call builder methods to set the `payload` [content](#jwt-content) or [claims](#jwt-claims). -4. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT, respectively. +4. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT. 5. Call the `compact()` method to produce the resulting compact JWT string. For example: @@ -765,7 +765,7 @@ For example: ```java String jwt = Jwts.builder() // (1) - .header() // (2) + .header() // (2) optional .keyId("aKeyId") .and() @@ -922,15 +922,15 @@ especially for representing identity claims. As a result, the `JwtBuilder` supports two distinct payload options: -* `content` if you would like the `payload` to be arbitrary byte array content, and -* `claims` (and supporting helper methods) if you would like the `payload` to be a JSON Claims `Object`. +* `content` if you would like the payload to be arbitrary byte array content, or +* `claims` (and supporting helper methods) if you would like the payload to be a JSON Claims `Object`. -Either option may be used, but not both. Using both will cause `build()` to throw an exception. +Either option may be used, but not both. Using both will cause `compact()` to throw an exception. #### Arbitrary Content -You can set the JWT `payload` to be any arbitrary byte array content by using the `JwtBuilder` `content` method. +You can set the JWT payload to be any arbitrary byte array content by using the `JwtBuilder` `content` method. For example: ```java @@ -963,8 +963,9 @@ For these reasons, it is strongly recommended to use the two-argument `content` #### JWT Claims -Instead of a content byte array, a JWT `payload` may contain assertions or claims for a JWT recipient. In -this case, the `payload` is a 'claims' JSON `Object`, and JJWT supports this with a type-safe `Claims` instance. +Instead of a content byte array, a JWT payload may contain assertions or claims for a JWT recipient. In +this case, the payload is a `Claims` JSON `Object`, and JJWT supports claims creation with type-safe +builder methods. ##### Standard Claims @@ -1015,7 +1016,7 @@ Each time `claim` is called, it simply appends the key-value pair to an internal overwriting any existing identically-named key/value pair. Obviously, you do not need to call `claim` for any [standard claim name](#jws-create-claims-standard), and it is -recommended instead to call the standard respective type-safe setter method as this enhances readability. +recommended instead to call the standard respective type-safe named builder method as this enhances readability. @@ -2533,10 +2534,13 @@ This is true for all secret or private key members in `SecretJwk` and `PrivateJw ## Compression -**The JWT specification only standardizes this feature for JWEs (Encrypted JWTs) however JJWT supports it for JWS -(Signed JWTs) as well**. If you are positive that a JWT you create with JJWT -will _also_ be parsed with JJWT, you can use this feature with both JWEs and JWSs, otherwise it is best to only use it -for JWEs. +> **Warning** +> +> **The JWT specification only standardizes compression for JWEs (Encrypted JWTs), however JJWT supports it for JWS +> (Signed JWTs) as well**. +> +> If you are positive that a JWT you create with JJWT will _also_ be parsed with JJWT, +> you can use this feature with both JWEs and JWSs, otherwise it is best to only use it for JWEs. If a JWT's `payload` is sufficiently large - that is, it is a large content byte array or JSON with a lot of name/value pairs (or individual values are very large or verbose) - you can reduce the size of the compact JWT by @@ -2550,31 +2554,37 @@ If you want to compress your JWT, you can use the `JwtBuilder`'s `compressWith( example: ```java - Jwts.builder() +Jwts.builder() - .compressWith(Jwts.ZIP.DEF) // or Jwts.ZIP.GZIP + .compressWith(Jwts.ZIP.DEF) // DEFLATE compression algorithm // .. etc ... ``` -If you use the `DEF`LATE or `GZIP` Compression Codecs - that's it, you're done. You don't have to do anything during -parsing or configure the `JwtParserBuilder` for compression - JJWT will automatically decompress the payload as -expected. - -> **Note** -> -> JJWT does not support compression for Unprotected JWTs because they are susceptible to various compression -> vulnerability attacks (memory exhaustion, denial of service, etc.). +If you use any of the algorithm constants in the `Jwts.ZIP` class, that's it, you're done. You don't have to +do anything during parsing or configure the `JwtParserBuilder` for compression - JJWT will automatically decompress +the payload as expected. ### Custom Compression Algorithm -If the default `DEF` or `GZIP` compression algorithms are not suitable for your needs, you can create your own +If the default `Jwts.ZIP` compression algorithms are not suitable for your needs, you can create your own `CompressionAlgorithm` implementation(s). Just as you would with the default algorithms, you may specify that you want a JWT compressed by calling the -`JwtBuilder`'s `compressWith` method, supplying your custom implementation instance. When you call `compressWith`, -the JWT `payload` will be compressed with your algorithm, and the +`JwtBuilder`'s `compressWith` method, supplying your custom implementation instance. For example: + +```java +CompressionAlgorithm myAlg = new MyCompressionAlgorithm(); + +Jwts.builder() + + .compressWith(myAlg) // <---- + + // .. etc ... +``` + +When you call `compressWith`, the JWT `payload` will be compressed with your algorithm, and the [`zip` (Compression Algorithm)](https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3) header will automatically be set to the value returned by your algorithm's `algorithm.getId()` method as required by the JWT specification. @@ -2593,7 +2603,7 @@ Jwts.parser() ``` This adds additional `CompressionAlgorithm` implementations to the parser's overall total set of supported compression -algorithms (which already includes the `DEF` and `GZIP` codecs by default). +algorithms (which already includes all of the `Jwts.ZIP` algorithms by default). The parser will then automatically check to see if the JWT `zip` header has been set to see if a compression algorithm has been used to compress the JWT. If set, the parser will automatically look up your diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java index d12837cf9..940b0cf4e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java @@ -142,7 +142,7 @@ public class DefaultJwtParser implements JwtParser { private final Locator keyLocator; - private final Decoder base64UrlDecoder; + private final Decoder decoder; private final Deserializer> deserializer; @@ -177,7 +177,7 @@ public class DefaultJwtParser implements JwtParser { this.clock = Assert.notNull(clock, "Clock cannot be null."); this.allowedClockSkewMillis = allowedClockSkewMillis; this.expectedClaims = Jwts.claims().add(expectedClaims); - this.base64UrlDecoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); + this.decoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null."); this.deserializer = Assert.notNull(deserializer, "Deserializer cannot be null."); this.sigAlgFn = new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.SIG.get(), extraSigAlgs, MISSING_JWS_ALG_MSG); @@ -709,7 +709,7 @@ public Jwe onClaimsJwe(Jwe jwe) { protected byte[] decode(String base64UrlEncoded, String name) { try { - return base64UrlDecoder.decode(base64UrlEncoded); + return decoder.decode(base64UrlEncoded); } catch (DecodingException e) { String msg = "Invalid Base64Url " + name + ": " + base64UrlEncoded; throw new MalformedJwtException(msg, e); From 4138b9148cbae8a09535adf07c40d49468f68006 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 12:34:08 -0700 Subject: [PATCH 16/24] doc/naming updates --- README.md | 6 +- .../io/jsonwebtoken/JwtParserBuilder.java | 117 ++++++---- .../impl/DefaultJwtParserBuilder.java | 18 +- .../java/io/jsonwebtoken/impl/IdLocator.java | 17 +- .../impl/DefaultJwtParserBuilderTest.groovy | 200 +++++++++++++++++- 5 files changed, 297 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index f51d1606b..8bf8b9d9b 100644 --- a/README.md +++ b/README.md @@ -730,7 +730,7 @@ that pack a punch! > **Note** > > **Type-safe JWTs:** To get a type-safe `Claims` JWT result, call the `parseClaimsJws` method (since there are many -similar methods available). You will get an `UnsupportedJwtException` if you parse your JWT with wrong method.]() +similar methods available). You will get an `UnsupportedJwtException` if you parse your JWT with wrong method. But what if parsing or signature validation failed? You can catch `JwtException` and react accordingly: @@ -756,7 +756,7 @@ You create a JWT as follows: 1. Use the `Jwts.builder()` method to create a `JwtBuilder` instance. 2. Optionally set any [`header` parameters](#jwt-header) as desired. -3. Call builder methods to set the `payload` [content](#jwt-content) or [claims](#jwt-claims). +3. Call builder methods to set the payload [content](#jwt-content) or [claims](#jwt-claims). 4. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT. 5. Call the `compact()` method to produce the resulting compact JWT string. @@ -2536,7 +2536,7 @@ This is true for all secret or private key members in `SecretJwk` and `PrivateJw > **Warning** > -> **The JWT specification only standardizes compression for JWEs (Encrypted JWTs), however JJWT supports it for JWS +> **The JWT specifications tandardizes compression for JWEs (Encrypted JWTs) ONLY, however JJWT supports it for JWS > (Signed JWTs) as well**. > > If you are positive that a JWT you create with JJWT will _also_ be parsed with JJWT, diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index 20e0468bb..2d0f7238c 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -355,7 +355,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the signature verification key to use to verify all encountered JWS digital signatures. * @return the parser builder for method chaining. - * @see #verifyWith(PublicKey) + * @see #verifyWith(PublicKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder verifyWith(SecretKey key); @@ -376,7 +376,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the signature verification key to use to verify all encountered JWS digital signatures. * @return the parser builder for method chaining. - * @see #verifyWith(SecretKey) + * @see #verifyWith(SecretKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder verifyWith(PublicKey key); @@ -398,7 +398,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. * @return the parser builder for method chaining. - * @see #decryptWith(PrivateKey) + * @see #decryptWith(PrivateKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder decryptWith(SecretKey key); @@ -419,7 +419,7 @@ public interface JwtParserBuilder extends Builder { * * @param key the algorithm-specific decryption key to use to decrypt all encountered JWEs. * @return the parser builder for method chaining. - * @see #decryptWith(SecretKey) + * @see #decryptWith(SecretKey) * @since JJWT_RELEASE_VERSION */ JwtParserBuilder decryptWith(PrivateKey key); @@ -499,82 +499,109 @@ public interface JwtParserBuilder extends Builder { /** * Adds the specified compression algorithms to the parser's total set of supported compression algorithms, - * overwriting any previously-added compression algorithms with the same {@link CompressionAlgorithm#getId() id}s. - * If the parser encounters a JWT {@code zip} header value that matches a compression algorithm's - * {@link CompressionAlgorithm#getId() id}, that algorithm will be used for decompression. + * replacing any existing ones with identical {@link Identifiable#getId() id}s. + * If the parser encounters a JWT {@code zip} header value that equals a compression algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used for decompression. * - *

                      There may be only one registered {@code CompressionAlgorithm} per {@code id}, and the {@code algs} - * collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} - * collection, the later element will evict any previously-added algorithm with the same {@code id}.

                      + *

                      There may be only one registered {@code CompressionAlgorithm} per CaSe-SeNsItIvE {@code id}, and the + * {@code algs} collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} + * collection, the later algorithm will evict any existing algorithm with the same {@code id}.

                      + * + *

                      Standard Algorithms and Overrides

                      * - *

                      Finally, {@link Jwts.ZIP#DEF} and {@link Jwts.ZIP#GZIP} algorithms are added last, - * after those in the {@code algs} collection, to ensure that JWA standard algorithms cannot be - * accidentally replaced.

                      + *

                      The {@link Jwts.ZIP} compression algorithms are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation. + * This is to allow application developers to favor their own implementations over JJWT's default implementations + * if necessary (for example, to support legacy or custom behavior). * - * @param algs collection of compression algorithms to add to the parser's total set of supported compression algorithms. + * @param algs collection of compression algorithms to add to the parser's total set of supported compression + * algorithms, replacing any existing ones with the same exact (CaSe-SeNsItIvE) + * {@link CompressionAlgorithm#getId() id}s. * @return the builder for method chaining. + * @see Jwts.ZIP * @since JJWT_RELEASE_VERSION */ JwtParserBuilder addCompressionAlgorithms(Collection algs); /** * Adds the specified AEAD encryption algorithms to the parser's total set of supported encryption algorithms, - * overwriting any previously-added algorithms with the same {@link AeadAlgorithm#getId() id}s. + * replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) {@link AeadAlgorithm#getId() id}s. + * If the parser encounters a JWT {@code enc} header value that equals an encryption algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used for decryption. + * + *

                      There may be only one registered {@code AeadAlgorithm} per algorithm {@code id}, and the {@code algs} + * collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} + * collection, the later algorithm will evict any existing algorithm with the same {@code id}.

                      * - *

                      There may be only one registered {@code AeadAlgorithm} per algorithm {@code id}, and the {@code encAlgs} - * collection is added in iteration order; if a duplicate id is found when iterating the {@code encAlgs} - * collection, the later element will evict any previously-added algorithm with the same {@code id}.

                      + *

                      Standard Algorithms and Overrides

                      * - *

                      Finally, the {@link Jwts.ENC JWA standard encryption algorithms} are added last, - * after those in the {@code encAlgs} collection, to ensure that JWA standard algorithms cannot be - * accidentally replaced.

                      + *

                      All JWA standard encryption algorithms in {@link Jwts.ENC} are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation. + * This is to allow application developers to favor their own implementations over JJWT's default implementations + * if necessary (for example, to support legacy or custom behavior). * - * @param encAlgs collection of AEAD encryption algorithms to add to the parser's total set of supported - * encryption algorithms. + * @param algs collection of AEAD encryption algorithms to add to the parser's total set of supported + * encryption algorithms, replacing any existing algorithms with the same + * {@link AeadAlgorithm#getId() id}s. * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder addEncryptionAlgorithms(Collection encAlgs); + JwtParserBuilder addEncryptionAlgorithms(Collection algs); /** * Adds the specified signature algorithms to the parser's total set of supported signature algorithms, - * overwriting any previously-added algorithms with the same - * {@link Identifiable#getId() id}s. + * replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) {@link Identifiable#getId() id}s. + * If the parser encounters a JWS {@code alg} header value that equals a signature algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used for signature verification. * *

                      There may be only one registered {@code SecureDigestAlgorithm} per algorithm {@code id}, and the - * {@code sigAlgs} collection is added in iteration order; if a duplicate id is found when iterating the - * {@code sigAlgs} collection, the later element will evict any previously-added algorithm with the same - * {@code id}.

                      + * {@code algs} collection is added in iteration order; if a duplicate id is found when iterating the + * {@code algs} argument, the later algorithm will evict any existing algorithm with the same {@code id}.

                      * - *

                      Finally, the {@link Jwts.SIG JWA standard signature and MAC algorithms} are - * added last, after those in the {@code sigAlgs} collection, to ensure that JWA standard algorithms - * cannot be accidentally replaced.

                      + *

                      Standard Algorithms and Overrides

                      * - * @param sigAlgs collection of signing algorithms to add to the parser's total set of supported signature - * algorithms. + *

                      All JWA standard signature and MAC algorithms in {@link Jwts.SIG} are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard + * algorithm implementation. This is to allow application developers to favor their own implementations over + * JJWT's default implementations if necessary (for example, to support legacy or custom behavior). + * + * @param algs collection of signature algorithms to add to the parser's total set of supported signature + * algorithms, replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) + * {@link Identifiable#getId() id}s. * @return the builder for method chaining. + * @see Algorithm Name (id) requirements * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder addSignatureAlgorithms(Collection> sigAlgs); + JwtParserBuilder addSignatureAlgorithms(Collection> algs); /** * Adds the specified key management algorithms to the parser's total set of supported key algorithms, - * overwriting any previously-added algorithms with the same {@link KeyAlgorithm#getId() id}s. + * replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) {@link KeyAlgorithm#getId() id}s. + * If the parser encounters a JWE {@code alg} header value that equals a key management algorithm's + * {@link Identifiable#getId() id}, that algorithm will be used to obtain the content decryption key. + * + *

                      There may be only one registered {@code KeyAlgorithm} per algorithm {@code id}, and the {@code algs} + * collection is added in iteration order; if a duplicate id is found when iterating the {@code algs} + * argument, the later algorithm will evict any existing algorithm with the same {@code id}.

                      * - *

                      There may be only one registered {@code KeyAlgorithm} per algorithm {@code id}, and the {@code keyAlgs} - * collection is added in iteration order; if a duplicate id is found when iterating the {@code keyAlgs} - * collection, the later element will evict any previously-added algorithm with the same {@code id}.

                      + *

                      Standard Algorithms and Overrides

                      * - *

                      Finally, the {@link Jwts.KEY#get() JWA standard key management algorithms} - * are added last, after those in the {@code keyAlgs} collection, to ensure that JWA standard algorithms - * cannot be accidentally replaced.

                      + *

                      All JWA standard key management algorithms in {@link Jwts.KEY} are supported by default and do not need + * to be added via this method, but beware: any algorithm in the {@code algs} collection with a + * JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation. + * This is to allow application developers to favor their own implementations over JJWT's default implementations + * if necessary (for example, to support legacy or custom behavior). * - * @param keyAlgs collection of key management algorithms to add to the parser's total set of supported key - * management algorithms. + * @param algs collection of key management algorithms to add to the parser's total set of supported key + * management algorithms, replacing any existing algorithms with the same exact (CaSe-SeNsItIvE) + * {@link KeyAlgorithm#getId() id}s. * @return the builder for method chaining. * @since JJWT_RELEASE_VERSION */ - JwtParserBuilder addKeyAlgorithms(Collection> keyAlgs); + JwtParserBuilder addKeyAlgorithms(Collection> algs); /** *

                      Deprecated as of JJWT JJWT_RELEASE_VERSION. This method will be removed before the 1.0 release.

                      diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index c67431ea6..795293693 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -270,23 +270,23 @@ public JwtParserBuilder addCompressionAlgorithms(Collection encAlgs) { - Assert.notEmpty(encAlgs, "Additional AeadAlgorithm collection cannot be null or empty."); - this.extraEncAlgs.addAll(encAlgs); + public JwtParserBuilder addEncryptionAlgorithms(Collection algs) { + Assert.notEmpty(algs, "Additional AeadAlgorithm collection cannot be null or empty."); + this.extraEncAlgs.addAll(algs); return this; } @Override - public JwtParserBuilder addSignatureAlgorithms(Collection> sigAlgs) { - Assert.notEmpty(sigAlgs, "Additional SignatureAlgorithm collection cannot be null or empty."); - this.extraSigAlgs.addAll(sigAlgs); + public JwtParserBuilder addSignatureAlgorithms(Collection> algs) { + Assert.notEmpty(algs, "Additional SignatureAlgorithm collection cannot be null or empty."); + this.extraSigAlgs.addAll(algs); return this; } @Override - public JwtParserBuilder addKeyAlgorithms(Collection> keyAlgs) { - Assert.notEmpty(keyAlgs, "Additional KeyAlgorithm collection cannot be null or empty."); - this.extraKeyAlgs.addAll(keyAlgs); + public JwtParserBuilder addKeyAlgorithms(Collection> algs) { + Assert.notEmpty(algs, "Additional KeyAlgorithm collection cannot be null or empty."); + this.extraKeyAlgs.addAll(algs); return this; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java b/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java index 3b069eef3..2bb4752b3 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/IdLocator.java @@ -47,9 +47,22 @@ public IdLocator(Field field, Registry registry, Collection all = new LinkedHashSet<>(Collections.size(registry) + Collections.size(extras)); + all.addAll(registry.values()); // defaults MUST come before extras to allow extras to override if necessary all.addAll(extras); - all.addAll(registry.values()); - this.registry = new IdRegistry<>(field.getName(), all); + + // The registry requires CaSe-SeNsItIvE keys on purpose - all JWA standard algorithm identifiers + // (JWS 'alg', JWE 'enc', JWK 'kty', etc) are all case-sensitive per via the following RFC language: + // + // This name is a case-sensitive ASCII string. Names may not match other registered names in a + // case-insensitive manner unless the Designated Experts state that there is a compelling reason to + // allow an exception. + // + // References: + // - JWS/JWE alg and JWE enc 'Algorithm Name': https://www.rfc-editor.org/rfc/rfc7518.html#section-7.1.1 + // - JWE zip 'Compression Algorithm Value': https://www.rfc-editor.org/rfc/rfc7518.html#section-7.3.1 + // - JWK '"kty" Parameter Value': https://www.rfc-editor.org/rfc/rfc7518.html#section-7.4.1 + + this.registry = new IdRegistry<>(field.getName(), all); // do not use the caseSensitive ctor argument - must be false } private static String type(Header header) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index 6db65e00c..100564620 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -24,10 +24,12 @@ import io.jsonwebtoken.io.Decoder import io.jsonwebtoken.io.DecodingException import io.jsonwebtoken.io.DeserializationException import io.jsonwebtoken.io.Deserializer +import io.jsonwebtoken.security.* import org.hamcrest.CoreMatchers import org.junit.Before import org.junit.Test +import javax.crypto.SecretKey import java.security.Provider import static org.easymock.EasyMock.* @@ -101,7 +103,7 @@ class DefaultJwtParserBuilderTest { } } def b = builder.base64UrlDecodeWith(decoder).build() - assertSame decoder, b.base64UrlDecoder + assertSame decoder, b.decoder } @Test(expected = IllegalArgumentException) @@ -165,6 +167,118 @@ class DefaultJwtParserBuilderTest { assertSame codec, parser.zipAlgFn.locate(header) } + @Test + void testAddCompressionAlgorithmsOverrideDefaults() { + def header = Jwts.header().add('zip', 'DEF').build() + def parser = builder.build() + assertSame Jwts.ZIP.DEF, parser.zipAlgFn.apply(header) // standard implementation default + + def alg = new TestCompressionCodec(id: 'DEF') // custom impl with standard identifier + parser = builder.addCompressionAlgorithms([alg]).build() + assertSame alg, parser.zipAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveCompressionAlgorithm() { + def standard = Jwts.header().add('zip', 'DEF').build() + def nonStandard = Jwts.header().add('zip', 'def').build() + def parser = builder.build() + assertSame Jwts.ZIP.DEF, parser.zipAlgFn.apply(standard) // standard implementation default + try { + parser.zipAlgFn.apply(nonStandard) + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWT ${DefaultHeader.COMPRESSION_ALGORITHM} header value: def" + assertEquals msg, e.getMessage() + } + } + + @Test + void testAddEncryptionAlgorithmsOverrideDefaults() { + final String standardId = Jwts.ENC.A256GCM.getId() + def header = Jwts.header().add('enc', standardId).build() + def parser = builder.build() + assertSame Jwts.ENC.A256GCM, parser.encAlgFn.apply(header) // standard implementation default + + def custom = new TestAeadAlgorithm(id: standardId) // custom impl with standard identifier + parser = builder.addEncryptionAlgorithms([custom]).build() + assertSame custom, parser.encAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveEncryptionAlgorithm() { + def alg = Jwts.ENC.A256GCM + def standard = Jwts.header().add('enc', alg.id).build() + def nonStandard = Jwts.header().add('enc', alg.id.toLowerCase()).build() + def parser = builder.build() + assertSame alg, parser.encAlgFn.apply(standard) // standard id + try { + parser.encAlgFn.apply(nonStandard) // non-standard id + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWE ${DefaultJweHeader.ENCRYPTION_ALGORITHM} header value: ${alg.id.toLowerCase()}" + assertEquals msg, e.getMessage() + } + } + + @Test + void testAddKeyAlgorithmsOverrideDefaults() { + final String standardId = Jwts.KEY.A256GCMKW.id + def header = Jwts.header().add('enc', Jwts.ENC.A256GCM.id).add('alg', standardId).build() + def parser = builder.build() + assertSame Jwts.KEY.A256GCMKW, parser.keyAlgFn.apply(header) // standard implementation default + + def custom = new TestKeyAlgorithm(id: standardId) // custom impl with standard identifier + parser = builder.addKeyAlgorithms([custom]).build() + assertSame custom, parser.keyAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveKeyAlgorithm() { + def alg = Jwts.KEY.A256GCMKW + def hb = Jwts.header().add('enc', Jwts.ENC.A256GCM.id) + def standard = hb.add('alg', alg.id).build() + def nonStandard = hb.add('alg', alg.id.toLowerCase()).build() + def parser = builder.build() + assertSame alg, parser.keyAlgFn.apply(standard) // standard id + try { + parser.keyAlgFn.apply(nonStandard) // non-standard id + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWE ${DefaultJweHeader.ALGORITHM} header value: ${alg.id.toLowerCase()}" + assertEquals msg, e.getMessage() + } + } + + @Test + void testAddSignatureAlgorithmsOverrideDefaults() { + final String standardId = Jwts.SIG.HS256.id + def header = Jwts.header().add('alg', standardId).build() + def parser = builder.build() + assertSame Jwts.SIG.HS256, parser.sigAlgFn.apply(header) // standard implementation default + + def custom = new TestMacAlgorithm(id: standardId) // custom impl with standard identifier + parser = builder.addSignatureAlgorithms([custom]).build() + assertSame custom, parser.sigAlgFn.apply(header) // custom one, not standard impl + } + + @Test + void testCaseSensitiveSignatureAlgorithm() { + def alg = Jwts.SIG.HS256 + def hb = Jwts.header().add('alg', alg.id) + def standard = hb.build() + def nonStandard = hb.add('alg', alg.id.toLowerCase()).build() + def parser = builder.build() + assertSame alg, parser.sigAlgFn.apply(standard) // standard id + try { + parser.sigAlgFn.apply(nonStandard) // non-standard id + fail() + } catch (UnsupportedJwtException e) { + String msg = "Unrecognized JWS ${DefaultJwsHeader.ALGORITHM} header value: ${alg.id.toLowerCase()}" + assertEquals msg, e.getMessage() + } + } + @Test void testCompressionCodecResolverAndExtraCompressionCodecs() { def codec = new TestCompressionCodec(id: 'test') @@ -252,6 +366,11 @@ class DefaultJwtParserBuilderTest { return this.id } + @Override + String getId() { + return this.id + } + @Override byte[] compress(byte[] content) throws CompressionException { return new byte[0] @@ -261,10 +380,87 @@ class DefaultJwtParserBuilderTest { byte[] decompress(byte[] compressed) throws CompressionException { return new byte[0] } + } + + static class TestAeadAlgorithm implements AeadAlgorithm { + + String id + int keyBitLength = 256 + + @Override + String getId() { + return id + } + + @Override + AeadResult encrypt(AeadRequest request) throws SecurityException { + return null + } + + @Override + Message decrypt(DecryptAeadRequest request) throws SecurityException { + return null + } + + @Override + SecretKeyBuilder key() { + return null + } + + @Override + int getKeyBitLength() { + return keyBitLength + } + } + + static class TestKeyAlgorithm implements KeyAlgorithm { + + String id + int keyBitLength = 256 @Override String getId() { - return this.id + return id + } + + @Override + KeyResult getEncryptionKey(KeyRequest request) throws SecurityException { + return null + } + + @Override + SecretKey getDecryptionKey(DecryptionKeyRequest request) throws SecurityException { + return null + } + } + + static class TestMacAlgorithm implements MacAlgorithm { + + String id + + @Override + String getId() { + return id + } + + @Override + byte[] digest(SecureRequest request) throws SecurityException { + return new byte[0] + } + + @Override + boolean verify(VerifySecureDigestRequest request) throws SecurityException { + return false + } + + @Override + SecretKeyBuilder key() { + return null + } + + @Override + int getKeyBitLength() { + return 0 } } } From 083da95a263675f2f5bfb27333128cf77a6c5609 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 15:46:40 -0700 Subject: [PATCH 17/24] - removed DynamicJwkBuilder chain methods with array arguments - added generic DynamicJwkBuilder#keyPair(KeyPair) method - added generic DynamicJwkBuilder#chain method --- .../security/DynamicJwkBuilder.java | 143 ++++++++++++------ .../security/DefaultDynamicJwkBuilder.java | 30 ++-- .../impl/security/JwksTest.groovy | 82 ++++++++-- .../io/jsonwebtoken/impl/security/README.md | 2 +- 4 files changed, 181 insertions(+), 76 deletions(-) diff --git a/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java index d2e6b4151..5ac13fecf 100644 --- a/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/security/DynamicJwkBuilder.java @@ -37,6 +37,48 @@ */ public interface DynamicJwkBuilder> extends JwkBuilder> { + /** + * Ensures the builder will create a {@link PublicJwk} for the specified Java {@link X509Certificate} chain. + * The first {@code X509Certificate} in the chain (at array index 0) MUST contain a {@link PublicKey} + * instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method. + * + *

                      This method is provided for congruence with the other {@code chain} methods and is expected to be used when + * the calling code has a variable {@code PublicKey} reference. Based on the argument type, it will + * delegate to one of the following methods if possible: + *

                        + *
                      • {@link #rsaChain(List)}
                      • + *
                      • {@link #ecChain(List)}
                      • + *
                      • {@link #octetChain(List)}
                      • + *
                      + * + *

                      If the specified {@code chain} argument is not capable of being supported by one of those methods, an + * {@link UnsupportedKeyException} will be thrown.

                      + * + *

                      Type Parameters

                      + * + *

                      In addition to the public key type A, the public key's associated private key type + * B is parameterized as well. This ensures that any subsequent call to the builder's + * {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:

                      + * + *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>chain(edECPublicKeyX509CertificateChain)
                      +     *     .privateKey(aPrivateKey) // <-- must be an EdECPrivateKey instance
                      +     *     ... etc ...
                      +     *     .build();
                      + * + * @param the type of {@link PublicKey} provided by the created public JWK. + * @param the type of {@link PrivateKey} that may be paired with the {@link PublicKey} to produce a + * {@link PrivateJwk} if desired. + * @param chain the {@link X509Certificate} chain to inspect to find the {@link PublicKey} to represent as a + * {@link PublicJwk}. + * @return the builder coerced as a {@link PublicJwkBuilder} for continued method chaining. + * @throws UnsupportedKeyException if the specified key is not a supported type and cannot be used to delegate to + * other {@code key} methods. + * @see PublicJwk + * @see PrivateJwk + */ + PublicJwkBuilder chain(List chain) + throws UnsupportedKeyException; + /** * Ensures the builder will create a {@link SecretJwk} for the specified Java {@link SecretKey}. * @@ -87,7 +129,6 @@ public interface DynamicJwkBuilder> extends JwkB */ EcPrivateJwkBuilder key(ECPrivateKey key); - /** * Ensures the builder will create a {@link PublicJwk} for the specified Java {@link PublicKey} argument. This * method is provided for congruence with the other {@code key} methods and is expected to be used when @@ -161,6 +202,45 @@ public interface DynamicJwkBuilder> extends JwkB */ PrivateJwkBuilder key(B key) throws UnsupportedKeyException; + /** + * Ensures the builder will create a {@link PrivateJwk} for the specified Java {@link KeyPair} argument. This + * method is provided for congruence with the other {@code keyPair} methods and is expected to be used when + * the calling code has a variable {@code PrivateKey} reference. Based on the argument's {@code PrivateKey} type, + * it will delegate to one of the following methods if possible: + *
                        + *
                      • {@link #key(RSAPrivateKey)}
                      • + *
                      • {@link #key(ECPrivateKey)}
                      • + *
                      • {@link #octetKey(PrivateKey)}
                      • + *
                      + *

                      and automatically set the resulting builder's {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} with + * the pair's {@code PublicKey}.

                      + * + *

                      If the specified {@code key} argument is not capable of being supported by one of those methods, an + * {@link UnsupportedKeyException} will be thrown.

                      + * + *

                      Type Parameters

                      + * + *

                      In addition to the private key type B, the private key's associated public key type + * A is parameterized as well. This ensures that any subsequent call to the builder's + * {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:

                      + * + *
                      Jwks.builder().<EdECPublicKey, EdECPrivateKey>keyPair(anEdECKeyPair)
                      +     *     .publicKey(aPublicKey) // <-- must be an EdECPublicKey instance
                      +     *     ... etc ...
                      +     *     .build();
                      + * + * @param
                      the {@code keyPair} argument's {@link PublicKey} type + * @param the {@code keyPair} argument's {@link PrivateKey} type + * @param keyPair the {@code KeyPair} containing the public and private key + * @return the builder coerced as a {@link PrivateJwkBuilder} for continued method chaining. + * @throws UnsupportedKeyException if the specified {@code KeyPair}'s keys are not supported and cannot be used to + * delegate to other {@code key} methods. + * @see PublicJwk + * @see PrivateJwk + */ + PrivateJwkBuilder keyPair(KeyPair keyPair) + throws UnsupportedKeyException; + /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Edwards-curve {@code PublicKey} * argument. The {@code PublicKey} must be an instance of one of the following: @@ -227,22 +307,6 @@ public interface DynamicJwkBuilder> extends JwkB */ OctetPrivateJwkBuilder octetKey(A key); - /** - * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Java Edwards-curve - * {@link KeyPair}. The pair's {@link KeyPair#getPublic() public key} MUST be an - * Edwards-curve public key as defined by {@link #octetKey(PublicKey)}. The pair's - * {@link KeyPair#getPrivate() private key} MUST be an Edwards-curve private key as defined by - * {@link #octetKey(PrivateKey)}. - * - * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. - * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. - * @param keyPair the Edwards-curve {@link KeyPair} to represent as an {@link OctetPrivateJwk}. - * @return the builder coerced as an {@link OctetPrivateJwkBuilder} for continued method chaining. - * @throws IllegalArgumentException if the {@code keyPair} does not contain Edwards-curve public and private key - * instances. - */ - OctetPrivateJwkBuilder octetKeyPair(KeyPair keyPair); - /** * Ensures the builder will create an {@link OctetPublicJwk} for the specified Java {@link X509Certificate} chain. * The first {@code X509Certificate} in the chain (at list index 0) MUST @@ -259,30 +323,20 @@ public interface DynamicJwkBuilder> extends JwkB OctetPublicJwkBuilder octetChain(List chain); /** - * Ensures the builder will create an {@link OctetPublicJwk} for the specified Java {@link X509Certificate} chain. - * The first {@code X509Certificate} in the chain (at array index 0) MUST - * {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by - * {@link #octetKey(PublicKey)}. - * - * @param the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}. - * @param the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce - * an {@link OctetPrivateJwk} if desired. - * @param chain the {@link X509Certificate} chain to inspect to find the Edwards-curve {@code PublicKey} to - * represent as an {@link OctetPublicJwk}. - * @return the builder coerced as an {@link OctetPublicJwkBuilder} for continued method chaining. - */ - OctetPublicJwkBuilder octetChain(X509Certificate... chain); - - /** - * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain. - * The first {@code X509Certificate} in the chain (at array index 0) MUST contain an {@link ECPublicKey} - * instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method. + * Ensures the builder will create an {@link OctetPrivateJwk} for the specified Java Edwards-curve + * {@link KeyPair}. The pair's {@link KeyPair#getPublic() public key} MUST be an + * Edwards-curve public key as defined by {@link #octetKey(PublicKey)}. The pair's + * {@link KeyPair#getPrivate() private key} MUST be an Edwards-curve private key as defined by + * {@link #octetKey(PrivateKey)}. * - * @param chain the {@link X509Certificate} chain to inspect to find the {@link ECPublicKey} to represent as a - * {@link EcPublicJwk}. - * @return the builder coerced as an {@link EcPublicJwkBuilder}. + * @param the type of Edwards-curve {@link PublicKey} contained in the key pair. + * @param the type of the Edwards-curve {@link PrivateKey} contained in the key pair. + * @param keyPair the Edwards-curve {@link KeyPair} to represent as an {@link OctetPrivateJwk}. + * @return the builder coerced as an {@link OctetPrivateJwkBuilder} for continued method chaining. + * @throws IllegalArgumentException if the {@code keyPair} does not contain Edwards-curve public and private key + * instances. */ - EcPublicJwkBuilder ecChain(X509Certificate... chain); + OctetPrivateJwkBuilder octetKeyPair(KeyPair keyPair); /** * Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain. @@ -308,17 +362,6 @@ public interface DynamicJwkBuilder> extends JwkB */ EcPrivateJwkBuilder ecKeyPair(KeyPair keyPair) throws IllegalArgumentException; - /** - * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain. - * The first {@code X509Certificate} in the chain (at array index 0) MUST contain an {@link RSAPublicKey} - * instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method. - * - * @param chain the {@link X509Certificate} chain to inspect to find the {@link RSAPublicKey} to represent as a - * {@link RsaPublicJwk}. - * @return the builder coerced as an {@link RsaPublicJwkBuilder}. - */ - RsaPublicJwkBuilder rsaChain(X509Certificate... chain); - /** * Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain. * The first {@code X509Certificate} in the chain (at list index 0) MUST contain an {@link RSAPublicKey} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java index b9f5c7c11..3cba163f8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultDynamicJwkBuilder.java @@ -15,7 +15,6 @@ */ package io.jsonwebtoken.impl.security; -import io.jsonwebtoken.lang.Arrays; import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.DynamicJwkBuilder; @@ -125,10 +124,14 @@ public OctetPrivateJwkBuilder return new AbstractAsymmetricJwkBuilder.DefaultOctetPrivateJwkBuilder<>(newContext(key)); } + @SuppressWarnings("unchecked") @Override - public RsaPublicJwkBuilder rsaChain(X509Certificate... chain) { + public PublicJwkBuilder chain(List chain) + throws UnsupportedKeyException { Assert.notEmpty(chain, "chain cannot be null or empty."); - return rsaChain(Arrays.asList(chain)); + X509Certificate cert = Assert.notNull(chain.get(0), "The first X509Certificate cannot be null."); + PublicKey key = Assert.notNull(cert.getPublicKey(), "The first X509Certificate's PublicKey cannot be null."); + return this.key((A)key).x509CertificateChain(chain); } @Override @@ -140,12 +143,6 @@ public RsaPublicJwkBuilder rsaChain(List chain) { return key(pubKey).x509CertificateChain(chain); } - @Override - public EcPublicJwkBuilder ecChain(X509Certificate... chain) { - Assert.notEmpty(chain, "chain cannot be null or empty."); - return ecChain(Arrays.asList(chain)); - } - @Override public EcPublicJwkBuilder ecChain(List chain) { Assert.notEmpty(chain, "X509Certificate chain cannot be empty."); @@ -165,12 +162,6 @@ public OctetPrivateJwkBuilder return (OctetPrivateJwkBuilder) octetKey(priv).publicKey(pub); } - @Override - public OctetPublicJwkBuilder octetChain(X509Certificate... chain) { - Assert.notEmpty(chain, "X509Certificate chain cannot be null or empty."); - return octetChain(Arrays.asList(chain)); - } - @SuppressWarnings("unchecked") // ok because of the EdwardsCurve.assertEdwards calls @Override public OctetPublicJwkBuilder octetChain(List chain) { @@ -196,6 +187,15 @@ public EcPrivateJwkBuilder ecKeyPair(KeyPair pair) { return key(priv).publicKey(pub); } + @SuppressWarnings("unchecked") + @Override + public PrivateJwkBuilder keyPair(KeyPair keyPair) + throws UnsupportedKeyException { + A pub = (A)KeyPairs.getKey(keyPair, PublicKey.class); + B priv = (B)KeyPairs.getKey(keyPair, PrivateKey.class); + return this.key(priv).publicKey(pub); + } + @Override public J build() { if (Strings.hasText(this.DELEGATE.get(AbstractJwk.KTY))) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index 25c9befa4..bc398f6a7 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -31,6 +31,7 @@ import java.security.cert.X509Certificate import java.security.interfaces.ECKey import java.security.interfaces.ECPublicKey import java.security.interfaces.RSAKey +import java.security.interfaces.RSAPublicKey import java.security.spec.ECParameterSpec import java.security.spec.ECPoint @@ -186,16 +187,7 @@ class JwksTest { for (def alg : algs) { //get test cert: X509Certificate cert = TestCertificates.readTestCertificate(alg) - def pubKey = cert.getPublicKey() - - def builder = Jwks.builder() - if (pubKey instanceof ECKey) { - builder = builder.ecChain(cert) - } else if (pubKey instanceof RSAKey) { - builder = builder.rsaChain(cert) - } else { - builder = builder.octetChain(cert) - } + def builder = Jwks.builder().chain(Arrays.asList(cert)) if (number == 1) { builder.withX509Sha1Thumbprint(true) @@ -415,6 +407,76 @@ class JwksTest { } } + @Test + void testEcChain() { + TestKeys.EC.each { + ECPublicKey key = it.pair.public as ECPublicKey + def jwk = Jwks.builder().ecChain(it.chain).build() + assertEquals key, jwk.toKey() + assertEquals it.chain, jwk.getX509CertificateChain() + } + } + + @Test + void testRsaChain() { + TestKeys.RSA.each { + RSAPublicKey key = it.pair.public as RSAPublicKey + def jwk = Jwks.builder().rsaChain(it.chain).build() + assertEquals key, jwk.toKey() + assertEquals it.chain, jwk.getX509CertificateChain() + } + } + + @Test + void testOctetChain() { + TestKeys.EdEC.findAll({ it -> it.cert != null }).each { // no chains for XEC keys + PublicKey key = it.pair.public + def jwk = Jwks.builder().octetChain(it.chain).build() + assertEquals key, jwk.toKey() + assertEquals it.chain, jwk.getX509CertificateChain() + } + } + + @Test + void testRsaKeyPair() { + TestKeys.RSA.each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().rsaKeyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + + @Test + void testEcKeyPair() { + TestKeys.EC.each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().ecKeyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + + @Test + void testOctetKeyPair() { + TestKeys.EdEC.findAll(it -> it.cert != null).each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().octetKeyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + + @Test + void testKeyPair() { + TestKeys.ASYM.each { + java.security.KeyPair pair = it.pair + PrivateJwk jwk = Jwks.builder().keyPair(pair).build() + assertEquals it.pair.public, jwk.toPublicJwk().toKey() + assertEquals it.pair.private, jwk.toKey() + } + } + private static class InvalidECPublicKey implements ECPublicKey { private final ECPublicKey good diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md b/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md index 81428ba83..6677b7e57 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md @@ -33,7 +33,7 @@ The Elliptic Curve `*.key.pem`, `*.crt.pem` and `*.pub.pem` files in this direct openssl x509 -pubkey -noout -in ES384.crt.pem > ES384.pub.pem openssl x509 -pubkey -noout -in ES512.crt.pem > ES512.pub.pem -The Edwards Curve `*.key.pem`, `*.crt.pem` and `*.pub.pem` files in this directory were created for testing as follows +The Edwards Curve `*.key.pem`, `*.crt.pem` and `*.pub.pem` files in this directory were created for testing as follows. Note that we don't/can't create self-signed certificates (`*.crt.pem` files) for X25519 and X448 because these algorithms cannot be used for signing (perhaps we could have signed them with another key, but it wasn't necessary for our testing): From a06d403edf64097d99fdeb5cbde083fa91c7624f Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:23:54 -0700 Subject: [PATCH 18/24] doc/naming fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bf8b9d9b..6a791f777 100644 --- a/README.md +++ b/README.md @@ -1288,7 +1288,7 @@ on the type of JWS or JWE algorithm used. That is: * For JWE direct encryption, the returned decryption key should be a `SecretKey`. * For password-based key derivation algorithms, the returned decryption key should be a `io.jsonwebtoken.security.Password`. You can create a `Password` instance by calling - `Keys.forPassword(char[] passwordCharacters)`. + `Keys.password(char[] passwordCharacters)`. * For asymmetric key management algorithms, the returned decryption key should be a `PrivateKey` (not a `PublicKey`). @@ -3315,7 +3315,7 @@ as shown below. ```java //DO NOT use this example password in a real app, it is well-known to password crackers: String pw = "correct horse battery staple"; -Password password = Keys.forPassword(pw.toCharArray()); +Password password = Keys.password(pw.toCharArray()); // Choose the desired PBES2 key derivation algorithm: KeyAlgorithm alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_HS384_A192KW or PBES2_HS256_A128KW From 65ad196056e25db84ba282237b2773768a24fe0c Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:09:45 -0700 Subject: [PATCH 19/24] doc enhancements --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6a791f777..dffa0c0db 100644 --- a/README.md +++ b/README.md @@ -2307,6 +2307,17 @@ SecretJwk = Jwks.builder().key(key) // (1) and (2) .build(); // (4) ``` +#### JWK from a Map + +If you have a `Map` of name/value pairs that reflect an existing JWK, you add them and build a type-safe +`Jwk` instance: + +```java +Map jwkValues = getMyJwkMap(); + +Jwk jwk = Jwks.builder().add(jwkValues).build(); +``` + ### Read a JWK @@ -2414,14 +2425,15 @@ Jwk jwk = Jwks.builder(). /* ... */ .build(); JwkThumbprint sha256Thumbprint = jwk.thumbprint(); // SHA-256 thumbprint by default -JwkThumbprint anotherThumbprint = jwk.thumbprint(hashAlg); // thumbprint using specified hash algorithm +JwkThumbprint anotherThumbprint = jwk.thumbprint(Jwks.HASH.SHA512); // or a specified hash algorithm ``` The resulting `JwkThumbprint` instance provides some useful methods: * `jwkThumbprint.toByteArray()`: the thumbprint's actual digest bytes - i.e. the raw output from the hash algorithm * `jwkThumbprint.toString()`: the digest bytes as a Base64URL-encoded string -* `jwkThumbprint.getHashAlgorithm()`: the specific `HashAlgorithm` used to compute the thumbprint +* `jwkThumbprint.getHashAlgorithm()`: the specific `HashAlgorithm` used to compute the thumbprint. Many standard IANA + hash algorithms are available as constants in the `Jwts.HASH` utility class. * `jwkThumbprint.toURI()`: the thumbprint's canonical URI as defined by the [JWK Thumbprint URI](https://www.rfc-editor.org/rfc/rfc9278.html) specification @@ -2452,7 +2464,7 @@ Instead, you may use the `idFromThumbprint` methods on the `JwkBuilder` when cre ```java Jwk jwk = Jwks.builder().key(aKey) - .idFromThumbprint() // or idFromThumbprint(hashAlgorithm) + .idFromThumbprint() // or idFromThumbprint(HashAlgorithm) .build(); ``` From 596a40619339801a552b13bce2038bf9b02f9f23 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:15:55 -0700 Subject: [PATCH 20/24] Fixed JavaDoc syntax error --- api/src/main/java/io/jsonwebtoken/JwtBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 802d64e77..2fafd3930 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -101,7 +101,7 @@ public interface JwtBuilder extends ClaimsMutator { * {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} * *

                      If you do not want to replace the existing header and only want to append to it, - * call {@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} instead.

                      + * call {@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()} instead.

                      * * @param map the name/value pairs to set as (and potentially replace) the constructed JWT header. * @return the builder for method chaining. From b597337df12ab307aafcf267347e90de77070205 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:22:07 -0700 Subject: [PATCH 21/24] Added license header --- .../impl/DelegatingClaimsMutator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java index 899ec1256..44227b2df 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DelegatingClaimsMutator.java @@ -1,3 +1,18 @@ +/* + * Copyright © 2023 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.ClaimsMutator; From 761ed684d5dfbea368fb45e4c9983b8fa0d091d4 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:10:28 -0700 Subject: [PATCH 22/24] Reintroduced deprecated Header mutation methods for a slightly easier transition to 0.12.0, will remove in next release --- .../java/io/jsonwebtoken/HeaderMutator.java | 41 +++++++++++++++++-- .../jsonwebtoken/ProtectedHeaderMutator.java | 24 +++++++++++ .../impl/DefaultJweHeaderMutator.java | 32 +++++++++++++-- .../impl/DefaultJwtHeaderBuilderTest.groovy | 9 ++++ 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java index 336f25052..ae1ff568a 100644 --- a/api/src/main/java/io/jsonwebtoken/HeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/HeaderMutator.java @@ -25,7 +25,7 @@ */ public interface HeaderMutator> extends MapMutator { - //IMPLEMENTOR NOTE: if this `algorithm` method ever needs to be exposed in the public API, it's probably better to + //IMPLEMENTOR NOTE: if this `algorithm` method ever needs to be exposed in the public API, it might be better to // have it in the Jwts.HeaderBuilder interface and NOT this one: in the context of // JwtBuilder.Header, there is never a reason for an application developer to call algorithm(id) // directly because the KeyAlgorithm or SecureDigestAlgorithm instance must always be provided @@ -57,7 +57,7 @@ public interface HeaderMutator> extends MapMutatortyp
                      (Type) header value. A {@code null} value will remove the property from the JSON map. * * @param typ the JWT JOSE {@code typ} header value or {@code null} to remove the property from the JSON map. - * @return the {@code Header} instance for method chaining. + * @return the instance for method chaining. */ T type(String typ); @@ -84,7 +84,42 @@ public interface HeaderMutator> extends MapMutatorexample;part="1/2"
                      .

                      * * @param cty the JWT JOSE {@code cty} header value or {@code null} to remove the property from the JSON map. - * @return the {@code Header} instance for method chaining. + * @return the instance for method chaining. */ T contentType(String cty); + + /** + * Deprecated since of JJWT_RELEASE_VERSION, delegates to {@link #type(String)}. + * + * @param typ the JWT JOSE {@code typ} header value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @see #type(String) + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #type(String)} method. + * This method will be removed before the 1.0 release. + */ + @Deprecated + T setType(String typ); + + /** + * Deprecated as of JJWT_RELEASE_VERSION, delegates to {@link #contentType(String)}. + * + * @param cty the JWT JOSE {@code cty} header value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @see #contentType(String) + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #contentType(String)}. + */ + @Deprecated + T setContentType(String cty); + + /** + * Deprecated as of JJWT_RELEASE_VERSION, there is no need to set this any longer as the {@code JwtBuilder} will + * always set the {@code zip} header as necessary. + * + * @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @since 0.6.0 + * @deprecated since JJWT_RELEASE_VERSION and will be removed before the 1.0 release. + */ + @Deprecated + T setCompressionAlgorithm(String zip); } diff --git a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java index 206134b15..5c329a345 100644 --- a/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java +++ b/api/src/main/java/io/jsonwebtoken/ProtectedHeaderMutator.java @@ -87,4 +87,28 @@ public interface ProtectedHeaderMutator> ext * @see JWE Key ID */ T keyId(String kid); + + /** + * Deprecated since JJWT_RELEASE_VERSION, delegates to {@link #keyId(String)}. + * + * @param kid the case-sensitive JWS {@code kid} header value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @see JWS Key ID + * @see JWE Key ID + * @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #keyId(String)} method. + */ + @Deprecated + T setKeyId(String kid); + + /** + * Deprecated as of JJWT_RELEASE_VERSION, there is no need to set this any longer as the {@code JwtBuilder} will + * always set the {@code alg} header as necessary. + * + * @param alg the JWS or JWE algorithm {@code alg} value or {@code null} to remove the property from the JSON map. + * @return the instance for method chaining. + * @since 0.1 + * @deprecated since JJWT_RELEASE_VERSION and will be removed before the 1.0 release. + */ + @Deprecated + T setAlgorithm(String alg); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java index 7bc5b63de..462128aa1 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java @@ -82,13 +82,28 @@ public T type(String typ) { return put(DefaultHeader.TYPE, typ); } + @Override + public T setType(String typ) { + return type(typ); + } + + @Override + public T setContentType(String cty) { + return contentType(cty); + } + + @Override + public T setCompressionAlgorithm(String zip) { + return put(DefaultHeader.COMPRESSION_ALGORITHM, zip); + } + // ============================================================= // Protected Header methods // ============================================================= @Override - public T jwkSetUrl(URI uri) { - return put(DefaultProtectedHeader.JKU, uri); + public T critical(Set crit) { + return put(DefaultProtectedHeader.CRIT, crit); } @Override @@ -96,16 +111,25 @@ public T jwk(PublicJwk jwk) { return put(DefaultProtectedHeader.JWK, jwk); } + @Override + public T jwkSetUrl(URI uri) { + return put(DefaultProtectedHeader.JKU, uri); + } + @Override public T keyId(String kid) { return put(DefaultProtectedHeader.KID, kid); } @Override - public T critical(Set crit) { - return put(DefaultProtectedHeader.CRIT, crit); + public T setKeyId(String kid) { + return keyId(kid); } + @Override + public T setAlgorithm(String alg) { + return put(DefaultHeader.ALGORITHM, alg); + } // ============================================================= // X.509 methods diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy index 79422e0d5..430ef5b1f 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtHeaderBuilderTest.groovy @@ -263,6 +263,15 @@ class DefaultJwtHeaderBuilderTest { assertSymmetry('compressionAlgorithm', 'DEF') } + @Test + void testDeprecatedSetters() { // TODO: remove before 1.0 + assertEquals 'foo', builder.setType('foo').build().getType() + assertEquals 'foo', builder.setContentType('foo').build().getContentType() + assertEquals 'foo', builder.setCompressionAlgorithm('foo').build().getCompressionAlgorithm() + assertEquals 'foo', builder.setKeyId('foo').build().getKeyId() + assertEquals 'foo', builder.setAlgorithm('foo').build().getAlgorithm() + } + // ====================== Protected Header Methods ======================= /** From e7ad356e1fc43853d91fa9e2dff64708c09cfda3 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:11:46 -0700 Subject: [PATCH 23/24] Fixed groovy syntax that wasn't working on JDK 7 (only 8+) --- .../test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index bc398f6a7..af441a46a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -459,7 +459,7 @@ class JwksTest { @Test void testOctetKeyPair() { - TestKeys.EdEC.findAll(it -> it.cert != null).each { + TestKeys.EdEC.findAll({ it -> it.cert != null }).each { java.security.KeyPair pair = it.pair PrivateJwk jwk = Jwks.builder().octetKeyPair(pair).build() assertEquals it.pair.public, jwk.toPublicJwk().toKey() From 651f2790dbdb9c10e41f11d7ef52c9ea53f136c3 Mon Sep 17 00:00:00 2001 From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:21:46 -0700 Subject: [PATCH 24/24] - Deprecated public String constants in Header.java and JwsHeader.java --- api/src/main/java/io/jsonwebtoken/Header.java | 8 ++++++ .../main/java/io/jsonwebtoken/JwsHeader.java | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/api/src/main/java/io/jsonwebtoken/Header.java b/api/src/main/java/io/jsonwebtoken/Header.java index a3e0ee20b..ea28b7a93 100644 --- a/api/src/main/java/io/jsonwebtoken/Header.java +++ b/api/src/main/java/io/jsonwebtoken/Header.java @@ -54,12 +54,16 @@ public interface Header extends Map { /** * JWT {@code Type} header parameter name: "typ" + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getType()}. */ + @Deprecated String TYPE = "typ"; /** * JWT {@code Content Type} header parameter name: "cty" + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getContentType()}. */ + @Deprecated String CONTENT_TYPE = "cty"; /** @@ -67,12 +71,16 @@ public interface Header extends Map { * * @see JWS Algorithm Header * @see JWE Algorithm Header + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getAlgorithm()}. */ + @Deprecated String ALGORITHM = "alg"; /** * JWT {@code Compression Algorithm} header parameter name: "zip" + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getCompressionAlgorithm()} */ + @Deprecated String COMPRESSION_ALGORITHM = "zip"; /** diff --git a/api/src/main/java/io/jsonwebtoken/JwsHeader.java b/api/src/main/java/io/jsonwebtoken/JwsHeader.java index 676304259..08a2e704f 100644 --- a/api/src/main/java/io/jsonwebtoken/JwsHeader.java +++ b/api/src/main/java/io/jsonwebtoken/JwsHeader.java @@ -24,46 +24,73 @@ public interface JwsHeader extends ProtectedHeader { /** * JWS Algorithm Header name: the string literal alg + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getAlgorithm()} */ + @Deprecated String ALGORITHM = "alg"; /** * JWS JWK Set URL Header name: the string literal jku + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getJwkSetUrl()} */ + @Deprecated String JWK_SET_URL = "jku"; /** * JWS JSON Web Key Header name: the string literal jwk + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getJwk()} */ + @Deprecated String JSON_WEB_KEY = "jwk"; /** * JWS Key ID Header name: the string literal kid + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getKeyId()} */ + @Deprecated String KEY_ID = "kid"; /** * JWS X.509 URL Header name: the string literal x5u + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509Url()} */ + @Deprecated String X509_URL = "x5u"; /** * JWS X.509 Certificate Chain Header name: the string literal x5c + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateChain()} */ + @Deprecated String X509_CERT_CHAIN = "x5c"; /** * JWS X.509 Certificate SHA-1 Thumbprint Header name: the string literal x5t + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateSha1Thumbprint()} */ + @Deprecated String X509_CERT_SHA1_THUMBPRINT = "x5t"; /** * JWS X.509 Certificate SHA-256 Thumbprint Header name: the string literal x5t#S256 + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateSha256Thumbprint()} */ + @Deprecated String X509_CERT_SHA256_THUMBPRINT = "x5t#S256"; /** * JWS Critical Header name: the string literal crit + * + * @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getCritical()} */ + @Deprecated String CRITICAL = "crit"; }