Skip to content

Commit

Permalink
Builder NestedCollection support (#841)
Browse files Browse the repository at this point in the history
- Added Conjunctor, CollectionMutator, and NestedCollection
- Added JwkBuilder#operations() NestedCollection builder and removed #operation(KeyOperation) and #operations(Collection<KeyOperation>)
- KeyOperationPolicyBuilder now extends CollectionMutator

- Replaced ProtectedHeaderMutator#critical* methods with critical() NestedCollection

- Replaced JwtParserBuilder#critical* methods with critical() NestedCollection

- Replaced ClaimsMutator#audience* methods with audience() AudienceCollection

- Replaced JwtParserBuilder#add* methods with new collection builder methods: enc(), key(), sig() and zip()
  • Loading branch information
lhazlewood committed Sep 29, 2023
1 parent 20b2fa9 commit 854bb89
Show file tree
Hide file tree
Showing 74 changed files with 1,214 additions and 816 deletions.
84 changes: 42 additions & 42 deletions api/src/main/java/io/jsonwebtoken/ClaimsMutator.java
Expand Up @@ -15,6 +15,8 @@
*/
package io.jsonwebtoken;

import io.jsonwebtoken.lang.NestedCollection;

import java.util.Collection;
import java.util.Date;

Expand Down Expand Up @@ -77,61 +79,29 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
* claim</a> as <em>a single String, <b>NOT</b> a String array</em>. This method exists only for producing
* JWTs sent to legacy recipients that are unable to interpret the {@code aud} value as a JSON String Array; it is
* strongly recommended to avoid calling this method whenever possible and favor the
* {@link #audience(String)} or {@link #audience(Collection)} methods instead, as they ensure a single deterministic
* data type for recipients.
* {@link #audience()}.{@link AudienceCollection#add(Object) add(String)} and
* {@link AudienceCollection#add(Collection) add(Collection)} methods instead, as they ensure a single
* deterministic data type for recipients.
*
* @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 since JJWT_RELEASE_VERSION in favor of {@link #audience()}. 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> (audience)
* Claim</a> as <em>a single String, <b>NOT</b> a String array</em>. This method exists only for producing
* JWTs sent to legacy recipients that are unable to interpret the {@code aud} value as a JSON String Array; it is
* strongly recommended to avoid calling this method whenever possible and favor the
* {@link #audience(String)} or {@link #audience(Collection)} methods instead, as they ensure a single deterministic
* data type for recipients.
*
* @param aud the value to use as the {@code aud} Claim single-String value (and not an array of Strings), or
* {@code null}, empty or whitespace to remove the property from the JSON map.
* @return the instance for method chaining
* @since JJWT_RELEASE_VERSION
* @deprecated This is technically not deprecated because the JWT RFC mandates support for single string values,
* but it is marked as deprecated to discourage its use when possible.
*/
// DO NOT REMOVE EVER. This is a required RFC feature, but marked as deprecated to discourage its use
@Deprecated
T audienceSingle(String aud);

/**
* Adds (appends) the specified {@code aud} value to the {@link #audience(Collection) audience} Claim set
* (JSON Array) unless it is {@code null}, empty, whitespace-only or already exists in the set.
*
* <p>This method may be called multiple times.</p>
*
* @param aud a JWT {@code aud} value to add to the {@link #audience(Collection) audience} Claim set.
* @return the {@code Claims} instance for method chaining.
* @throws IllegalArgumentException if the {@code aud} argument is null or empty.
* @since JJWT_RELEASE_VERSION
*/
T audience(String aud);

/**
* Adds (appends) the specified values to the JWT
* Configures the JWT
* <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3"><code>aud</code></a> (audience) Claim
* set, quietly ignoring any null, empty, whitespace-only, or existing value already in the set.
*
* <p>This method may be called multiple times.</p>
*
* @param aud the values to add to the {@code aud} Claim set (JSON Array)
* @return the instance for method chaining
* @return the {@link AudienceCollection AudienceCollection} to use for {@code aud} configuration.
* @see AudienceCollection AudienceCollection
* @see AudienceCollection#single(String) AudienceCollection.single(String)
* @since JJWT_RELEASE_VERSION
*/
T audience(Collection<String> aud);
AudienceCollection<T> audience();

/**
* Sets the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4">
Expand Down Expand Up @@ -246,4 +216,34 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
* @since JJWT_RELEASE_VERSION
*/
T id(String jti);

/**
* A {@code NestedCollection} for setting {@link #audience()} values that also allows overriding the collection
* to be a {@link #single(String) single string value} for legacy JWT recipients if necessary.
*
* @param <P> the type of ClaimsMutator to return for method chaining.
* @see #single(String)
* @since JJWT_RELEASE_VERSION
*/
interface AudienceCollection<P> extends NestedCollection<String, P> {

/**
* Sets the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3"><code>aud</code> (audience)
* Claim</a> as <em>a single String, <b>NOT</b> a String array</em>. This method exists only for producing
* JWTs sent to legacy recipients that are unable to interpret the {@code aud} value as a JSON String Array;
* it is strongly recommended to avoid calling this method whenever possible and favor the
* {@link #add(Object) add(String)} or {@link #add(Collection)} methods instead, as they ensure a single
* deterministic data type for recipients.
*
* @param aud the value to use as the {@code aud} Claim single-String value (and not an array of Strings), or
* {@code null}, empty or whitespace to remove the property from the JSON map.
* @return the instance for method chaining
* @since JJWT_RELEASE_VERSION
* @deprecated This is technically not deprecated because the JWT RFC mandates support for single string values,
* but it is marked as deprecated to discourage its use when possible.
*/
// DO NOT REMOVE EVER. This is a required RFC feature, but marked as deprecated to discourage its use
@Deprecated
P single(String aud);
}
}
Expand Up @@ -15,8 +15,6 @@
*/
package io.jsonwebtoken;

import java.util.Collection;

/**
* Looks for a JWT {@code zip} header, and if found, returns the corresponding {@link CompressionCodec} the parser
* can use to decompress the JWT body.
Expand All @@ -31,9 +29,9 @@
* {@link io.jsonwebtoken.JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver) parsing} JWTs.</p>
*
* @see JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver)
* @see JwtParserBuilder#addCompressionAlgorithms(Collection)
* @see JwtParserBuilder#zip()
* @since 0.6.0
* @deprecated in favor of {@link JwtParserBuilder#addCompressionAlgorithms(Collection)}
* @deprecated in favor of {@link JwtParserBuilder#zip()}
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
Expand Down
39 changes: 7 additions & 32 deletions api/src/main/java/io/jsonwebtoken/JwtBuilder.java
Expand Up @@ -20,6 +20,7 @@
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoder;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.lang.Conjunctor;
import io.jsonwebtoken.lang.MapMutator;
import io.jsonwebtoken.security.AeadAlgorithm;
import io.jsonwebtoken.security.InvalidKeyException;
Expand Down Expand Up @@ -402,9 +403,9 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* String jwt = Jwts.builder()
*
* <b>.claims()
* .subject("Joe")
* .audience("you")
* .issuer("me")
* .subject("Joe")
* .audience().add("you").and()
* .add("customClaim", customValue)
* .add(myClaimsMap)
* // ... etc ...
Expand Down Expand Up @@ -514,20 +515,6 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
// 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) claim. 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) claim. A {@code null} value will remove the property from the Claims.
Expand Down Expand Up @@ -1052,14 +1039,8 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
*
* @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();
interface BuilderClaims extends MapMutator<String, Object, BuilderClaims>, ClaimsMutator<BuilderClaims>,
Conjunctor<JwtBuilder> {
}

/**
Expand All @@ -1069,13 +1050,7 @@ interface BuilderClaims extends MapMutator<String, Object, BuilderClaims>, Claim
*
* @since JJWT_RELEASE_VERSION
*/
interface BuilderHeader extends JweHeaderMutator<BuilderHeader>, X509Builder<BuilderHeader> {

/**
* Returns the associated JwtBuilder for continued configuration.
*
* @return the associated JwtBuilder for continued configuration.
*/
JwtBuilder and();
interface BuilderHeader extends JweHeaderMutator<BuilderHeader>, X509Builder<BuilderHeader>,
Conjunctor<JwtBuilder> {
}
}
6 changes: 6 additions & 0 deletions api/src/main/java/io/jsonwebtoken/JwtHandlerAdapter.java
Expand Up @@ -30,6 +30,12 @@
*/
public abstract class JwtHandlerAdapter<T> implements JwtHandler<T> {

/**
* Default constructor, does not initialize any internal state.
*/
public JwtHandlerAdapter() {
}

@Override
public T onContentJwt(Jwt<Header, byte[]> jwt) {
throw new UnsupportedJwtException("Unprotected content JWTs are not supported.");
Expand Down

0 comments on commit 854bb89

Please sign in to comment.