Builder setters (#794)

- 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.

- Renamed MapMutator `set` methods to `add` methods to avoid Java setter full replacement idiom confusion (as opposed to add/append)

- 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

- 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

- 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

- Renamed KeyBuilderSupplier#keyBuilder() to less verbose KeyBuilderSupplier#key()
- Renamed KeyPairBuilderSupplier#keyPairBuilder() to less verbose KeyPairBuilderSupplier#keyPair()

- Renamed ProtoJwkBuilder to DynamicJwkBuilder

- 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

- removed DynamicJwkBuilder chain methods with array arguments
- added generic DynamicJwkBuilder#keyPair(KeyPair) method
- added generic DynamicJwkBuilder#chain method

- Reintroduced deprecated Header mutation methods for a slightly easier transition to 0.12.0, will remove in next release

- Deprecated public String constants in Header.java and JwsHeader.java

- Documentation, JavaDoc and code example changes/formatting fixes and enhancements
This commit is contained in:
lhazlewood 2023-08-08 19:13:34 -07:00 committed by GitHub
parent db94dc7b79
commit 7ed0b772ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
140 changed files with 2633 additions and 1919 deletions

View File

@ -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<Claims> 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
@ -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.

618
README.md

File diff suppressed because it is too large Load Diff

View File

@ -33,27 +33,66 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.1">
* <code>iss</code></a> (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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2">
* <code>sub</code></a> (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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2">
* <code>sub</code></a> (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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3">
* <code>aud</code></a> (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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3">
* <code>aud</code></a> (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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4">
* <code>exp</code></a> (expiration) timestamp. A {@code null} value will remove the property from the JSON map.
@ -62,9 +101,24 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4">
* <code>exp</code></a> (expiration) timestamp. A {@code null} value will remove the property from the JSON map.
*
* <p>A JWT obtained after this timestamp should not be used.</p>
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5">
* <code>nbf</code></a> (not before) timestamp. A {@code null} value will remove the property from the JSON map.
@ -73,9 +127,24 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5">
* <code>nbf</code></a> (not before) timestamp. A {@code null} value will remove the property from the JSON map.
*
* <p>A JWT obtained before this timestamp should not be used.</p>
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.6">
* <code>iat</code></a> (issued at) timestamp. A {@code null} value will remove the property from the JSON map.
@ -84,9 +153,24 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.6">
* <code>iat</code></a> (issued at) timestamp. A {@code null} value will remove the property from the JSON map.
*
* <p>The value is the timestamp when the JWT was created.</p>
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7">
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the JSON map.
@ -97,6 +181,23 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
*
* @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 <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7">
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the JSON map.
*
* <p>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.</p>
*
* @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);
}

View File

@ -54,12 +54,16 @@ public interface Header extends Map<String, Object> {
/**
* JWT {@code Type} header parameter name: <code>"typ"</code>
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getType()}.
*/
@Deprecated
String TYPE = "typ";
/**
* JWT {@code Content Type} header parameter name: <code>"cty"</code>
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getContentType()}.
*/
@Deprecated
String CONTENT_TYPE = "cty";
/**
@ -67,12 +71,16 @@ public interface Header extends Map<String, Object> {
*
* @see <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">JWS Algorithm Header</a>
* @see <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1">JWE Algorithm Header</a>
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getAlgorithm()}.
*/
@Deprecated
String ALGORITHM = "alg";
/**
* JWT {@code Compression Algorithm} header parameter name: <code>"zip"</code>
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getCompressionAlgorithm()}
*/
@Deprecated
String COMPRESSION_ALGORITHM = "zip";
/**

View File

@ -25,14 +25,41 @@ import io.jsonwebtoken.lang.MapMutator;
*/
public interface HeaderMutator<T extends HeaderMutator<T>> extends MapMutator<String, Object, T> {
//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
// 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.
* <ul>
* <li>If the JWT is a Signed JWT (a JWS), the
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">{@code alg}</a> (Algorithm) header
* parameter identifies the cryptographic algorithm used to secure the JWS.</li>
* <li>If the JWT is an Encrypted JWT (a JWE), the
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1"><code>alg</code></a> (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 <code>alg</code> value does not represent a
* supported algorithm, or if the recipient does not have a key that can be used with that algorithm.</li>
* </ul>
*
* @param alg the {@code alg} header value
* @return this header for method chaining
* @since JJWT_RELEASE_VERSION
*
T algorithm(String alg);
*/
/**
* Sets the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-5.1">
* <code>typ</code> (Type)</a> 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 setType(String typ);
T type(String typ);
/**
* Sets the JWT <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.10">
@ -57,46 +84,42 @@ public interface HeaderMutator<T extends HeaderMutator<T>> extends MapMutator<St
* <b><code>example;part=&quot;1/2&quot;</code></b>.</p>
*
* @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);
/**
* Sets the JWT {@code alg} (Algorithm) header value. A {@code null} value will remove the property
* from the JSON map.
* <ul>
* <li>If the JWT is a Signed JWT (a JWS), the
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">{@code alg}</a> (Algorithm) header
* parameter identifies the cryptographic algorithm used to secure the JWS.</li>
* <li>If the JWT is an Encrypted JWT (a JWE), the
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1"><code>alg</code></a> (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 <code>alg</code> value does not represent a
* supported algorithm, or if the recipient does not have a key that can be used with that algorithm.</li>
* </ul>
*
* @param alg the {@code alg} header value
* @return this header for method chaining
* @since JJWT_RELEASE_VERSION
*/
T setAlgorithm(String alg);
/**
* Sets the JWT <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a>
* (Compression Algorithm) header parameter value. A {@code null} value will remove
* the property from the JSON map.
*
* <p><b>Compatibility Note</b></p>
*
* <p>While the JWT family of specifications only defines the <code>zip</code> 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 <b>if you use compression when creating a JWS token, other libraries may not be able to
* parse the JWS</b>. However, Compression when creating JWE tokens should be universally accepted for any library
* that supports JWE.</p>
* 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 {@code Header} instance for method chaining.
* @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);
}

View File

@ -37,7 +37,7 @@ public interface JweHeaderMutator<T extends JweHeaderMutator<T>> 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<T extends JweHeaderMutator<T>> extends Protect
*
* <p>If not {@code null}, this is a convenience method that calls the equivalent of the following:</p>
* <blockquote><pre>
* {@link #setAgreementPartyUInfo(byte[]) setAgreementPartyUInfo}(info.getBytes(StandardCharsets.UTF_8))</pre></blockquote>
* {@link #agreementPartyUInfo(byte[]) agreementPartyUInfo}(info.getBytes(StandardCharsets.UTF_8))</pre></blockquote>
*
* @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<T extends JweHeaderMutator<T>> 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<T extends JweHeaderMutator<T>> 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<T extends JweHeaderMutator<T>> extends Protect
*
* <p>If not {@code null}, this is a convenience method that calls the equivalent of the following:</p>
* <blockquote><pre>
* {@link #setAgreementPartyVInfo(byte[]) setAgreementPartVUInfo}(info.getBytes(StandardCharsets.UTF_8))</pre></blockquote>
* {@link #agreementPartyVInfo(byte[]) setAgreementPartVUInfo}(info.getBytes(StandardCharsets.UTF_8))</pre></blockquote>
*
* @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<T extends JweHeaderMutator<T>> 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<T extends JweHeaderMutator<T>> extends Protect
* @see Jwts.KEY#PBES2_HS512_A256KW
* @see <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2">OWASP PBKDF2 Iteration Recommendations</a>
*/
T setPbes2Count(int count);
T pbes2Count(int count);
}

View File

@ -24,46 +24,73 @@ public interface JwsHeader extends ProtectedHeader {
/**
* JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">Algorithm Header</a> name: the string literal <b><code>alg</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getAlgorithm()}
*/
@Deprecated
String ALGORITHM = "alg";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.2">JWK Set URL Header</a> name: the string literal <b><code>jku</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getJwkSetUrl()}
*/
@Deprecated
String JWK_SET_URL = "jku";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.3">JSON Web Key Header</a> name: the string literal <b><code>jwk</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getJwk()}
*/
@Deprecated
String JSON_WEB_KEY = "jwk";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.4">Key ID Header</a> name: the string literal <b><code>kid</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getKeyId()}
*/
@Deprecated
String KEY_ID = "kid";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.5">X.509 URL Header</a> name: the string literal <b><code>x5u</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509Url()}
*/
@Deprecated
String X509_URL = "x5u";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.6">X.509 Certificate Chain Header</a> name: the string literal <b><code>x5c</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateChain()}
*/
@Deprecated
String X509_CERT_CHAIN = "x5c";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.7">X.509 Certificate SHA-1 Thumbprint Header</a> name: the string literal <b><code>x5t</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateSha1Thumbprint()}
*/
@Deprecated
String X509_CERT_SHA1_THUMBPRINT = "x5t";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.8">X.509 Certificate SHA-256 Thumbprint Header</a> name: the string literal <b><code>x5t#S256</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getX509CertificateSha256Thumbprint()}
*/
@Deprecated
String X509_CERT_SHA256_THUMBPRINT = "x5t#S256";
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.11">Critical Header</a> name: the string literal <b><code>crit</code></b>
*
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getCritical()}
*/
@Deprecated
String CRITICAL = "crit";
}

View File

@ -20,6 +20,7 @@ import io.jsonwebtoken.io.Decoder;
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;
@ -55,7 +56,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* @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,95 +67,125 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* @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.
* When finished, callers may return to JWT construction via the {@link JwtBuilder.Header#and() and()} method.
* 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 BuilderHeader#and() and()} method.
* For example:
*
* <blockquote><pre>
* String jwt = Jwts.builder()
*
* <b>.header()
* .setKeyId("keyId")
* .set(myHeaderMap)
* // ... other header params ...
* .{@link JwtBuilder.Header#and() and()}</b> //return back to the JwtBuilder
* .keyId("keyId")
* .add("aName", aValue)
* .add(myHeaderMap)
* // ... etc ...
* .{@link BuilderHeader#and() and()}</b> //return back to the JwtBuilder
*
* .setSubject("Joe") // resume JwtBuilder calls
* .subject("Joe") // resume JwtBuilder calls
* // ... etc ...
* .compact();</pre></blockquote>
*
* @return the {@link JwtBuilder.Header} to use for header construction.
* @return the {@link BuilderHeader} to use for header construction.
* @since JJWT_RELEASE_VERSION
*/
JwtBuilder.Header header();
BuilderHeader 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 is a wrapper method for:
*
* <blockquote><pre>
* {@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}</pre></blockquote>
*
* <p>If you do not want to replace the existing header and only want to append to it,
* call <code>{@link #header()}.{@link io.jsonwebtoken.lang.MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}</code> instead.</p>
*
* @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
* <code>{@link #header()}.{@link MapMutator#empty() empty()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}</code>
* (to replace all header parameters) or
* <code>{@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}</code>
* to only append the {@code map} entries. This method will be removed before the 1.0 release.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
JwtBuilder setHeader(Map<String, ?> 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. This is a wrapper method for:
* <blockquote><pre>
* {@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}</pre></blockquote>
*
* @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
* <code>{@link #header()}.{@link MapMutator#add(Map) add(map)}.{@link BuilderHeader#and() and()}</code>.
* This method will be removed before the 1.0 release.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
JwtBuilder setHeaderParams(Map<String, ?> 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. If the value is {@code null} or empty, the parameter will
* be removed from the header entirely. This is a wrapper method for:
* <blockquote><pre>
* {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderHeader#and() and()}</pre></blockquote>
*
* @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 <code>
* {@link #header()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderHeader#and() and()}</code>.
* This method will be removed before the 1.0 release.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
JwtBuilder setHeaderParam(String name, Object value);
/**
* 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 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 #setContent(byte[], String)} instead.
* {@link #content(byte[], String)} instead.
*
* <p>This is a convenience method that is effectively the same as:</p>
* <p>This is a wrapper method for:</p>
* <blockquote><pre>
* {@link #setContent(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));</pre></blockquote>
* {@link #content(byte[]) setPayload}(payload.getBytes(StandardCharsets.UTF_8));</pre></blockquote>
*
* <p>If you want the JWT payload to be JSON, use the
* {@link #setClaims(Claims)} or {@link #setClaims(java.util.Map)} methods instead.</p>
* <p>If you want the JWT payload to be JSON, use the {@link #claims()} method instead.</p>
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
* <p>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.</p>
*
* @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);
/**
* Sets the JWT payload to be the specified content byte array.
*
* <p>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.</p>
*
* <p><b>Content Type Recommendation</b></p>
*
* <p>Unless you are confident that the JWT recipient will <em>always</em> 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.</p>
*
* <p>Note that the content and claims properties are mutually exclusive - only one of the two may be used.</p>
@ -163,14 +194,17 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* @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 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.
*
* <p>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.</p>
*
* <p><b>Compact Media Type Identifier</b></p>
*
* <p>As a convenience, this method will automatically trim any <code><b>application/</b></code> prefix from the
@ -178,18 +212,18 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.10">JWT specification recommendations</a>.</p>
*
* <p>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:</p>
* method - instead call {@link #content(byte[])} and set the header's
* {@link BuilderHeader#contentType(String) contentType} independently. For example:</p>
*
* <blockquote><pre>
* Jwts.builder()
* .header().setContentType("application/whatever").and()
* .setContent(byteArray)
* .header().contentType("application/whatever").and()
* .content(byteArray)
* ...
* .build();</pre></blockquote>
*
* <p>If you want the JWT payload to be JSON claims, use the {@link #setClaims(Claims)} or
* {@link #setClaims(java.util.Map)} methods instead.</p>
* <p>If you want the JWT payload to be JSON claims, use the {@link #claim(String, Object)} or
* {@link #claims()} methods instead.</p>
*
* <p>Note that the content and claims properties are mutually exclusive - only one of the two may be used.</p>
*
@ -199,258 +233,75 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* @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[])}
* method instead.
* Returns the JWT {@code Claims} payload to modify as desired. When finished, callers may
* return to {@code JwtBuilder} configuration via the {@link BuilderClaims#and() and()} method.
* For example:
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
* <blockquote><pre>
* String jwt = Jwts.builder()
*
* @param claims the JWT claims to be set as the JWT payload.
* @return the builder for method chaining.
* <b>.claims()
* .subject("Joe")
* .audience("you")
* .issuer("me")
* .add("customClaim", customValue)
* .add(myClaimsMap)
* // ... etc ...
* .{@link BuilderClaims#and() and()}</b> //return back to the JwtBuilder
*
* .signWith(key) // resume JwtBuilder calls
* // ... etc ...
* .compact();</pre></blockquote>
*
* @return the {@link BuilderClaims} to use for Claims construction.
* @since JJWT_RELEASE_VERSION
*/
JwtBuilder setClaims(Claims claims);
BuilderClaims 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
* {@link #setContent(byte[])} or {@link #setContent(byte[], String)} methods instead.
* 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.
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
* <p>The content and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @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()} method.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
JwtBuilder setClaims(Map<String, ?> 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.
* <p>
* This is a convenience wrapper for:
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
* <blockquote><pre>
* {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* <p>The content and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @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
* <code>{@link #claims()}.{@link BuilderClaims#add(Map) add(Map)}.{@link BuilderClaims#and() and()}</code>.
* This method will be removed before the 1.0 release.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
JwtBuilder addClaims(Map<String, ?> claims);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
* <code>iss</code></a> (issuer) value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setIssuer("Joe").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setIssuer("Joe").build();
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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
JwtBuilder setIssuer(String iss);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
* <code>sub</code></a> (subject) value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* 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:
* <blockquote><pre>
* String jwt = Jwts.builder().setSubject("Me").compact();</pre></blockquote>
*
* <p>instead of this:</p>
* <blockquote><pre>
* Claims claims = Jwts.claims().setSubject("Me").build();
* String jwt = Jwts.builder().setClaims(claims).compact();</pre></blockquote>
* <p>if desired.</p>
*
* @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
JwtBuilder setSubject(String sub);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
* <code>aud</code></a> (audience) value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setAudience("You").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setAudience("You");
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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
JwtBuilder setAudience(String aud);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
* <code>exp</code></a> (expiration) value. A {@code null} value will remove the property from the Claims.
*
* <p>A JWT obtained after this timestamp should not be used.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setExpiration(new Date(System.currentTimeMillis() + 3600000)).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setExpiration(new Date(System.currentTimeMillis() + 3600000));
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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
JwtBuilder setExpiration(Date exp);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
* <code>nbf</code></a> (not before) value. A {@code null} value will remove the property from the Claims.
*
* <p>A JWT obtained before this timestamp should not be used.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setNotBefore(new Date()).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setNotBefore(new Date());
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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 setNotBefore(Date nbf);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
* <code>iat</code></a> (issued at) value. A {@code null} value will remove the property from the Claims.
*
* <p>The value is the timestamp when the JWT was created.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setIssuedAt(new Date()).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setIssuedAt(new Date());
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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
JwtBuilder setIssuedAt(Date iat);
/**
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the Claims.
*
* <p>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.</p>
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().setId(UUID.randomUUID().toString()).compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().setId(UUID.randomUUID().toString());
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
*
* @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
JwtBuilder setId(String jti);
/**
* Sets a custom JWT Claims parameter value. A {@code null} value will remove the property from the Claims.
*
* <p>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:</p>
*
* <pre>
* String jwt = Jwts.builder().claim("aName", "aValue").compact();
* </pre>
*
* <p>instead of this:</p>
* <pre>
* Claims claims = Jwts.claims().put("aName", "aValue");
* String jwt = Jwts.builder().setClaims(claims).compact();
* </pre>
* <p>if desired.</p>
* {@link #claims()}.{@link MapMutator#add(Object, Object) add(name, value)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @param name the JWT Claims property name
* @param value the value to set for the specified Claims property name
@ -459,6 +310,133 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
*/
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:
* <blockquote><pre>
* {@link #claims()}.{@link MapMutator#add(Map) add(claims)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* <p>The content and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @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<String, ?> claims);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.1">
* <code>iss</code></a> (issuer) value. A {@code null} value will remove the property from the Claims.
* This is a convenience wrapper for:
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#issuer(String) issuer(iss)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder issuer(String iss);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2">
* <code>sub</code></a> (subject) value. A {@code null} value will remove the property from the Claims.
* This is a convenience wrapper for:
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#subject(String) subject(sub)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder subject(String sub);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3">
* <code>aud</code></a> (audience) value. A {@code null} value will remove the property from the Claims.
* This is a convenience wrapper for:
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#audience(String) audience(aud)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder audience(String aud);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4">
* <code>exp</code></a> (expiration) value. A {@code null} value will remove the property from the Claims.
*
* <p>A JWT obtained after this timestamp should not be used.</p>
*
* <p>This is a convenience wrapper for:</p>
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#expiration(Date) expiration(exp)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder expiration(Date exp);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5">
* <code>nbf</code></a> (not before) value. A {@code null} value will remove the property from the Claims.
*
* <p>A JWT obtained before this timestamp should not be used.</p>
*
* <p>This is a convenience wrapper for:</p>
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#notBefore(Date) notBefore(nbf)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder setNotBefore(Date nbf);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.6">
* <code>iat</code></a> (issued at) value. A {@code null} value will remove the property from the Claims.
*
* <p>The value is the timestamp when the JWT was created.</p>
*
* <p>This is a convenience wrapper for:</p>
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#issuedAt(Date) issuedAt(iat)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder issuedAt(Date iat);
/**
* Sets the JWT Claims <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7">
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the Claims.
*
* <p>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.</p>
*
* <p>This is a convenience wrapper for:</p>
* <blockquote><pre>
* {@link #claims()}.{@link ClaimsMutator#id(String) id(jti)}.{@link BuilderClaims#and() and()}</pre></blockquote>
*
* @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
JwtBuilder id(String jti);
/**
* Signs the constructed JWT with the specified key using the key's <em>recommended signature algorithm</em>
* as defined below, producing a JWS. If the recommended signature algorithm isn't sufficient for your needs,
@ -760,7 +738,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* {@code enc} algorithm. In this case, the {@code key} argument <em>MUST</em> 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}.</li>
* {@link AeadAlgorithm#key() key()} builder.</li>
* </ul>
*
* @param key the symmetric encryption key to use with the {@code enc} algorithm.
@ -828,19 +806,35 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
JwtBuilder compressWith(CompressionAlgorithm alg);
/**
* Perform Base64Url encoding with the specified Encoder.
* Perform Base64Url encoding during {@link #compact() compaction} with the specified Encoder.
*
* <p>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.</p>
*
* @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.
*/
@Deprecated
JwtBuilder base64UrlEncodeWith(Encoder<byte[], String> base64UrlEncoder);
/**
* Performs object-to-JSON serialization with the specified Serializer. This is used by the builder to convert
* Perform Base64Url encoding during {@link #compact() compaction} with the specified Encoder.
*
* <p>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.</p>
*
* @param encoder the encoder to use when Base64Url-encoding
* @return the builder for method chaining.
* @since JJWT_RELEASE_VERSION
*/
JwtBuilder encoder(Encoder<byte[], String> 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.
*
* <p>If this method is not called, JJWT will use whatever serializer it can find at runtime, checking for the
@ -850,12 +844,29 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* @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<Map<String, ?>> 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.
*
* <p>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.</p>
*
* @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<Map<String, ?>> serializer);
/**
* Actually builds the JWT and serializes it to a compact, URL-safe string according to the
* <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-7">JWT Compact Serialization</a>
* <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-7.1">JWT Compact Serialization</a>
* rules.
*
* @return A compact URL-safe JWT string.
@ -863,13 +874,30 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
String compact();
/**
* Editable header for use with a {@link JwtBuilder} that supports method chaining for any/all
* 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 BuilderClaims extends MapMutator<String, Object, BuilderClaims>, ClaimsMutator<BuilderClaims> {
/**
* 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
* {@link JwtBuilder} may be obtained with the {@link #and() and()} method for continued configuration.
*
* @since JJWT_RELEASE_VERSION
*/
interface Header extends JweHeaderMutator<Header>, X509Builder<Header> {
interface BuilderHeader extends JweHeaderMutator<BuilderHeader>, X509Builder<BuilderHeader> {
/**
* Returns the associated JwtBuilder for continued configuration.

View File

@ -23,8 +23,11 @@ import io.jsonwebtoken.security.AeadAlgorithm;
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 @@ import java.util.Map;
public interface JwtParserBuilder extends Builder<JwtParser> {
/**
* Enables parsing of Unsecured JWSs (JWTs with an 'alg' (Algorithm) header value of
* 'none'). <b>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). <b>Be careful when calling this method - one should fully understand
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-8.5">Unsecured JWS Security Considerations</a>
* before enabling this feature.</b>
* <p>If this method is not called, Unsecured JWSs are disabled by default as mandated by
* <p>If this method is not called, Unsecured JWTs are disabled by default as mandated by
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6">RFC 7518, Section
* 3.6</a>.</p>
*
@ -60,23 +63,23 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @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
* <a href="https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf">In the
* Compression Hornets Nest: A Security Study of Data Compression in Network Services</a>.
*
* <p>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
* <p>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.</p>
*
* <b>As is the case for {@link #enableUnsecuredJws()}, be careful when calling this method - one should fully
* <b>As is the case for {@link #enableUnsecured()}, be careful when calling this method - one should fully
* understand
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-8.5">Unsecured JWS Security Considerations</a>
* before enabling this feature.</b>
@ -86,7 +89,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @see <a href="https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf">In the
* Compression Hornets Nest: A Security Study of Data Compression in Network Services</a>
* @see Jwts.SIG#NONE
* @see #enableUnsecuredJws()
* @see #enableUnsecured()
* @since JJWT_RELEASE_VERSION
*/
JwtParserBuilder enableUnsecuredDecompression();
@ -100,7 +103,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @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 +208,36 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
*
* @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.
*
* @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.
* @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.
@ -218,7 +248,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* any such value would cause numeric overflow when multiplying by 1000 to obtain
* a millisecond value.
*/
JwtParserBuilder setAllowedClockSkewSeconds(long seconds) throws IllegalArgumentException;
JwtParserBuilder clockSkewSeconds(long seconds) throws IllegalArgumentException;
/**
* <p><b>Deprecation Notice</b></p>
@ -226,7 +256,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* <p>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 <em>only</em> 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.</p>
* {@link SecretKey} instance and call {@link #verifyWith(SecretKey)} instead.</p>
*
* <p>Previous Documentation</p>
*
@ -241,8 +271,8 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @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);
@ -268,7 +298,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* StackOverflow answer</a> explaining why raw (non-base64-encoded) strings are almost always incorrect for
* signature operations.</p>
*
* <p>Finally, please use the {@link #verifyWith(Key)} method instead, as this method (and likely
* <p>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.</p>
*
* <p><b>Previous JavaDoc</b></p>
@ -278,12 +308,12 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* <blockquote><pre>
* 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);</pre></blockquote>
* return {@link #verifyWith(SecretKey) verifyWith}(key);</pre></blockquote>
*
* @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 <b>Deprecation Notice</b>,
* @deprecated in favor of {@link #verifyWith(SecretKey)} as explained in the above <b>Deprecation Notice</b>,
* and will be removed in 1.0.0.
*/
@Deprecated
@ -295,63 +325,104 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* <p>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.</p>
* {@link #verifyWith(SecretKey)} for type safety, to reflect accurate naming of the concept, and for name
* congruence with the {@link #decryptWith(SecretKey)} method.</p>
*
* <p>This method merely delegates directly to {@link #verifyWith(Key)}.</p>
* <p>This method merely delegates directly to {@link #verifyWith(SecretKey)}.</p>
*
* @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.
*
* <p>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
* <em>MUST</em> be a valid key for the signature algorithm ({@code alg} header) used for the JWS.</p>
*
* <p>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.</p>
* <p>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.</p>
*
* <p>Calling this method overrides any previously set signature verification key.</p>
*
* @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(Key key);
JwtParserBuilder verifyWith(SecretKey key);
/**
* Sets the decryption key used to decrypt all encountered JWEs, <b>overwriting any previously configured
* {@link #setKeyLocator(Locator) keyLocator}</b>. 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.
*
* <p>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
* <em>MUST</em> be a valid key for the signature algorithm ({@code alg} header) used for the JWS.</p>
*
* <p>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.</p>
*
* <p>Calling this method overrides any previously set signature verification key.</p>
*
* @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);
/**
* 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.
*
* <p>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 <em>MUST</em> be a valid
* JWEs that can always be decrypted by a single SecretKey. This also implies that this key <em>MUST</em> 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.</p>
*
* <p>If there is any chance that the parser will encounter JWEs that need different decryption keys based on the
* JWE being parsed, or JWSs, it is strongly recommended to configure
* your own {@link Locator Locator} via the {@link #setKeyLocator(Locator) setKeyLocator} method instead of
* using {@code decryptWith}.</p>
* <p>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.</p>
*
* <p>Calling this method overrides any previously set decryption key.</p>
*
* @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(Key key);
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.
*
* <p>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 <em>MUST</em> be a valid
* key for the JWE's key management algorithm ({@code alg} header).</p>
*
* <p>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.</p>
*
* <p>Calling this method overrides any previously set decryption key.</p>
*
* @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);
/**
* Sets the {@link Locator} used to acquire any signature verification or decryption key needed during parsing.
@ -361,13 +432,13 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* <li>If the parsed String is a JWE, it will be called to find the appropriate decryption key.</li>
* </ul>
*
* <p>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
* <p>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:</p>
*
* <pre>
* Jws&lt;Claims&gt; jws = Jwts.parser().setKeyLocator(new Locator&lt;Key&gt;() {
* Jws&lt;Claims&gt; jws = Jwts.parser().keyLocator(new Locator&lt;Key&gt;() {
* &#64;Override
* public Key locate(Header&lt;?&gt; header) {
* if (header instanceof JwsHeader) {
@ -386,14 +457,14 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @return the parser builder for method chaining.
* @since JJWT_RELEASE_VERSION
*/
JwtParserBuilder setKeyLocator(Locator<Key> keyLocator);
JwtParserBuilder keyLocator(Locator<Key> keyLocator);
/**
* <p><b>Deprecation Notice</b></p>
*
* <p>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.</p>
*
* <p><b>Previous Documentation</b></p>
@ -420,7 +491,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
*
* @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
@ -428,82 +499,109 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
/**
* 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.
*
* <p>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}.</p>
* <p>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}.</p>
*
* <p>Finally, {@link Jwts.ZIP#DEF} and {@link Jwts.ZIP#GZIP} algorithms are added last,
* <em>after</em> those in the {@code algs} collection, to ensure that JWA standard algorithms cannot be
* accidentally replaced.</p>
* <p><b>Standard Algorithms and Overrides</b></p>
*
* @param algs collection of compression algorithms to add to the parser's total set of supported compression algorithms.
* <p>The {@link Jwts.ZIP} compression algorithms are supported by default and do not need
* to be added via this method, but beware: <b>any algorithm in the {@code algs} collection with a
* JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation</b>.
* 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, 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<? extends CompressionAlgorithm> 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.
*
* <p>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}.</p>
* <p>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}.</p>
*
* <p>Finally, the {@link Jwts.ENC JWA standard encryption algorithms} are added last,
* <em>after</em> those in the {@code encAlgs} collection, to ensure that JWA standard algorithms cannot be
* accidentally replaced.</p>
* <p><b>Standard Algorithms and Overrides</b></p>
*
* @param encAlgs collection of AEAD encryption algorithms to add to the parser's total set of supported
* encryption algorithms.
* <p>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: <b>any algorithm in the {@code algs} collection with a
* JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation</b>.
* 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 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<? extends AeadAlgorithm> encAlgs);
JwtParserBuilder addEncryptionAlgorithms(Collection<? extends AeadAlgorithm> 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.
*
* <p>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}.</p>
* {@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}.</p>
*
* <p>Finally, the {@link Jwts.SIG JWA standard signature and MAC algorithms} are
* added last, <em>after</em> those in the {@code sigAlgs} collection, to ensure that JWA standard algorithms
* cannot be accidentally replaced.</p>
* <p><b>Standard Algorithms and Overrides</b></p>
*
* @param sigAlgs collection of signing algorithms to add to the parser's total set of supported signature
* algorithms.
* <p>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: <b>any algorithm in the {@code algs} collection with a
* JWA standard {@link Identifiable#getId() id} will replace the JJWT standard
* algorithm implementation</b>. 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 <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-7.1.1">Algorithm Name (id) requirements</a>
* @since JJWT_RELEASE_VERSION
*/
JwtParserBuilder addSignatureAlgorithms(Collection<? extends SecureDigestAlgorithm<?, ?>> sigAlgs);
JwtParserBuilder addSignatureAlgorithms(Collection<? extends SecureDigestAlgorithm<?, ?>> 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.
*
* <p>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}.</p>
* <p>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}.</p>
*
* <p>Finally, the {@link Jwts.KEY#get() JWA standard key management algorithms}
* are added last, <em>after</em> those in the {@code keyAlgs} collection, to ensure that JWA standard algorithms
* cannot be accidentally replaced.</p>
* <p><b>Standard Algorithms and Overrides</b></p>
*
* @param keyAlgs collection of key management algorithms to add to the parser's total set of supported key
* management algorithms.
* <p>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: <b>any algorithm in the {@code algs} collection with a
* JWA standard {@link Identifiable#getId() id} will replace the JJWT standard algorithm implementation</b>.
* 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 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<? extends KeyAlgorithm<?, ?>> keyAlgs);
JwtParserBuilder addKeyAlgorithms(Collection<? extends KeyAlgorithm<?, ?>> algs);
/**
* <p><b>Deprecated as of JJWT JJWT_RELEASE_VERSION. This method will be removed before the 1.0 release.</b></p>
@ -531,6 +629,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @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 +642,41 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
*
* @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 #decoder(Decoder)}. This method will be removed before the JJWT 1.0 release.
*/
@Deprecated
JwtParserBuilder base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder);
/**
* Perform Base64Url decoding with the specified Decoder
*
* <p>JJWT uses a spec-compliant decoder that works on all supported JDK versions, but you may call this method
* to specify a different decoder if you desire.</p>
*
* @param base64UrlDecoder the decoder to use when Base64Url-decoding
* @return the parser builder for method chaining.
*/
JwtParserBuilder decoder(Decoder<String, byte[]> base64UrlDecoder);
/**
* Uses the specified deserializer to convert JSON Strings (UTF-8 byte arrays) into Java Map objects. This is
* used by the parser after Base64Url-decoding to convert JWT/JWS/JWT JSON headers and claims into Java Map
* objects.
*
* <p>If this method is not called, JJWT will use whatever deserializer it can find at runtime, checking for the
* presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
* in the runtime classpath, an exception will be thrown when one of the various {@code parse}* methods is
* invoked.</p>
*
* @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
* @return the builder for method chaining.
* @deprecated since JJWT_RELEASE_VERSION in favor of the shorter and more modern builder-style named
* {@link #deserializer(Deserializer)}. This method will be removed before the JJWT 1.0 release.
*/
@Deprecated
JwtParserBuilder deserializeJsonWith(Deserializer<Map<String, ?>> 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
@ -559,7 +690,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
* @param deserializer the deserializer to use when converting JSON Strings (UTF-8 byte arrays) into Map objects.
* @return the builder for method chaining.
*/
JwtParserBuilder deserializeJsonWith(Deserializer<Map<String, ?>> deserializer);
JwtParserBuilder deserializer(Deserializer<Map<String, ?>> deserializer);
/**
* Returns an immutable/thread-safe {@link JwtParser} created from the configuration from this JwtParserBuilder.

View File

@ -365,7 +365,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Encrypts this newly-generated {@code SecretKey} with a 128-bit shared symmetric key using the
* AES Key Wrap algorithm, producing encrypted key ciphertext.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -389,7 +389,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Encrypts this newly-generated {@code SecretKey} with a 192-bit shared symmetric key using the
* AES Key Wrap algorithm, producing encrypted key ciphertext.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -413,7 +413,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Encrypts this newly-generated {@code SecretKey} with a 256-bit shared symmetric key using the
* AES Key Wrap algorithm, producing encrypted key ciphertext.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -437,7 +437,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.</li>
* <li>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 final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.</li>
* <li>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 final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Generates a new secure-random 96-bit Initialization Vector to use during key wrap/encryption.</li>
* <li>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 final class Jwts {
* <li>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.</li>
* <li>Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
@ -609,7 +609,7 @@ public final class Jwts {
* <li>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.</li>
* <li>Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
@ -654,7 +654,7 @@ public final class Jwts {
* <li>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.</li>
* <li>Generates a new secure-random Content Encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
@ -690,7 +690,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>Encrypts this newly-generated {@code SecretKey} with the RSA key wrap algorithm, using the JWE
* recipient's RSA Public Key, producing encrypted key ciphertext.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -715,7 +715,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -740,7 +740,7 @@ public final class Jwts {
* <p>During JWE creation, this algorithm:</p>
* <ol>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -818,7 +818,7 @@ public final class Jwts {
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">&quot;epk&quot;
* (Ephemeral Public Key) Header Parameter</a> to be transmitted in the JWE.</li>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
@ -866,7 +866,7 @@ public final class Jwts {
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">&quot;epk&quot;
* (Ephemeral Public Key) Header Parameter</a> to be transmitted in the JWE.</li>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
@ -915,7 +915,7 @@ public final class Jwts {
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">&quot;epk&quot;
* (Ephemeral Public Key) Header Parameter</a> to be transmitted in the JWE.</li>
* <li>Generates a new secure-random content encryption {@link SecretKey} suitable for use with a
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#keyBuilder()}).</li>
* specified {@link AeadAlgorithm} (using {@link AeadAlgorithm#key()}).</li>
* <li>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.</li>
@ -1041,7 +1041,7 @@ public final class Jwts {
/**
* <p><b>Deprecated since JJWT_RELEASE_VERSION in favor of
* {@code Jwts.}{@link #claims()}{@code .set(map).build()}</b>.
* {@code Jwts.}{@link #claims()}{@code .add(map).build()}</b>.
* This method will be removed before 1.0.</p>
*
* <p>Returns a new {@link Claims} instance populated with the specified name/value pairs.</p>
@ -1053,16 +1053,7 @@ public final class Jwts {
*/
@Deprecated
public static Claims claims(Map<String, Object> claims) {
return claims().set(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");
return claims().add(claims).build();
}
/**
@ -1076,6 +1067,15 @@ public final class Jwts {
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.
*/

View File

@ -29,6 +29,32 @@ import java.util.Set;
*/
public interface ProtectedHeaderMutator<T extends ProtectedHeaderMutator<T>> extends HeaderMutator<T>, X509Mutator<T> {
/**
* Sets the header parameter names that use extensions to the JWT or JWA specification that <em>MUST</em>
* 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 <em>MUST</em>
* be understood and supported by the JWT recipient.
* @return the header for method chaining.
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11">JWS <code>crit</code> (Critical) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.13">JWS <code>crit</code> (Critical) Header Parameter</a>
*/
T critical(Set<String> crit);
/**
* Sets the {@code jwk} (JSON Web Key) associated with the JWT. When set for a {@link JwsHeader}, the
* {@code jwk} is the public key complement of the private key used to digitally sign the JWS. When set for a
* {@link JweHeader}, the {@code jwk} is the public key to which the JWE was encrypted, and may be used to
* determine the private key needed to decrypt the JWE.
*
* @param jwk the {@code jwk} (JSON Web Key) associated with the header.
* @return the header for method chaining
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.3">JWS <code>jwk</code> (JSON Web Key) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.5">JWE <code>jwk</code> (JSON Web Key) Header Parameter</a>
*/
T jwk(PublicJwk<?> jwk);
/**
* Sets the {@code jku} (JWK Set URL) value that refers to a
* <a href="https://www.rfc-editor.org/rfc/rfc7517.html#section-5">JWK Set</a>
@ -43,20 +69,7 @@ public interface ProtectedHeaderMutator<T extends ProtectedHeaderMutator<T>> ext
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.2">JWS JWK Set URL</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.4">JWE JWK Set URL</a>
*/
T setJwkSetUrl(URI uri);
/**
* Sets the {@code jwk} (JSON Web Key) associated with the JWT. When set for a {@link JwsHeader}, the
* {@code jwk} is the public key complement of the private key used to digitally sign the JWS. When set for a
* {@link JweHeader}, the {@code jwk} is the public key to which the JWE was encrypted, and may be used to
* determine the private key needed to decrypt the JWE.
*
* @param jwk the {@code jwk} (JSON Web Key) associated with the header.
* @return the header for method chaining
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.3">JWS <code>jwk</code> (JSON Web Key) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.5">JWE <code>jwk</code> (JSON Web Key) Header Parameter</a>
*/
T setJwk(PublicJwk<?> jwk);
T jwkSetUrl(URI uri);
/**
* Sets the JWT case-sensitive {@code kid} (Key ID) header value. A {@code null} value will remove the property
@ -73,18 +86,29 @@ public interface ProtectedHeaderMutator<T extends ProtectedHeaderMutator<T>> ext
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.4">JWS Key ID</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.6">JWE Key ID</a>
*/
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 <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.4">JWS Key ID</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.6">JWE Key ID</a>
* @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style {@link #keyId(String)} method.
*/
@Deprecated
T setKeyId(String kid);
/**
* Sets the header parameter names that use extensions to the JWT or JWA specification that <em>MUST</em>
* be understood and supported by the JWT recipient. A {@code null} value will remove the
* property from the JSON map.
* 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 crit the header parameter names that use extensions to the JWT or JWA specification that <em>MUST</em>
* be understood and supported by the JWT recipient.
* @return the header for method chaining.
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11">JWS <code>crit</code> (Critical) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.13">JWS <code>crit</code> (Critical) Header Parameter</a>
* @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.
*/
T setCritical(Set<String> crit);
@Deprecated
T setAlgorithm(String alg);
}

View File

@ -44,7 +44,7 @@ import java.security.Key;
* the {@link io.jsonwebtoken.SigningKeyResolverAdapter} and overriding only the method you need to support instead of
* implementing this interface directly.</p>
*
* @see io.jsonwebtoken.JwtParserBuilder#setKeyLocator(Locator)
* @see io.jsonwebtoken.JwtParserBuilder#keyLocator(Locator)
* @since 0.4
* @deprecated since JJWT_RELEASE_VERSION. Implement {@link Locator} instead.
*/

View File

@ -25,7 +25,7 @@ import java.security.Key;
*
* <p>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. <b>This {@code SigningKeyResolverAdapter} class will be removed before the 1.0 release.</b></p>
*
@ -46,11 +46,11 @@ import java.security.Key;
* 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.</p>
*
* @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

View File

@ -29,6 +29,16 @@ import java.util.Map;
*/
public interface MapMutator<K, V, T extends MapMutator<K, V, T>> {
/**
* Removes the map entry with the specified key.
* <p>This method is the same as {@link Map#remove Map.remove}, but instead returns the mutator instance for
* method chaining.</p>
*
* @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.
* <p>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<K, V, T extends MapMutator<K, V, T>> {
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.
*
* <p>This method is the same as {@link Map#put Map.put}, but instead returns the mutator instance for
* method chaining.</p>
*
@ -48,26 +59,17 @@ public interface MapMutator<K, V, T extends MapMutator<K, V, T>> {
* @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 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.
*
* <p>This method is the same as {@link Map#putAll Map.putAll}, but instead returns the mutator instance for
* method chaining.</p>
*
* @param m the map to add
* @return the mutator/builder for method chaining.
*/
T set(Map<? extends K, ? extends V> m);
/**
* Removes the map entry with the specified key.
* <p>This method is the same as {@link Map#remove Map.remove}, but instead returns the mutator instance for
* method chaining.</p>
*
* @param key the key for the map entry to remove.
* @return the mutator/builder for method chaining.
*/
T delete(K key);
T add(Map<? extends K, ? extends V> m);
}

View File

@ -51,7 +51,7 @@ import javax.crypto.SecretKey;
* and algorithm parameters required by that algorithm. For example:</p>
*
* <pre><code>
* SecretKey key = aeadAlgorithm.keyBuilder().build();
* SecretKey key = aeadAlgorithm.key().build();
* </code></pre>
*
* <p>The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for

View File

@ -69,7 +69,7 @@ public interface AsymmetricJwkBuilder<K extends Key, J extends AsymmetricJwk<K>,
*
* <p>Per
* <a href="https://www.rfc-editor.org/rfc/rfc7517.html#section-4.3">JWK RFC 7517, Section 4.3, last paragraph</a>,
* 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
* <em>SHOULD NOT</em> be used together; however, if both are used, the information they convey <em>MUST</em> be
* consistent. Applications should specify which of these members they use, if either is to be used by the
* application.</p>
@ -78,5 +78,5 @@ public interface AsymmetricJwkBuilder<K extends Key, J extends AsymmetricJwk<K>,
* @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;
}

View File

@ -28,14 +28,56 @@ import java.security.interfaces.RSAPublicKey;
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 <K> the type of Java {@link Key} represented by the created {@link Jwk}.
* @param <J> the type of {@link Jwk} created by the builder
* @since JJWT_RELEASE_VERSION
*/
public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBuilder<K, J, ProtoJwkBuilder<K, J>> {
public interface DynamicJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBuilder<K, J, DynamicJwkBuilder<K, J>> {
/**
* 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) <em>MUST</em> contain a {@link PublicKey}
* instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method.
*
* <p>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:
* <ul>
* <li>{@link #rsaChain(List)}</li>
* <li>{@link #ecChain(List)}</li>
* <li>{@link #octetChain(List)}</li>
* </ul>
*
* <p>If the specified {@code chain} argument is not capable of being supported by one of those methods, an
* {@link UnsupportedKeyException} will be thrown.</p>
*
* <p><b>Type Parameters</b></p>
*
* <p>In addition to the public key type <code>A</code>, the public key's associated private key type
* <code>B</code> 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:</p>
*
* <blockquote><pre>Jwks.builder().&lt;EdECPublicKey, <b>EdECPrivateKey</b>&gt;chain(edECPublicKeyX509CertificateChain)
* .privateKey(<b>aPrivateKey</b>) // &lt;-- must be an EdECPrivateKey instance
* ... etc ...
* .build();</pre></blockquote>
*
* @param <A> the type of {@link PublicKey} provided by the created public JWK.
* @param <B> 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
*/
<A extends PublicKey, B extends PrivateKey> PublicJwkBuilder<A, B, ?, ?, ?, ?> chain(List<X509Certificate> chain)
throws UnsupportedKeyException;
/**
* Ensures the builder will create a {@link SecretJwk} for the specified Java {@link SecretKey}.
@ -43,7 +85,7 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> 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 +93,20 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> 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 +114,30 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> 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:
* <ul>
* <li>{@link #forKey(RSAPublicKey)}</li>
* <li>{@link #forKey(ECPublicKey)}</li>
* <li>{@link #forOctetKey(PublicKey)}</li>
* <li>{@link #key(RSAPublicKey)}</li>
* <li>{@link #key(ECPublicKey)}</li>
* <li>{@link #octetKey(PublicKey)}</li>
* </ul>
*
* <p>If the specified {@code key} argument is not capable of being supported by one of those methods, an
@ -106,10 +147,10 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
*
* <p>In addition to the public key type <code>A</code>, the public key's associated private key type
* <code>B</code> 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:</p>
* {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:</p>
*
* <blockquote><pre>Jwks.builder().&lt;EdECPublicKey, <b>EdECPrivateKey</b>&gt;forKey(anEdECPublicKey)
* .setPrivateKey(<b>aPrivateKey</b>) // &lt;-- must be an EdECPrivateKey instance
* <blockquote><pre>Jwks.builder().&lt;EdECPublicKey, <b>EdECPrivateKey</b>&gt;key(anEdECPublicKey)
* .privateKey(<b>aPrivateKey</b>) // &lt;-- must be an EdECPrivateKey instance
* ... etc ...
* .build();</pre></blockquote>
*
@ -119,21 +160,21 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> 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
*/
<A extends PublicKey, B extends PrivateKey> PublicJwkBuilder<A, B, ?, ?, ?, ?> forKey(A key) throws UnsupportedKeyException;
<A extends PublicKey, B extends PrivateKey> PublicJwkBuilder<A, B, ?, ?, ?, ?> 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:
* <ul>
* <li>{@link #forKey(RSAPrivateKey)}</li>
* <li>{@link #forKey(ECPrivateKey)}</li>
* <li>{@link #forOctetKey(PrivateKey)}</li>
* <li>{@link #key(RSAPrivateKey)}</li>
* <li>{@link #key(ECPrivateKey)}</li>
* <li>{@link #octetKey(PrivateKey)}</li>
* </ul>
*
* <p>If the specified {@code key} argument is not capable of being supported by one of those methods, an
@ -143,10 +184,10 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
*
* <p>In addition to the private key type <code>B</code>, the private key's associated public key type
* <code>A</code> 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:</p>
* {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:</p>
*
* <blockquote><pre>Jwks.builder().&lt;<b>EdECPublicKey</b>, EdECPrivateKey&gt;forKey(anEdECPrivateKey)
* .setPublicKey(<b>aPublicKey</b>) // &lt;-- must be an EdECPublicKey instance
* <blockquote><pre>Jwks.builder().&lt;<b>EdECPublicKey</b>, EdECPrivateKey&gt;key(anEdECPrivateKey)
* .publicKey(<b>aPublicKey</b>) // &lt;-- must be an EdECPublicKey instance
* ... etc ...
* .build();</pre></blockquote>
*
@ -155,11 +196,50 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> 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
*/
<A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> forKey(B key) throws UnsupportedKeyException;
<A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> 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:
* <ul>
* <li>{@link #key(RSAPrivateKey)}</li>
* <li>{@link #key(ECPrivateKey)}</li>
* <li>{@link #octetKey(PrivateKey)}</li>
* </ul>
* <p>and automatically set the resulting builder's {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} with
* the pair's {@code PublicKey}.</p>
*
* <p>If the specified {@code key} argument is not capable of being supported by one of those methods, an
* {@link UnsupportedKeyException} will be thrown.</p>
*
* <p><b>Type Parameters</b></p>
*
* <p>In addition to the private key type <code>B</code>, the private key's associated public key type
* <code>A</code> 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:</p>
*
* <blockquote><pre>Jwks.builder().&lt;<b>EdECPublicKey</b>, EdECPrivateKey&gt;keyPair(anEdECKeyPair)
* .publicKey(<b>aPublicKey</b>) // &lt;-- must be an EdECPublicKey instance
* ... etc ...
* .build();</pre></blockquote>
*
* @param <A> the {@code keyPair} argument's {@link PublicKey} type
* @param <B> 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
*/
<A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> keyPair(KeyPair keyPair)
throws UnsupportedKeyException;
/**
* Ensures the builder will create an {@link OctetPublicJwk} for the specified Edwards-curve {@code PublicKey}
@ -175,10 +255,10 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
*
* <p>In addition to the public key type <code>A</code>, the public key's associated private key type
* <code>B</code> 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:</p>
* {@link PublicJwkBuilder#privateKey(PrivateKey) privateKey} method will be type-safe. For example:</p>
*
* <blockquote><pre>Jwks.builder().&lt;EdECPublicKey, <b>EdECPrivateKey</b>&gt;forKey(anEdECPublicKey)
* .setPrivateKey(<b>aPrivateKey</b>) // &lt;-- must be an EdECPrivateKey instance
* <blockquote><pre>Jwks.builder().&lt;EdECPublicKey, <b>EdECPrivateKey</b>&gt;key(anEdECPublicKey)
* .privateKey(<b>aPrivateKey</b>) // &lt;-- must be an EdECPrivateKey instance
* ... etc ...
* .build();</pre></blockquote>
*
@ -191,7 +271,7 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
* @see <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/interfaces/XECPublicKey.html">java.security.interfaces.XECPublicKey</a>
* @see <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECPublicKey.html">java.security.interfaces.EdECPublicKey</a>
*/
<A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> forOctetKey(A key);
<A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> octetKey(A key);
/**
* Ensures the builder will create an {@link OctetPrivateJwk} for the specified Edwards-curve {@code PrivateKey}
@ -209,10 +289,10 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
*
* <p>In addition to the private key type <code>B</code>, the private key's associated public key type
* <code>A</code> 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:</p>
* {@link PrivateJwkBuilder#publicKey(PublicKey) publicKey} method will be type-safe. For example:</p>
*
* <blockquote><pre>Jwks.builder().&lt;<b>EdECPublicKey</b>, EdECPrivateKey&gt;forKey(anEdECPrivateKey)
* .setPublicKey(<b>aPublicKey</b>) // &lt;-- must be an EdECPublicKey instance
* <blockquote><pre>Jwks.builder().&lt;<b>EdECPublicKey</b>, EdECPrivateKey&gt;key(anEdECPrivateKey)
* .publicKey(<b>aPublicKey</b>) // &lt;-- must be an EdECPublicKey instance
* ... etc ...
* .build();</pre></blockquote>
*
@ -225,64 +305,38 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
* @see <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/interfaces/XECPrivateKey.html">java.security.interfaces.XECPrivateKey</a>
* @see <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECPrivateKey.html">java.security.interfaces.EdECPrivateKey</a>
*/
<A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> forOctetKey(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} <em>MUST</em> be an
* Edwards-curve public key as defined by {@link #forOctetKey(PublicKey)}. The pair's
* {@link KeyPair#getPrivate() private key} <em>MUST</em> be an Edwards-curve private key as defined by
* {@link #forOctetKey(PrivateKey)}.
*
* @param <A> the type of Edwards-curve {@link PublicKey} contained in the key pair.
* @param <B> 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.
*/
<A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> forOctetKeyPair(KeyPair keyPair);
<A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> octetKey(A key);
/**
* 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) <em>MUST</em>
* {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by
* {@link #forOctetKey(PublicKey)}.
* {@link #octetKey(PublicKey)}.
*
* @param <A> the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}.
* @param <B> the type of Edwards-curve {@link PrivateKey} that may be paired with the {@link PublicKey} to produce
* an {@link OctetPrivateJwk} if desired.
* @param <A> the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}.
* @param <B> 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.
*/
<A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> forOctetChain(List<X509Certificate> chain);
<A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> octetChain(List<X509Certificate> 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) <em>MUST</em>
* {@link X509Certificate#getPublicKey() contain} an Edwards-curve public key as defined by
* {@link #forOctetKey(PublicKey)}.
* Ensures the builder will create an {@link OctetPrivateJwk} for the specified Java Edwards-curve
* {@link KeyPair}. The pair's {@link KeyPair#getPublic() public key} <em>MUST</em> be an
* Edwards-curve public key as defined by {@link #octetKey(PublicKey)}. The pair's
* {@link KeyPair#getPrivate() private key} <em>MUST</em> be an Edwards-curve private key as defined by
* {@link #octetKey(PrivateKey)}.
*
* @param <A> the type of Edwards-curve {@link PublicKey} contained in the first {@code X509Certificate}.
* @param <B> 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.
* @param <A> the type of Edwards-curve {@link PublicKey} contained in the key pair.
* @param <B> 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.
*/
<A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> forOctetChain(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) <em>MUST</em> contain an {@link ECPublicKey}
* instance when calling the certificate's {@link X509Certificate#getPublicKey() getPublicKey()} method.
*
* @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}.
*/
EcPublicJwkBuilder forEcChain(X509Certificate... chain);
<A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> octetKeyPair(KeyPair keyPair);
/**
* Ensures the builder will create an {@link EcPublicJwk} for the specified Java {@link X509Certificate} chain.
@ -293,7 +347,7 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
* {@link EcPublicJwk}.
* @return the builder coerced as an {@link EcPublicJwkBuilder}.
*/
EcPublicJwkBuilder forEcChain(List<X509Certificate> chain);
EcPublicJwkBuilder ecChain(List<X509Certificate> chain);
/**
* Ensures the builder will create an {@link EcPrivateJwk} for the specified Java Elliptic Curve
@ -306,18 +360,7 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
* @throws IllegalArgumentException if the {@code keyPair} does not contain {@link ECPublicKey} and
* {@link ECPrivateKey} instances.
*/
EcPrivateJwkBuilder forEcKeyPair(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) <em>MUST</em> 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 forRsaChain(X509Certificate... chain);
EcPrivateJwkBuilder ecKeyPair(KeyPair keyPair) throws IllegalArgumentException;
/**
* Ensures the builder will create an {@link RsaPublicJwk} for the specified Java {@link X509Certificate} chain.
@ -328,7 +371,7 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> extends JwkBui
* {@link RsaPublicJwk}.
* @return the builder coerced as an {@link RsaPublicJwkBuilder}.
*/
RsaPublicJwkBuilder forRsaChain(List<X509Certificate> chain);
RsaPublicJwkBuilder rsaChain(List<X509Certificate> chain);
/**
* Ensures the builder will create an {@link RsaPrivateJwk} for the specified Java RSA
@ -341,5 +384,5 @@ public interface ProtoJwkBuilder<K extends Key, J extends Jwk<K>> 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;
}

View File

@ -57,7 +57,7 @@ public interface JwkBuilder<K extends Key, J extends Jwk<K>, 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 <a href="https://www.rfc-editor.org/rfc/rfc7517.html#section-4.5">{@code kid} (Key ID)
@ -77,22 +77,22 @@ public interface JwkBuilder<K extends Key, J extends Jwk<K>, 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
* <code>jwk.{@link Jwk#thumbprint(HashAlgorithm) thumbprint}({@link Jwks.HASH}.{@link Jwks.HASH#SHA256 SHA256}).{@link JwkThumbprint#toString() toString()}</code>.
*
* <p>This is a convenience method that delegates to {@link #setIdFromThumbprint(HashAlgorithm)} using
* <p>This is a convenience method that delegates to {@link #idFromThumbprint(HashAlgorithm)} using
* {@link Jwks.HASH}{@code .}{@link Jwks.HASH#SHA256 SHA256}.</p>
*
* @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
* <code>{@link Jwk#thumbprint(HashAlgorithm) thumbprint}(alg).{@link JwkThumbprint#toString() toString()}.</code>
@ -101,7 +101,7 @@ public interface JwkBuilder<K extends Key, J extends Jwk<K>, T extends JwkBuilde
* @return the builder for method chaining.
* @see Jwks.HASH
*/
T setIdFromThumbprint(HashAlgorithm alg);
T idFromThumbprint(HashAlgorithm alg);
/**
* Sets the JWK <a href="https://www.rfc-editor.org/rfc/rfc7517.html#section-4.3">{@code key_ops}
@ -174,5 +174,5 @@ public interface JwkBuilder<K extends Key, J extends Jwk<K>, T extends JwkBuilde
* @return the builder for method chaining.
* @throws IllegalArgumentException if {@code ops} is {@code null} or empty.
*/
T setOperations(Set<String> ops) throws IllegalArgumentException;
T operations(Set<String> ops) throws IllegalArgumentException;
}

View File

@ -25,7 +25,7 @@ import java.util.Map;
* A builder to construct a {@link JwkParser}. Example usage:
* <blockquote><pre>
* Jwk&lt;?&gt; jwk = Jwks.parser()
* .setProvider(aJcaProvider) // optional
* .provider(aJcaProvider) // optional
* .deserializeJsonWith(deserializer) // optional
* .build()
* .parse(jwkString);</pre></blockquote>
@ -42,7 +42,7 @@ public interface JwkParserBuilder extends Builder<JwkParser> {
* 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

View File

@ -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";
@ -54,7 +54,7 @@ public final class Jwks {
* <blockquote><pre>
* Jwks.{@link Jwks#builder}()
* // ... etc ...
* .{@link JwkBuilder#setIdFromThumbprint(HashAlgorithm) setIdFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // &lt;---
* .{@link JwkBuilder#idFromThumbprint(HashAlgorithm) idFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // &lt;---
* .build()</pre></blockquote>
* <p>or</p>
* <blockquote><pre>
@ -152,7 +152,7 @@ public final class Jwks {
*
* @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);
}

View File

@ -22,8 +22,8 @@ import java.security.Key;
* their associated cryptographic algorithm implementation.
*
* @param <K> type of {@link Key} created by the builder
* @param <B> type of builder to create each time {@link #keyBuilder()} is called.
* @see #keyBuilder()
* @param <B> 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<K extends Key, B extends KeyBuilder<K, B>> {
* @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();
}

View File

@ -21,7 +21,7 @@ import java.security.KeyPair;
* 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();
}

View File

@ -49,8 +49,7 @@ public interface KeyRequest<T> extends Request<T> {
* {@code KeyRequest}. {@link KeyAlgorithm} implementations that generate an ephemeral {@code SecretKey} to use
* as what the <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-2">JWE specification calls</a> a
* &quot;Content Encryption Key (CEK)&quot; 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}.

View File

@ -68,8 +68,8 @@ public final class Keys {
"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 final class Keys {
* <p><b>Deprecation Notice</b></p>
*
* <p>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:</p>
* length for that specific algorithm by calling their {@code key()} builder method directly. For example:</p>
*
* <pre><code>
* {@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();
* </code></pre>
*
* <p>Call those methods as needed instead of this static {@code secretKeyFor} helper method - the returned
@ -124,7 +124,7 @@ public final class Keys {
* @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 final class Keys {
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();
}
/**
* <p><b>Deprecation Notice</b></p>
*
* <p>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:</p>
* for that specific algorithm by calling their {@code keyPair()} builder method directly. For example:</p>
*
* <blockquote><pre>
* 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();</pre></blockquote>
* Jwts.SIG.{@link Jwts.SIG#ES512 ES512}.keyPair().build();</pre></blockquote>
*
* <p>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 final class Keys {
* @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 final class Keys {
throw new IllegalArgumentException(msg);
}
SignatureAlgorithm asalg = ((SignatureAlgorithm) salg);
return asalg.keyPairBuilder().build();
return asalg.keyPair().build();
}
/**
@ -264,7 +264,7 @@ public final class Keys {
* @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});
}
}

View File

@ -47,7 +47,7 @@ import javax.crypto.SecretKey;
* have a sufficient length and any algorithm parameters required by that algorithm. For example:</p>
*
* <blockquote><pre>
* SecretKey key = macAlgorithm.keyBuilder().build();</pre></blockquote>
* SecretKey key = macAlgorithm.key().build();</pre></blockquote>
*
* <p>The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for
* that exact {@code MacAlgorithm} instance.</p>

View File

@ -26,7 +26,7 @@ import java.security.PublicKey;
* @param <M> the type of {@link PrivateJwk} created
* @param <J> the type of {@link PublicJwk} paired with the created private JWK.
* @param <T> the type of the builder, for subtype method chaining
* @see #setPublicKey(PublicKey)
* @see #publicKey(PublicKey)
* @since JJWT_RELEASE_VERSION
*/
public interface PrivateJwkBuilder<K extends PrivateKey, L extends PublicKey,
@ -40,7 +40,7 @@ public interface PrivateJwkBuilder<K extends PrivateKey, L extends PublicKey,
*
* <p>As discussed in the {@link PrivateJwk} documentation, the JWK and JWA specifications require private JWKs to
* contain <em>both</em> private key <em>and</em> 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.</p>
*
* <p>Calling this method with the {@code PrivateKey}'s matching {@code PublicKey} instance eliminates the need
@ -49,5 +49,5 @@ public interface PrivateJwkBuilder<K extends PrivateKey, L extends PublicKey,
* @param publicKey the {@link PublicKey} that matches the builder's existing {@link PrivateKey}.
* @return the builder for method chaining.
*/
T setPublicKey(L publicKey);
T publicKey(L publicKey);
}

View File

@ -27,7 +27,7 @@ import java.security.PublicKey;
* @param <M> the type of {@link PrivateJwk} that matches the created {@link PublicJwk}
* @param <P> the type of {@link PrivateJwkBuilder} that matches this builder if a {@link PrivateJwk} is desired.
* @param <T> the type of the builder, for subtype method chaining
* @see #setPrivateKey(PrivateKey)
* @see #privateKey(PrivateKey)
* @since JJWT_RELEASE_VERSION
*/
public interface PublicJwkBuilder<K extends PublicKey, L extends PrivateKey,
@ -43,5 +43,5 @@ public interface PublicJwkBuilder<K extends PublicKey, L extends PrivateKey,
* @param privateKey the {@link PrivateKey} that pairs with the builder's existing {@link PublicKey}
* @return the builder coerced as a {@link PrivateJwkBuilder} which will produce a corresponding {@link PrivateJwk}.
*/
P setPrivateKey(L privateKey);
P privateKey(L privateKey);
}

View File

@ -25,8 +25,8 @@ import java.security.SecureRandom;
* during instance creation, such as a {@link java.security.Provider} or {@link java.security.SecureRandom}.
*
* @param <T> 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<T, B extends SecurityBuilder<T, B>> extends Builder<T> {
@ -38,7 +38,7 @@ public interface SecurityBuilder<T, B extends SecurityBuilder<T, B>> 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<T, B extends SecurityBuilder<T, B>> 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);
}

View File

@ -38,7 +38,7 @@ import java.security.PublicKey;
* required by that algorithm. For example:</p>
*
* <blockquote><pre>
* KeyPair pair = signatureAlgorithm.keyPairBuilder().build();</pre></blockquote>
* KeyPair pair = signatureAlgorithm.keyPair().build();</pre></blockquote>
*
* <p>The resulting {@code pair} is guaranteed to have the correct algorithm parameters and length/strength necessary
* for that exact {@code signatureAlgorithm} instance.</p>

View File

@ -28,8 +28,8 @@ public interface X509Builder<T extends X509Builder<T>> extends X509Mutator<T> {
/**
* 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.
*
* <p>If no chain has been configured, or {@code enable} is {@code false}, the builder will not compute nor add a
* {@code x5t} value.</p>
@ -42,8 +42,8 @@ public interface X509Builder<T extends X509Builder<T>> extends X509Mutator<T> {
/**
* 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.
*
* <p>If no chain has been configured, or {@code enable} is {@code false}, the builder will not compute nor add a
* {@code x5t#S256} value.</p>

View File

@ -62,7 +62,7 @@ public interface X509Mutator<T extends X509Mutator<T>> {
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.5">JWS <code>x5u</code> (X.509 URL) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.7">JWE <code>x5u</code> (X.509 URL) Header Parameter</a>
*/
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<T extends X509Mutator<T>> {
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.6">JWS <code>x5c</code> (X.509 Certificate Chain) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.8">JWE <code>x5c</code> (X.509 Certificate Chain) Header Parameter</a>
*/
T setX509CertificateChain(List<X509Certificate> chain);
T x509CertificateChain(List<X509Certificate> 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<T extends X509Mutator<T>> {
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.7">JWS <code>x5t</code> (X.509 Certificate SHA-1 Thumbprint) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.9">JWE <code>x5t</code> (X.509 Certificate SHA-1 Thumbprint) Header Parameter</a>
*/
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<T extends X509Mutator<T>> {
* @see <a href="https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.8">JWS <code>x5t#S256</code> (X.509 Certificate SHA-256 Thumbprint) Header Parameter</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.10">JWE <code>x5t#S256</code> (X.509 Certificate SHA-256 Thumbprint) Header Parameter</a>
*/
T setX509CertificateSha256Thumbprint(byte[] thumbprint);
T x509CertificateSha256Thumbprint(byte[] thumbprint);
}

View File

@ -41,7 +41,7 @@ public class AbstractX509Context<T extends X509Mutator<T>> extends FieldMap impl
}
@Override
public T setX509Url(URI uri) {
public T x509Url(URI uri) {
put(AbstractAsymmetricJwk.X5U, uri);
return self();
}
@ -52,7 +52,7 @@ public class AbstractX509Context<T extends X509Mutator<T>> extends FieldMap impl
}
@Override
public T setX509CertificateChain(List<X509Certificate> chain) {
public T x509CertificateChain(List<X509Certificate> chain) {
put(AbstractAsymmetricJwk.X5C, chain);
return self();
}
@ -63,7 +63,7 @@ public class AbstractX509Context<T extends X509Mutator<T>> extends FieldMap impl
}
@Override
public T setX509CertificateSha1Thumbprint(byte[] thumbprint) {
public T x509CertificateSha1Thumbprint(byte[] thumbprint) {
put(AbstractAsymmetricJwk.X5T, thumbprint);
return self();
}
@ -74,7 +74,7 @@ public class AbstractX509Context<T extends X509Mutator<T>> extends FieldMap impl
}
@Override
public T setX509CertificateSha256Thumbprint(byte[] thumbprint) {
public T x509CertificateSha256Thumbprint(byte[] thumbprint) {
put(AbstractAsymmetricJwk.X5T_S256, thumbprint);
return self();
}

View File

@ -17,60 +17,16 @@ package io.jsonwebtoken.impl;
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<String, Object, FieldMap, ClaimsBuilder>
public final class DefaultClaimsBuilder extends DelegatingClaimsMutator<ClaimsBuilder>
implements ClaimsBuilder {
public DefaultClaimsBuilder() {
super(new FieldMap(DefaultClaims.FIELDS));
}
<T> ClaimsBuilder put(Field<T> field, Object value) {
this.DELEGATE.put(field, value);
return self();
}
@Override
public ClaimsBuilder setIssuer(String iss) {
return put(DefaultClaims.ISSUER, iss);
}
@Override
public ClaimsBuilder setSubject(String sub) {
return put(DefaultClaims.SUBJECT, sub);
}
@Override
public ClaimsBuilder setAudience(String aud) {
return put(DefaultClaims.AUDIENCE, aud);
}
@Override
public ClaimsBuilder setExpiration(Date exp) {
return put(DefaultClaims.EXPIRATION, exp);
}
@Override
public ClaimsBuilder setNotBefore(Date nbf) {
return put(DefaultClaims.NOT_BEFORE, nbf);
}
@Override
public ClaimsBuilder setIssuedAt(Date iat) {
return put(DefaultClaims.ISSUED_AT, iat);
}
@Override
public ClaimsBuilder setId(String jti) {
return put(DefaultClaims.JTI, jti);
super();
}
@Override

View File

@ -29,8 +29,8 @@ public class DefaultJwe<P> extends DefaultProtectedJwt<JweHeader, P> 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.");
}

View File

@ -67,21 +67,31 @@ public class DefaultJweHeaderMutator<T extends JweHeaderMutator<T>>
// 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 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);
@ -92,51 +102,60 @@ public class DefaultJweHeaderMutator<T extends JweHeaderMutator<T>>
// =============================================================
@Override
public T setJwkSetUrl(URI uri) {
return put(DefaultProtectedHeader.JKU, uri);
public T critical(Set<String> crit) {
return put(DefaultProtectedHeader.CRIT, crit);
}
@Override
public T setJwk(PublicJwk<?> jwk) {
public T jwk(PublicJwk<?> jwk) {
return put(DefaultProtectedHeader.JWK, jwk);
}
@Override
public T setKeyId(String kid) {
public T jwkSetUrl(URI uri) {
return put(DefaultProtectedHeader.JKU, uri);
}
@Override
public T keyId(String kid) {
return put(DefaultProtectedHeader.KID, kid);
}
@Override
public T setCritical(Set<String> 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
// =============================================================
@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<X509Certificate> chain) {
this.x509.setX509CertificateChain(chain);
public T x509CertificateChain(List<X509Certificate> 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 +164,27 @@ public class DefaultJweHeaderMutator<T extends JweHeaderMutator<T>>
// =============================================================
@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);
}
}

View File

@ -25,8 +25,8 @@ public class DefaultJws<P> extends DefaultProtectedJwt<JwsHeader, P> 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;
}

View File

@ -15,8 +15,7 @@
*/
package io.jsonwebtoken.impl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ClaimsBuilder;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JweHeader;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
@ -38,6 +37,7 @@ import io.jsonwebtoken.io.Serializer;
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;
@ -63,14 +63,15 @@ import java.util.Map;
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 DefaultJwtBuilderHeader headerBuilder = new DefaultJwtBuilderHeader(this);
private final ClaimsBuilder claimsBuilder = new DefaultClaimsBuilder();
private final DefaultBuilderHeader headerBuilder;
private final DefaultBuilderClaims claimsBuilder;
protected byte[] content;
@ -89,22 +90,32 @@ public class DefaultJwtBuilder implements JwtBuilder {
protected Function<Map<String, ?>, byte[]> headerSerializer;
protected Function<Map<String, ?>, byte[]> claimsSerializer;
protected Encoder<byte[], String> base64UrlEncoder = Encoders.BASE64URL;
protected Encoder<byte[], String> 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 setProvider(Provider provider) {
public BuilderClaims claims() {
return this.claimsBuilder;
}
@Override
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;
}
@ -130,6 +141,11 @@ public class DefaultJwtBuilder implements JwtBuilder {
@Override
public JwtBuilder serializeToJsonWith(final Serializer<Map<String, ?>> serializer) {
return serializer(serializer);
}
@Override
public JwtBuilder serializer(Serializer<Map<String, ?>> serializer) {
Assert.notNull(serializer, "Serializer cannot be null.");
this.serializer = serializer;
this.headerSerializer = wrap(serializer, "header");
@ -138,29 +154,30 @@ public class DefaultJwtBuilder implements JwtBuilder {
}
@Override
public JwtBuilder base64UrlEncodeWith(Encoder<byte[], String> base64UrlEncoder) {
Assert.notNull(base64UrlEncoder, "base64UrlEncoder cannot be null.");
this.base64UrlEncoder = base64UrlEncoder;
public JwtBuilder base64UrlEncodeWith(Encoder<byte[], String> encoder) {
return encoder(encoder);
}
@Override
public JwtBuilder encoder(Encoder<byte[], String> encoder) {
Assert.notNull(encoder, "encoder cannot be null.");
this.encoder = encoder;
return this;
}
@Override
public JwtBuilder setHeader(Map<String, ?> map) {
this.headerBuilder.clear();
this.headerBuilder.putAll(map);
return this;
return this.headerBuilder.empty().add(map).and();
}
@Override
public JwtBuilder setHeaderParams(Map<String, ?> 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
@ -227,7 +244,8 @@ public class DefaultJwtBuilder implements JwtBuilder {
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);
}
@ -236,7 +254,8 @@ public class DefaultJwtBuilder implements JwtBuilder {
@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);
}
@ -293,90 +312,119 @@ public class DefaultJwtBuilder implements JwtBuilder {
@Override
public JwtBuilder setPayload(String payload) {
byte[] bytes = payload != null ? payload.getBytes(StandardCharsets.UTF_8) : null;
return setContent(bytes);
return content(Strings.utf8(payload));
}
@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);
}
@Override
public JwtBuilder setClaims(Claims claims) {
Assert.notNull(claims, "Claims argument cannot be null.");
return setClaims((Map<String, ?>) claims);
this.headerBuilder.contentType(cty);
return content(content);
}
@Override
public JwtBuilder setClaims(Map<String, ?> claims) {
Assert.notNull(claims, "Claims map cannot be null.");
this.claimsBuilder.empty();
this.claimsBuilder.set(claims);
return this;
return this.claimsBuilder.empty().add(claims).and();
}
@Override
public JwtBuilder addClaims(Map<String, ?> claims) {
this.claimsBuilder.set(claims);
return this;
return claims(claims);
}
@Override
public JwtBuilder claims(Map<String, ?> claims) {
return claims().add(claims).and();
}
@Override
public JwtBuilder claim(String name, Object value) {
return claims().add(name, value).and();
}
@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 this;
return id(jti);
}
@Override
public JwtBuilder claim(String name, Object value) {
this.claimsBuilder.set(name, value);
public JwtBuilder id(String jti) {
this.claimsBuilder.id(jti);
return this;
}
@ -390,7 +438,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
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:
@ -406,7 +454,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
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;
@ -415,7 +463,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
}
if (!Objects.isEmpty(payload) && compressionAlgorithm != null) {
payload = compressionAlgorithm.compress(payload);
this.headerBuilder.setCompressionAlgorithm(compressionAlgorithm.getId());
this.headerBuilder.add(DefaultHeader.COMPRESSION_ALGORITHM.getId(), compressionAlgorithm.getId());
}
if (jwe) {
@ -425,25 +473,17 @@ public class DefaultJwtBuilder implements JwtBuilder {
}
}
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());
this.headerBuilder.setAlgorithm(sigAlg.getId());
final io.jsonwebtoken.Header header = buildHeader();
final Header header = this.headerBuilder.build();
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;
@ -453,7 +493,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
byte[] data = jwt.getBytes(StandardCharsets.US_ASCII);
SecureRequest<byte[], Key> 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
@ -483,13 +523,13 @@ public class DefaultJwtBuilder implements JwtBuilder {
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.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 = 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);
@ -499,20 +539,43 @@ public class DefaultJwtBuilder implements JwtBuilder {
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;
return base64UrlEncodedHeader + DefaultJwtParser.SEPARATOR_CHAR +
base64UrlEncodedEncryptedCek + DefaultJwtParser.SEPARATOR_CHAR +
base64UrlEncodedIv + DefaultJwtParser.SEPARATOR_CHAR +
base64UrlEncodedCiphertext + DefaultJwtParser.SEPARATOR_CHAR +
base64UrlEncodedTag;
}
private static class DefaultJwtBuilderHeader extends DefaultJweHeaderBuilder<Header>
implements JwtBuilder.Header {
private static class DefaultBuilderClaims extends DelegatingClaimsMutator<BuilderClaims>
implements BuilderClaims {
private final JwtBuilder builder;
public DefaultJwtBuilderHeader(JwtBuilder builder) {
private DefaultBuilderClaims(JwtBuilder builder) {
super();
this.builder = builder;
}
@Override
public JwtBuilder and() {
return this.builder;
}
private io.jsonwebtoken.Claims build() {
return new DefaultClaims(this.DELEGATE);
}
}
private static class DefaultBuilderHeader extends DefaultJweHeaderBuilder<BuilderHeader> implements BuilderHeader {
private final JwtBuilder builder;
private DefaultBuilderHeader(JwtBuilder builder) {
super();
this.builder = Assert.notNull(builder, "JwtBuilder cannot be null.");
}
@ -521,5 +584,9 @@ public class DefaultJwtBuilder implements JwtBuilder {
public JwtBuilder and() {
return builder;
}
private Header build() {
return new DefaultJwtHeaderBuilder(this).build();
}
}
}

View File

@ -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.enableUnsecuredJws() 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,15 +120,15 @@ 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;
@SuppressWarnings("deprecation")
private final SigningKeyResolver signingKeyResolver;
private final boolean enableUnsecuredJws;
private final boolean enableUnsecured;
private final boolean enableUnsecuredDecompression;
@ -143,7 +142,7 @@ public class DefaultJwtParser implements JwtParser {
private final Locator<? extends Key> keyLocator;
private final Decoder<String, byte[]> base64UrlDecoder;
private final Decoder<String, byte[]> decoder;
private final Deserializer<Map<String, ?>> deserializer;
@ -157,7 +156,7 @@ public class DefaultJwtParser implements JwtParser {
@SuppressWarnings("deprecation")
DefaultJwtParser(Provider provider,
SigningKeyResolver signingKeyResolver,
boolean enableUnsecuredJws,
boolean enableUnsecured,
boolean enableUnsecuredDecompression,
Locator<? extends Key> keyLocator,
Clock clock,
@ -171,14 +170,14 @@ public class DefaultJwtParser implements JwtParser {
Collection<KeyAlgorithm<?, ?>> extraKeyAlgs,
Collection<AeadAlgorithm> 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.");
this.clock = Assert.notNull(clock, "Clock cannot be null.");
this.allowedClockSkewMillis = allowedClockSkewMillis;
this.expectedClaims = Jwts.claims().set(expectedClaims);
this.base64UrlDecoder = Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null.");
this.expectedClaims = Jwts.claims().add(expectedClaims);
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);
@ -305,10 +304,10 @@ public class DefaultJwtParser implements JwtParser {
}
//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 = base64UrlDecode(tokenized.getDigest(), "JWS signature");
byte[] signature = decode(tokenized.getDigest(), "JWS signature");
try {
VerifySecureDigestRequest<Key> request =
@ -346,8 +345,8 @@ public class DefaultJwtParser implements JwtParser {
}
// =============== Header =================
final byte[] headerBytes = base64UrlDecode(base64UrlHeader, "protected header");
Map<String, ?> m = readValue(headerBytes, "protected header");
final byte[] headerBytes = decode(base64UrlHeader, "protected header");
Map<String, ?> m = deserialize(headerBytes, "protected header");
Header header;
try {
header = tokenized.createHeader(m);
@ -376,7 +375,7 @@ public class DefaultJwtParser implements JwtParser {
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);
}
@ -389,9 +388,9 @@ public class DefaultJwtParser implements JwtParser {
throw new MalformedJwtException(msg);
}
// =============== Body =================
byte[] payload = base64UrlDecode(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);
}
@ -406,7 +405,7 @@ public class DefaultJwtParser implements JwtParser {
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 @@ public class DefaultJwtParser implements JwtParser {
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 @@ public class DefaultJwtParser implements JwtParser {
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);
@ -467,7 +466,7 @@ public class DefaultJwtParser implements JwtParser {
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);
}
@ -490,7 +489,7 @@ public class DefaultJwtParser implements JwtParser {
// parameter is performed by the JWS application."
//
&& isLikelyJson(payload)) { // likely to be json, parse it:
Map<String, ?> claimsMap = readValue(payload, "claims");
Map<String, ?> claimsMap = deserialize(payload, "claims");
try {
claims = new DefaultClaims(claimsMap);
} catch (Exception e) {
@ -708,16 +707,16 @@ public class DefaultJwtParser implements JwtParser {
});
}
protected byte[] base64UrlDecode(String base64UrlEncoded, String name) {
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);
}
}
protected Map<String, ?> readValue(byte[] bytes, final String name) {
protected Map<String, ?> deserialize(byte[] bytes, final String name) {
try {
return deserializer.deserialize(bytes);
} catch (MalformedJwtException | DeserializationException e) {

View File

@ -36,8 +36,11 @@ import io.jsonwebtoken.security.KeyAlgorithm;
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;
@ -82,7 +85,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
@SuppressWarnings("deprecation")
private CompressionCodecResolver compressionCodecResolver;
private Decoder<String, byte[]> base64UrlDecoder = Decoders.BASE64URL;
private Decoder<String, byte[]> decoder = Decoders.BASE64URL;
private Deserializer<Map<String, ?>> deserializer;
@ -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;
}
@ -108,22 +111,32 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
}
@Override
public JwtParserBuilder setProvider(Provider provider) {
public JwtParserBuilder provider(Provider provider) {
this.provider = provider;
return this;
}
@Override
public JwtParserBuilder deserializeJsonWith(Deserializer<Map<String, ?>> deserializer) {
return deserializer(deserializer);
}
@Override
public JwtParserBuilder deserializer(Deserializer<Map<String, ?>> deserializer) {
Assert.notNull(deserializer, "deserializer cannot be null.");
this.deserializer = deserializer;
return this;
}
@Override
public JwtParserBuilder base64UrlDecodeWith(Decoder<String, byte[]> base64UrlDecoder) {
Assert.notNull(base64UrlDecoder, "base64UrlDecoder cannot be null.");
this.base64UrlDecoder = base64UrlDecoder;
public JwtParserBuilder base64UrlDecodeWith(Decoder<String, byte[]> decoder) {
return decoder(decoder);
}
@Override
public JwtParserBuilder decoder(Decoder<String, byte[]> decoder) {
Assert.notNull(decoder, "decoder cannot be null.");
this.decoder = decoder;
return this;
}
@ -173,12 +186,17 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
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;
}
@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 +204,11 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
@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;
@ -210,13 +233,31 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
}
@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;
}
@ -229,23 +270,23 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
}
@Override
public JwtParserBuilder addEncryptionAlgorithms(Collection<? extends AeadAlgorithm> encAlgs) {
Assert.notEmpty(encAlgs, "Additional AeadAlgorithm collection cannot be null or empty.");
this.extraEncAlgs.addAll(encAlgs);
public JwtParserBuilder addEncryptionAlgorithms(Collection<? extends AeadAlgorithm> algs) {
Assert.notEmpty(algs, "Additional AeadAlgorithm collection cannot be null or empty.");
this.extraEncAlgs.addAll(algs);
return this;
}
@Override
public JwtParserBuilder addSignatureAlgorithms(Collection<? extends SecureDigestAlgorithm<?, ?>> sigAlgs) {
Assert.notEmpty(sigAlgs, "Additional SignatureAlgorithm collection cannot be null or empty.");
this.extraSigAlgs.addAll(sigAlgs);
public JwtParserBuilder addSignatureAlgorithms(Collection<? extends SecureDigestAlgorithm<?, ?>> algs) {
Assert.notEmpty(algs, "Additional SignatureAlgorithm collection cannot be null or empty.");
this.extraSigAlgs.addAll(algs);
return this;
}
@Override
public JwtParserBuilder addKeyAlgorithms(Collection<? extends KeyAlgorithm<?, ?>> keyAlgs) {
Assert.notEmpty(keyAlgs, "Additional KeyAlgorithm collection cannot be null or empty.");
this.extraKeyAlgs.addAll(keyAlgs);
public JwtParserBuilder addKeyAlgorithms(Collection<? extends KeyAlgorithm<?, ?>> algs) {
Assert.notEmpty(algs, "Additional KeyAlgorithm collection cannot be null or empty.");
this.extraKeyAlgs.addAll(algs);
return this;
}
@ -258,7 +299,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
}
@Override
public JwtParserBuilder setKeyLocator(Locator<Key> keyLocator) {
public JwtParserBuilder keyLocator(Locator<Key> keyLocator) {
this.keyLocator = Assert.notNull(keyLocator, "Key locator cannot be null.");
return this;
}
@ -304,8 +345,8 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
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);
@ -324,13 +365,13 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
return new DefaultJwtParser(
provider,
signingKeyResolver,
enableUnsecuredJws,
enableUnsecured,
enableUnsecuredDecompression,
keyLocator,
clock,
allowedClockSkewMillis,
expClaims,
base64UrlDecoder,
decoder,
new JwtDeserializer<>(deserializer),
compressionCodecResolver,
extraZipAlgs,

View File

@ -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();
}
}

View File

@ -24,12 +24,12 @@ import java.util.Map;
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 @@ class DefaultTokenizedJwt implements TokenizedJwt {
}
@Override
public String getBody() {
return this.body;
public String getPayload() {
return this.payload;
}
@Override

View File

@ -0,0 +1,111 @@
/*
* 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;
import io.jsonwebtoken.impl.lang.DelegatingMapMutator;
import io.jsonwebtoken.impl.lang.Field;
import io.jsonwebtoken.lang.MapMutator;
import java.util.Date;
/**
* @param <T> subclass type
* @since JJWT_RELEASE_VERSION
*/
public class DelegatingClaimsMutator<T extends MapMutator<String, Object, T> & ClaimsMutator<T>>
extends DelegatingMapMutator<String, Object, FieldMap, T>
implements ClaimsMutator<T> {
protected DelegatingClaimsMutator() {
super(new FieldMap(DefaultClaims.FIELDS));
}
<F> T put(Field<F> 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);
}
}

View File

@ -47,9 +47,22 @@ public class IdLocator<H extends Header, R extends Identifiable> implements Loca
this.valueRequired = Strings.hasText(this.requiredMsg);
Assert.notEmpty(registry, "Registry cannot be null or empty.");
Collection<R> 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) {

View File

@ -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();
}

View File

@ -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.

View File

@ -41,13 +41,13 @@ public class DelegatingMapMutator<K, V, D extends Map<K, V>, T extends MapMutato
}
@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<? extends K, ? extends V> m) {
public T add(Map<? extends K, ? extends V> m) {
putAll(m);
return self();
}

View File

@ -69,7 +69,7 @@ abstract class AbstractAsymmetricJwkBuilder<K extends Key, J extends AsymmetricJ
}
@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 @@ abstract class AbstractAsymmetricJwkBuilder<K extends Key, J extends AsymmetricJ
*/
@Override
public T setX509CertificateChain(List<X509Certificate> chain) {
public T x509CertificateChain(List<X509Certificate> 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 @@ abstract class AbstractAsymmetricJwkBuilder<K extends Key, J extends AsymmetricJ
*/
@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 @@ abstract class AbstractAsymmetricJwkBuilder<K extends Key, J extends AsymmetricJ
}
@Override
public P setPrivateKey(L privateKey) {
public P privateKey(L privateKey) {
Assert.notNull(privateKey, "PrivateKey argument cannot be null.");
final K publicKey = Assert.notNull(DELEGATE.getKey(), "PublicKey cannot be null.");
return newPrivateBuilder(newContext(privateKey)).setPublicKey(publicKey);
return newPrivateBuilder(newContext(privateKey)).publicKey(publicKey);
}
protected abstract P newPrivateBuilder(JwkContext<L> ctx);
@ -170,7 +170,7 @@ abstract class AbstractAsymmetricJwkBuilder<K extends Key, J extends AsymmetricJ
}
@Override
public T setPublicKey(L publicKey) {
public T publicKey(L publicKey) {
this.DELEGATE.setPublicKey(publicKey);
return self();
}

View File

@ -54,26 +54,26 @@ abstract class AbstractJwkBuilder<K extends Key, J extends Jwk<K>, T extends Jwk
}
@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 @@ abstract class AbstractJwkBuilder<K extends Key, J extends Jwk<K>, T extends Jwk
}
@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 @@ abstract class AbstractJwkBuilder<K extends Key, J extends Jwk<K>, T extends Jwk
}
@Override
public T setOperations(Set<String> ops) {
public T operations(Set<String> ops) {
Assert.notEmpty(ops, "Operations cannot be null or empty.");
this.DELEGATE.setOperations(ops);
return self();

View File

@ -81,7 +81,7 @@ abstract class AesAlgorithm extends CryptoAlgorithm implements KeyBuilderSupplie
}
@Override
public SecretKeyBuilder keyBuilder() {
public SecretKeyBuilder key() {
return new DefaultSecretKeyBuilder(KEY_ALG_NAME, getKeyBitLength());
}

View File

@ -92,8 +92,8 @@ abstract class CryptoAlgorithm implements Identifiable {
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();
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.");
}

View File

@ -74,7 +74,7 @@ class DefaultCurve implements Curve {
return ID;
}
public KeyPairBuilder keyPairBuilder() {
return new DefaultKeyPairBuilder(this.JCA_NAME).setProvider(this.PROVIDER);
public KeyPairBuilder keyPair() {
return new DefaultKeyPairBuilder(this.JCA_NAME).provider(this.PROVIDER);
}
}

View File

@ -15,16 +15,15 @@
*/
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;
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,35 +43,35 @@ import java.security.interfaces.RSAPublicKey;
import java.util.List;
@SuppressWarnings("unused") //used via reflection by io.jsonwebtoken.security.Jwks
public class DefaultProtoJwkBuilder<K extends Key, J extends Jwk<K>>
extends AbstractJwkBuilder<K, J, ProtoJwkBuilder<K, J>> implements ProtoJwkBuilder<K, J> {
public class DefaultDynamicJwkBuilder<K extends Key, J extends Jwk<K>>
extends AbstractJwkBuilder<K, J, DynamicJwkBuilder<K, J>> implements DynamicJwkBuilder<K, J> {
public DefaultProtoJwkBuilder() {
public DefaultDynamicJwkBuilder() {
super(new DefaultJwkContext<K>());
}
@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 +83,14 @@ public class DefaultProtoJwkBuilder<K extends Key, J extends Jwk<K>>
@SuppressWarnings("unchecked")
@Override
public <A extends PublicKey, B extends PrivateKey> PublicJwkBuilder<A, B, ?, ?, ?, ?> forKey(A key) {
public <A extends PublicKey, B extends PrivateKey> PublicJwkBuilder<A, B, ?, ?, ?, ?> key(A key) {
if (key instanceof RSAPublicKey) {
return (PublicJwkBuilder<A, B, ?, ?, ?, ?>) forKey((RSAPublicKey) key);
return (PublicJwkBuilder<A, B, ?, ?, ?, ?>) key((RSAPublicKey) key);
} else if (key instanceof ECPublicKey) {
return (PublicJwkBuilder<A, B, ?, ?, ?, ?>) forKey((ECPublicKey) key);
return (PublicJwkBuilder<A, B, ?, ?, ?, ?>) key((ECPublicKey) key);
} else {
try {
return forOctetKey(key);
return octetKey(key);
} catch (Exception e) {
throw unsupportedKey(key, e);
}
@ -100,15 +99,15 @@ public class DefaultProtoJwkBuilder<K extends Key, J extends Jwk<K>>
@SuppressWarnings("unchecked")
@Override
public <A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> forKey(B key) {
public <A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> key(B key) {
Assert.notNull(key, "Key cannot be null.");
if (key instanceof RSAPrivateKey) {
return (PrivateJwkBuilder<B, A, ?, ?, ?>) forKey((RSAPrivateKey) key);
return (PrivateJwkBuilder<B, A, ?, ?, ?>) key((RSAPrivateKey) key);
} else if (key instanceof ECPrivateKey) {
return (PrivateJwkBuilder<B, A, ?, ?, ?>) forKey((ECPrivateKey) key);
return (PrivateJwkBuilder<B, A, ?, ?, ?>) key((ECPrivateKey) key);
} else {
try {
return forOctetKey(key);
return octetKey(key);
} catch (Exception e) {
throw unsupportedKey(key, e);
}
@ -116,84 +115,85 @@ public class DefaultProtoJwkBuilder<K extends Key, J extends Jwk<K>>
}
@Override
public <A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> forOctetKey(A key) {
public <A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> octetKey(A key) {
return new AbstractAsymmetricJwkBuilder.DefaultOctetPublicJwkBuilder<>(newContext(key));
}
@Override
public <A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> forOctetKey(A key) {
public <A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> octetKey(A key) {
return new AbstractAsymmetricJwkBuilder.DefaultOctetPrivateJwkBuilder<>(newContext(key));
}
@SuppressWarnings("unchecked")
@Override
public RsaPublicJwkBuilder forRsaChain(X509Certificate... chain) {
public <A extends PublicKey, B extends PrivateKey> PublicJwkBuilder<A, B, ?, ?, ?, ?> chain(List<X509Certificate> chain)
throws UnsupportedKeyException {
Assert.notEmpty(chain, "chain cannot be null or empty.");
return forRsaChain(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.<A,B>key((A)key).x509CertificateChain(chain);
}
@Override
public RsaPublicJwkBuilder forRsaChain(List<X509Certificate> chain) {
public RsaPublicJwkBuilder rsaChain(List<X509Certificate> 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) {
Assert.notEmpty(chain, "chain cannot be null or empty.");
return forEcChain(Arrays.asList(chain));
}
@Override
public EcPublicJwkBuilder forEcChain(List<X509Certificate> chain) {
public EcPublicJwkBuilder ecChain(List<X509Certificate> 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 <A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> forOctetKeyPair(KeyPair pair) {
public <A extends PrivateKey, B extends PublicKey> OctetPrivateJwkBuilder<A, B> 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<A, B>) forOctetKey(priv).setPublicKey(pub);
}
@Override
public <A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> forOctetChain(X509Certificate... chain) {
Assert.notEmpty(chain, "X509Certificate chain cannot be null or empty.");
return forOctetChain(Arrays.asList(chain));
return (OctetPrivateJwkBuilder<A, B>) octetKey(priv).publicKey(pub);
}
@SuppressWarnings("unchecked") // ok because of the EdwardsCurve.assertEdwards calls
@Override
public <A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> forOctetChain(List<X509Certificate> chain) {
public <A extends PublicKey, B extends PrivateKey> OctetPublicJwkBuilder<A, B> octetChain(List<X509Certificate> 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.<A, B>forOctetKey((A) key).setX509CertificateChain(chain);
return this.<A, B>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);
}
@SuppressWarnings("unchecked")
@Override
public <A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> keyPair(KeyPair keyPair)
throws UnsupportedKeyException {
A pub = (A)KeyPairs.getKey(keyPair, PublicKey.class);
B priv = (B)KeyPairs.getKey(keyPair, PrivateKey.class);
return this.<A,B>key(priv).publicKey(pub);
}
@Override

View File

@ -59,9 +59,9 @@ public class DefaultJwkParser implements JwkParser {
JwkBuilder<?, ?, ?> builder = Jwks.builder();
if (this.provider != null) {
builder.setProvider(this.provider);
builder.provider(this.provider);
}
return builder.set(data).build();
return builder.add(data).build();
}
}

View File

@ -31,7 +31,7 @@ public class DefaultJwkParserBuilder implements JwkParserBuilder {
private Deserializer<Map<String,?>> deserializer;
@Override
public JwkParserBuilder setProvider(Provider provider) {
public JwkParserBuilder provider(Provider provider) {
this.provider = provider;
return this;
}

View File

@ -50,13 +50,13 @@ public class DefaultKeyPairBuilder implements KeyPairBuilder {
}
@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;
}

View File

@ -81,7 +81,7 @@ public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey
}
@Override
public SecretKeyBuilder keyBuilder() {
public SecretKeyBuilder key() {
return new DefaultSecretKeyBuilder(getJcaName(), getKeyBitLength());
}
@ -142,8 +142,8 @@ public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey
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.";

View File

@ -39,17 +39,17 @@ public class DefaultSecretKeyBuilder implements SecretKeyBuilder {
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;
}

View File

@ -61,7 +61,7 @@ public class ECCurve extends DefaultCurve {
}
@Override
public KeyPairBuilder keyPairBuilder() {
public KeyPairBuilder keyPair() {
return new DefaultKeyPairBuilder(KEY_PAIR_GENERATOR_JCA_NAME, toParameterSpec());
}
}

View File

@ -100,10 +100,10 @@ public class EcSignatureAlgorithm extends AbstractSignatureAlgorithm {
}
@Override
public KeyPairBuilder keyPairBuilder() {
public KeyPairBuilder keyPair() {
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

View File

@ -25,6 +25,7 @@ import io.jsonwebtoken.lang.Arrays;
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.KeyLengthSupplier;
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;
@ -98,7 +98,7 @@ class EcdhKeyAlgorithm extends CryptoAlgorithm implements KeyAlgorithm<PublicKey
//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.keyPair().provider(provider).random(random).build();
}
protected byte[] generateZ(final KeyRequest<?> request, final PublicKey pub, final PrivateKey priv) {
@ -183,7 +183,7 @@ class EcdhKeyAlgorithm extends CryptoAlgorithm implements KeyAlgorithm<PublicKey
KeyPair pair; // generated (ephemeral) key pair
final SecureRandom random = ensureSecureRandom(request);
ProtoJwkBuilder<?, ?> jwkBuilder = Jwks.builder().setRandom(random);
DynamicJwkBuilder<?, ?> jwkBuilder = Jwks.builder().random(random);
if (publicKey instanceof ECKey) {
ECKey ecPublicKey = (ECKey) publicKey;
@ -204,13 +204,13 @@ class EcdhKeyAlgorithm extends CryptoAlgorithm implements KeyAlgorithm<PublicKey
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());

View File

@ -64,8 +64,8 @@ public class EdSignatureAlgorithm extends AbstractSignatureAlgorithm {
}
@Override
public KeyPairBuilder keyPairBuilder() {
return this.preferredCurve.keyPairBuilder();
public KeyPairBuilder keyPair() {
return this.preferredCurve.keyPair();
}
@Override

View File

@ -357,8 +357,8 @@ public class EdwardsCurve extends DefaultCurve implements KeyLengthSupplier {
}
@Override
public KeyPairBuilder keyPairBuilder() {
return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).setProvider(getProvider());
public KeyPairBuilder keyPair() {
return new DefaultKeyPairBuilder(getJcaName(), KEY_PAIR_GENERATOR_BIT_LENGTH).provider(getProvider());
}
public static boolean isEdwards(Key key) {

View File

@ -51,7 +51,7 @@ final class EdwardsPublicKeyDeriver implements Function<PrivateKey, PublicKey> {
// 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.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");
}

View File

@ -66,7 +66,7 @@ public class HmacAesAeadAlgorithm extends AesAlgorithm implements AeadAlgorithm
}
@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());

View File

@ -121,7 +121,7 @@ public final class JwkConverter<T extends Jwk<?>> implements Converter<T, Object
throw new IllegalArgumentException(msg);
}
String skey = (String) key;
builder.set(skey, entry.getValue());
builder.add(skey, entry.getValue());
}
Jwk<?> jwk = builder.build();

View File

@ -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);
}

View File

@ -78,10 +78,10 @@ public class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm {
}
@Override
public KeyPairBuilder keyPairBuilder() {
public KeyPairBuilder keyPair() {
return new DefaultKeyPairBuilder("RSA", this.preferredKeyBitLength)
.setProvider(getProvider())
.setRandom(Randoms.secureRandom());
.provider(getProvider())
.random(Randoms.secureRandom());
}
@Override

View File

@ -144,8 +144,8 @@ public final class StandardKeyAlgorithms extends DelegatingRegistry<String, KeyA
for (int i = 0; points.size() < NUM_SAMPLES; i++) {
char[] password = randomChars(PASSWORD_LENGTH);
Password key = Keys.forPassword(password);
HEADER.setPbes2Count(workFactor);
Password key = Keys.password(password);
HEADER.pbes2Count(workFactor);
KeyRequest<Password> request = new DefaultKeyRequest<>(null, null, key, HEADER, ENC_ALG);
long start = System.currentTimeMillis();

View File

@ -72,25 +72,25 @@ public class X509BuilderSupport implements X509Builder<X509BuilderSupport> {
}
@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<X509Certificate> chain) {
public X509BuilderSupport x509CertificateChain(List<X509Certificate> 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 class X509BuilderSupport implements X509Builder<X509BuilderSupport> {
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);
}
}
}

View File

@ -37,13 +37,13 @@ class CustomObjectDeserializationTest {
String jwtString = Jwts.builder().claim("cust", customBean).compact()
// no custom deserialization, object is a map
Jwt<Header, Claims> jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(jwtString)
Jwt<Header, Claims> 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

View File

@ -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<Header, Claims> jwt = Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact)
Jwt<Header, Claims> 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<Header, Claims> jwt = Jwts.parser().enableUnsecuredJws().setAllowedClockSkewSeconds(10).build().parse(compact)
Jwt<Header, Claims> 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<Header, Claims> jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(compact)
Jwt<Header, Claims> 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

View File

@ -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
@ -165,8 +165,8 @@ class JwtsTest {
void testSetContentWithContentType() {
String s = 'Hello JJWT'
String cty = 'text/plain'
String compact = Jwts.builder().setContent(s.getBytes(StandardCharsets.UTF_8), cty).compact()
def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact)
String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).compact()
def jwt = Jwts.parser().enableUnsecured().build().parseContentJwt(compact)
assertEquals cty, jwt.header.getContentType()
assertEquals s, new String(jwt.payload, StandardCharsets.UTF_8)
}
@ -176,8 +176,8 @@ 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()
def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact)
String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).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)
}
@ -187,8 +187,8 @@ 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()
def jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(compact)
String compact = Jwts.builder().content(s.getBytes(StandardCharsets.UTF_8), cty).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)
}
@ -198,9 +198,9 @@ 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().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")
}
@ -290,12 +290,12 @@ 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)
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')
@ -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()
}
@ -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()
}
@ -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,12 +754,12 @@ 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()
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
@ -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
@ -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)
@ -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()
@ -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
@ -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()
@ -1354,7 +1354,7 @@ class JwtsTest {
it instanceof Pbes2HsAkwAlgorithm
})// as Collection<KeyAlgorithm<SecretKey, SecretKey>>
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()
@ -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().claims().add(claims).and().signWith(privateKey, alg).compact()
def key = publicKey
if (verifyWithPrivateKey) {
@ -1587,11 +1587,11 @@ 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])
String jwt = Jwts.builder().setClaims(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().setClaims(claims).signWith(privateKey, alg).compact()
String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact()
def key = publicKey
if (verifyWithPrivateKey) {

View File

@ -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()
}
@ -108,7 +109,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 +117,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<String, ?> m = new LinkedHashMap<>(pubJwk)
def header = h([jwk: m])
@ -138,7 +139,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 +152,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()
@ -212,7 +213,7 @@ class AbstractProtectedHeaderTest {
@Test
void testCritical() {
Set<String> crits = Collections.setOf('foo', 'bar')
def header = h([crit: crits])
def header = Jwts.header().critical(crits).build() as DefaultProtectedHeader
assertEquals crits, header.getCritical()
}

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -70,7 +70,7 @@ class DefaultJwtBuilderTest {
}
@Override
KeyPairBuilder keyPairBuilder() {
KeyPairBuilder keyPair() {
throw new IllegalStateException("should not be called during build")
}
@ -81,8 +81,8 @@ class DefaultJwtBuilderTest {
}
replay provider
def b = new DefaultJwtBuilder().setProvider(provider)
.setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg)
def b = new DefaultJwtBuilder().provider(provider)
.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")
}
@ -123,8 +123,8 @@ class DefaultJwtBuilderTest {
}
}
def b = new DefaultJwtBuilder().setSecureRandom(random)
.setSubject('me').signWith(Jwts.SIG.HS256.keyBuilder().build(), alg)
def b = new DefaultJwtBuilder().random(random)
.setSubject('me').signWith(Jwts.SIG.HS256.key().build(), alg)
assertSame random, b.secureRandom
b.compact()
assertTrue called[0]
@ -132,44 +132,53 @@ 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()
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
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.claims().add(c)
def c2 = [foo: 'bar', baz: 'buz']
b.addClaims(c2)
assertEquals 'initial', b.claimsBuilder.get('initial')
@ -203,8 +212,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.claims().add(c)
assertEquals c, builder.claimsBuilder
assertEquals builder.claimsBuilder.size(), 1
assertEquals c.size(), 1
@ -253,7 +262,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)
@ -273,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()
@ -306,7 +315,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()
@ -417,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)
@ -474,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)
@ -483,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()

View File

@ -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.add('alg', val); break // no setter
case 'compressionAlgorithm': builder.add('zip', val); break // no setter
default: builder."$propName"(val)
}
header = builder.build()
if (val instanceof byte[]) {
assertArrayEquals val, header."get$name"()
@ -192,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
}
@ -208,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()
@ -217,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()
}
@ -259,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 =======================
/**
@ -277,7 +290,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 +345,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 +358,7 @@ class DefaultJwtHeaderBuilderTest {
Request<byte[]> 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 +374,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 +387,7 @@ class DefaultJwtHeaderBuilderTest {
Request<byte[]> 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 +406,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 +422,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 +437,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 +478,7 @@ class DefaultJwtHeaderBuilderTest {
assertEquals new DefaultHeader([foo: 'bar']), builder.build()
// add JWS-required property:
builder.setAlgorithm('HS256')
builder.put(DefaultHeader.ALGORITHM.getId(), 'HS256')
assertEquals new DefaultJwsHeader([foo: 'bar', alg: 'HS256']), builder.build()
// add JWE required property:

View File

@ -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.*
@ -53,7 +55,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 +65,7 @@ class DefaultJwtParserBuilderTest {
void testKeyLocatorAndVerificationKeyConfigured() {
try {
builder
.setKeyLocator(new ConstantKeyLocator(null, null))
.keyLocator(new ConstantKeyLocator(null, null))
.verifyWith(TestKeys.HS256)
.build()
fail()
@ -77,7 +79,7 @@ class DefaultJwtParserBuilderTest {
void testKeyLocatorAndDecryptionKeyConfigured() {
try {
builder
.setKeyLocator(new ConstantKeyLocator(null, null))
.keyLocator(new ConstantKeyLocator(null, null))
.decryptWith(TestKeys.A128GCM)
.build()
fail()
@ -101,7 +103,7 @@ class DefaultJwtParserBuilderTest {
}
}
def b = builder.base64UrlDecodeWith(decoder).build()
assertSame decoder, b.base64UrlDecoder
assertSame decoder, b.decoder
}
@Test(expected = IllegalArgumentException)
@ -121,7 +123,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()
@ -161,10 +163,122 @@ class DefaultJwtParserBuilderTest {
void testAddCompressionAlgorithms() {
def codec = new TestCompressionCodec(id: 'test')
def parser = builder.addCompressionAlgorithms([codec] as Set<CompressionCodec>).build()
def header = Jwts.header().setCompressionAlgorithm(codec.getId()).build()
def header = Jwts.header().add('zip', codec.getId()).build()
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')
@ -189,7 +303,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 +313,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 +325,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()
}
@ -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 this.id
return id
}
@Override
AeadResult encrypt(AeadRequest request) throws SecurityException {
return null
}
@Override
Message<byte[]> 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 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<byte[], SecretKey> request) throws SecurityException {
return new byte[0]
}
@Override
boolean verify(VerifySecureDigestRequest<SecretKey> request) throws SecurityException {
return false
}
@Override
SecretKeyBuilder key() {
return null
}
@Override
int getKeyBitLength() {
return 0
}
}
}

View File

@ -50,7 +50,7 @@ class DefaultJwtParserTest {
@Test(expected = MalformedJwtException)
void testBase64UrlDecodeWithInvalidInput() {
newParser().base64UrlDecode('20:SLDKJF;3993;----', 'test')
newParser().decode('20:SLDKJF;3993;----', 'test')
}
@Test
@ -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()

View File

@ -29,8 +29,8 @@ class DefaultJwtTest {
@Test
void testToString() {
String compact = Jwts.builder().setHeaderParam('foo', 'bar').setAudience('jsmith').compact()
Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseClaimsJwt(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,15 +38,15 @@ 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()
Jwt jwt = Jwts.parser().enableUnsecuredJws().build().parseContentJwt(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()
}
@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()

View File

@ -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.add('alg', val); break // no setter
case 'compressionAlgorithm': header.add('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()
}

View File

@ -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
}
}

View File

@ -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().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().setAlgorithm('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) {

View File

@ -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()
}
}

View File

@ -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
}
/**

View File

@ -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<byte[]> 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<byte[]> 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<byte[]> 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<byte[]> 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:

View File

@ -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)

View File

@ -32,7 +32,7 @@ class AbstractJwkBuilderTest {
private static final SecretKey SKEY = TestKeys.A256GCM
private static AbstractJwkBuilder<SecretKey, SecretJwk, AbstractJwkBuilder> builder() {
return (AbstractJwkBuilder) Jwks.builder().forKey(SKEY)
return (AbstractJwkBuilder) Jwks.builder().key(SKEY)
}
@Test
@ -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,14 +76,14 @@ 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')
}
@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
}
@ -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
}
@ -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
}
@ -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
}
@ -117,7 +117,7 @@ class AbstractJwkBuilderTest {
def a = UUID.randomUUID().toString()
def b = UUID.randomUUID().toString()
def set = [a, b] as Set<String>
def jwk = builder().setOperations(set).build()
def jwk = builder().operations(set).build()
assertEquals set, jwk.getOperations()
assertEquals set, jwk.key_ops
}
@ -127,7 +127,7 @@ class AbstractJwkBuilderTest {
def a = UUID.randomUUID().toString()
def b = UUID.randomUUID().toString()
def set = [a, b] as Set<String>
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<String>
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
}
@ -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()
}

View File

@ -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=<redacted>')
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=<redacted>')
def rsaPrivJwk = Jwks.builder().forKey(TestKeys.RS256.pair.private).build()
def rsaPrivJwk = Jwks.builder().key(TestKeys.RS256.pair.private).build()
String s = 'd=<redacted>, p=<redacted>, q=<redacted>, dp=<redacted>, dq=<redacted>, qi=<redacted>'
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).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().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).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().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).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()

View File

@ -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<byte[], PrivateKey>(data, provider, null, pair.getPrivate()))
assertTrue Jwts.SIG.RS256.verify(new DefaultVerifySecureDigestRequest<PublicKey>(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

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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()

View File

@ -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
}
}

View File

@ -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')
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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) {
@ -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()

View File

@ -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)

Some files were not shown because too many files have changed in this diff Show More