the type of elements in the collection
+ * @param the parent to return
+ * @since JJWT_RELEASE_VERSION
+ */
+public interface NestedCollection extends CollectionMutator>, Conjunctor {
+}
diff --git a/api/src/main/java/io/jsonwebtoken/lang/Strings.java b/api/src/main/java/io/jsonwebtoken/lang/Strings.java
index 0d9d78a0..442a533b 100644
--- a/api/src/main/java/io/jsonwebtoken/lang/Strings.java
+++ b/api/src/main/java/io/jsonwebtoken/lang/Strings.java
@@ -275,6 +275,12 @@ public final class Strings {
return new String(asciiBytes, StandardCharsets.US_ASCII);
}
+ /**
+ * Returns the {@link StandardCharsets#US_ASCII US_ASCII}-encoded bytes of the specified {@code CharSequence}.
+ *
+ * @param s the {@code CharSequence} to encode to {@code US_ASCII}.
+ * @return the {@link StandardCharsets#US_ASCII US_ASCII}-encoded bytes of the specified {@code CharSequence}.
+ */
public static byte[] ascii(CharSequence s) {
byte[] bytes = null;
if (s != null) {
diff --git a/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java
index ca57c5d0..84583434 100644
--- a/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/security/AsymmetricJwkBuilder.java
@@ -16,7 +16,6 @@
package io.jsonwebtoken.security;
import java.security.Key;
-import java.util.Collection;
/**
* A {@link JwkBuilder} that builds asymmetric (public or private) JWKs.
@@ -69,7 +68,7 @@ public interface AsymmetricJwkBuilder,
*
* Per
* JWK RFC 7517, Section 4.3, last paragraph,
- * the use (Public Key Use)
and {@link #operations(Collection) key_ops (Key Operations)} members
+ * the use (Public Key Use)
and {@link #operations() key_ops (Key Operations)} members
* SHOULD NOT be used together; however, if both are used, the information they convey MUST be
* consistent. Applications should specify which of these members they use, if either is to be used by the
* application.
diff --git a/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java b/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java
index b55761bd..af41efb0 100644
--- a/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/security/JwkBuilder.java
@@ -15,10 +15,11 @@
*/
package io.jsonwebtoken.security;
+import io.jsonwebtoken.lang.Conjunctor;
import io.jsonwebtoken.lang.MapMutator;
+import io.jsonwebtoken.lang.NestedCollection;
import java.security.Key;
-import java.util.Collection;
/**
* A {@link SecurityBuilder} that produces a JWK. A JWK is an immutable set of name/value pairs that represent a
@@ -104,83 +105,34 @@ public interface JwkBuilder, T extends JwkBuilde
T idFromThumbprint(HashAlgorithm alg);
/**
- * Specifies an operation for which the key may be used by adding it to the
- * JWK {@code key_ops} (Key Operations)
- * Parameter values. This method may be called multiple times.
+ * Configures the key operations for which
+ * the key is intended to be used. When finished, use the collection's {@link Conjunctor#and() and()} method to
+ * return to the JWK builder, for example:
+ *
+ * jwkBuilder.operations().add(aKeyOperation).{@link Conjunctor#and() and()} // etc...
*
- * The {@code key_ops} (key operations) parameter identifies the operation(s) for which the key is
- * intended to be used. The {@code key_ops} parameter is intended for use cases in which public,
- * private, or symmetric keys may be present.
- *
- * Security Vulnerability Notice
- *
- * Multiple unrelated key operations SHOULD NOT be specified for a key because of the potential
- * vulnerabilities associated with using the same key with multiple algorithms. Thus, the combinations
- * {@link Jwks.OP#SIGN sign} with {@link Jwks.OP#VERIFY verify},
- * {@link Jwks.OP#ENCRYPT encrypt} with {@link Jwks.OP#DECRYPT decrypt}, and
- * {@link Jwks.OP#WRAP_KEY wrapKey} with {@link Jwks.OP#UNWRAP_KEY unwrapKey} are permitted, but other combinations
- * SHOULD NOT be used. This is enforced by the builder's key operation
- * {@link #operationPolicy(KeyOperationPolicy) policy}.
+ * The {@code and()} method will throw an {@link IllegalArgumentException} if any of the specified
+ * {@code KeyOperation}s are not permitted by the JWK's
+ * {@link #operationPolicy(KeyOperationPolicy) operationPolicy}. See that documentation for more
+ * information on security vulnerabilities when using the same key with multiple algorithms.
*
* Standard {@code KeyOperation}s and Overrides
*
* All RFC-standard JWK Key Operations in the {@link Jwks.OP} registry are supported via the builder's default
- * operations {@link #operationPolicy(KeyOperationPolicy) policy}, but other (custom) values
+ * {@link #operationPolicy(KeyOperationPolicy) operationPolicy}, but other (custom) values
* MAY be specified (for example, using a {@link Jwks.OP#builder()}).
*
* If the {@code JwkBuilder} is being used to rebuild or parse an existing JWK however, any custom operations
- * should be enabled for the {@code JwkBuilder} by {@link #operationPolicy(KeyOperationPolicy) specifying}
- * an operations policy that includes the custom values (e.g. via
+ * should be enabled by configuring an {@link #operationPolicy(KeyOperationPolicy) operationPolicy}
+ * that includes the custom values (e.g. via
* {@link Jwks.OP#policy()}.{@link KeyOperationPolicyBuilder#add(KeyOperation) add(customKeyOperation)}).
*
* For best interoperability with other applications however, it is recommended to use only the {@link Jwks.OP}
* constants.
*
- * @param operation the value to add to the JWK {@code key_ops} value set
- * @return the builder for method chaining.
- * @throws IllegalArgumentException if the {@code op} is not permitted by the operations
- * {@link #operationPolicy(KeyOperationPolicy) policy}.
+ * @return the {@link NestedCollection} to use for {@code key_ops} configuration.
* @see Jwks.OP
+ * @see RFC 7517: key_ops (Key Operations) Parameter
*/
- T operation(KeyOperation operation) throws IllegalArgumentException;
-
- /**
- * Adds {@code ops} to the JWK {@code key_ops}
- * (Key Operations) Parameter values.
- *
- * The {@code key_ops} (key operations) parameter identifies the operation(s) for which the key is
- * intended to be used. The {@code key_ops} parameter is intended for use cases in which public,
- * private, or symmetric keys may be present.
- *
- * Security Vulnerability Notice
- *
- * Multiple unrelated key operations SHOULD NOT be specified for a key because of the potential
- * vulnerabilities associated with using the same key with multiple algorithms. Thus, the combinations
- * {@link Jwks.OP#SIGN sign} with {@link Jwks.OP#VERIFY verify},
- * {@link Jwks.OP#ENCRYPT encrypt} with {@link Jwks.OP#DECRYPT decrypt}, and
- * {@link Jwks.OP#WRAP_KEY wrapKey} with {@link Jwks.OP#UNWRAP_KEY unwrapKey} are permitted, but other combinations
- * SHOULD NOT be used. This is enforced by the builder's default
- * operation {@link #operationPolicy(KeyOperationPolicy) policy}.
- *
- * Standard {@code KeyOperation}s and Overrides
- *
- * All RFC-standard JWK Key Operations in the {@link Jwks.OP} registry are supported via the builder's default
- * operations {@link #operationPolicy(KeyOperationPolicy) policy}, but other (custom) values
- * MAY be specified (for example, using a {@link Jwks.OP#builder()}).
- *
- * If the {@code JwkBuilder} is being used to rebuild or parse an existing JWK however, any custom operations
- * should be enabled for the {@code JwkBuilder} by {@link #operationPolicy(KeyOperationPolicy) specifying}
- * an operations policy that includes the custom values (e.g. via
- * {@link Jwks.OP#policy()}.{@link KeyOperationPolicyBuilder#add(KeyOperation) add(customKeyOperation)}).
- *
- * For best interoperability with other applications however, it is recommended to use only the {@link Jwks.OP}
- * constants.
- *
- * @param ops the {@code KeyOperation} values to add to the JWK {@code key_ops} value set
- * @return the builder for method chaining.
- * @throws IllegalArgumentException if any of the operations are not permitted by the operations
- * {@link #operationPolicy(KeyOperationPolicy) policy}.
- * @see Jwks.OP
- */
- T operations(Collection ops) throws IllegalArgumentException;
+ NestedCollection operations();
}
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyOperationBuilder.java b/api/src/main/java/io/jsonwebtoken/security/KeyOperationBuilder.java
index ccfaec38..cb24e45b 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyOperationBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyOperationBuilder.java
@@ -17,11 +17,9 @@ package io.jsonwebtoken.security;
import io.jsonwebtoken.lang.Builder;
-import java.util.Collection;
-
/**
* A {@code KeyOperationBuilder} produces {@link KeyOperation} instances that may be added to a JWK's
- * {@link JwkBuilder#operations(Collection) key operations} parameter. This is primarily only useful for creating
+ * {@link JwkBuilder#operations() key operations} parameter. This is primarily only useful for creating
* custom (non-standard) {@code KeyOperation}s for use with a custom {@link KeyOperationPolicy}, as all standard ones
* are available already via the {@link Jwks.OP} registry singleton.
*
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java
index a386fbfd..49e89387 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java
@@ -33,8 +33,10 @@ public interface KeyOperationPolicied> {
*
* Multiple unrelated key operations SHOULD NOT be specified for a key
* because of the potential vulnerabilities associated with using the
- * same key with multiple algorithms.
- *
+ * same key with multiple algorithms. Thus, the combinations "{@link Jwks.OP#SIGN sign}"
+ * with "{@link Jwks.OP#VERIFY verify}", "{@link Jwks.OP#ENCRYPT encrypt}" with "{@link Jwks.OP#DECRYPT decrypt}", and "{@link Jwks.OP#WRAP_KEY wrapKey}" with
+ * "{@link Jwks.OP#UNWRAP_KEY unwrapKey}" are permitted, but other combinations SHOULD NOT be used.
+ *
*
*
* If you wish to enable a different policy, perhaps to support additional custom {@code KeyOperation} values,
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java
index d94536f1..b36aaa31 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java
@@ -20,8 +20,8 @@ import java.util.Collection;
/**
* A key operation policy determines which {@link KeyOperation}s may be assigned to a JWK.
*
- * @since JJWT_RELEASE_VERSION
* @see JwkBuilder#operationPolicy(KeyOperationPolicy)
+ * @since JJWT_RELEASE_VERSION
*/
public interface KeyOperationPolicy {
@@ -39,5 +39,5 @@ public interface KeyOperationPolicy {
* @param ops the operations to validate
*/
@SuppressWarnings("GrazieInspection")
- void validate(Collection ops) throws IllegalArgumentException;
+ void validate(Collection extends KeyOperation> ops) throws IllegalArgumentException;
}
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicyBuilder.java b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicyBuilder.java
index dcd39729..3873cc2f 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicyBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicyBuilder.java
@@ -17,6 +17,7 @@ package io.jsonwebtoken.security;
import io.jsonwebtoken.Identifiable;
import io.jsonwebtoken.lang.Builder;
+import io.jsonwebtoken.lang.CollectionMutator;
import java.util.Collection;
@@ -32,7 +33,8 @@ import java.util.Collection;
* @see Jwks.OP#builder()
* @since JJWT_RELEASE_VERSION
*/
-public interface KeyOperationPolicyBuilder extends Builder {
+public interface KeyOperationPolicyBuilder extends CollectionMutator,
+ Builder {
/**
* Allows a JWK to have unrelated {@link KeyOperation}s in its {@code key_ops} parameter values. Be careful
@@ -72,8 +74,10 @@ public interface KeyOperationPolicyBuilder extends Builder {
* @see Jwks.OP
* @see Jwks.OP#builder()
* @see JwkBuilder#operationPolicy(KeyOperationPolicy)
- * @see JwkBuilder#operations(Collection)
+ * @see JwkBuilder#operations()
*/
+ @Override
+ // for better JavaDoc
KeyOperationPolicyBuilder add(KeyOperation op);
/**
@@ -101,8 +105,10 @@ public interface KeyOperationPolicyBuilder extends Builder {
* @see Jwks.OP
* @see Jwks.OP#builder()
* @see JwkBuilder#operationPolicy(KeyOperationPolicy)
- * @see JwkBuilder#operations(Collection)
+ * @see JwkBuilder#operations()
*/
- KeyOperationPolicyBuilder add(Collection ops);
+ @Override
+ // for better JavaDoc
+ KeyOperationPolicyBuilder add(Collection extends KeyOperation> ops);
}
diff --git a/api/src/main/java/io/jsonwebtoken/security/SecureRequest.java b/api/src/main/java/io/jsonwebtoken/security/SecureRequest.java
index cd0cd764..25749db7 100644
--- a/api/src/main/java/io/jsonwebtoken/security/SecureRequest.java
+++ b/api/src/main/java/io/jsonwebtoken/security/SecureRequest.java
@@ -20,6 +20,7 @@ import java.security.Key;
/**
* A request to a cryptographic algorithm requiring a {@link Key}.
*
+ * @param the type of payload in the request
* @param they type of key used by the algorithm during the request
* @since JJWT_RELEASE_VERSION
*/
diff --git a/api/src/main/java/io/jsonwebtoken/security/SecurityBuilder.java b/api/src/main/java/io/jsonwebtoken/security/SecurityBuilder.java
index d0333a87..40e216b8 100644
--- a/api/src/main/java/io/jsonwebtoken/security/SecurityBuilder.java
+++ b/api/src/main/java/io/jsonwebtoken/security/SecurityBuilder.java
@@ -25,6 +25,7 @@ import java.security.SecureRandom;
* during instance creation, such as a {@link java.security.Provider} or {@link java.security.SecureRandom}.
*
* @param The type of object that will be created each time {@link #build()} is invoked.
+ * @param the type of SecurityBuilder returned for method chaining
* @see #provider(Provider)
* @see #random(SecureRandom)
* @since JJWT_RELEASE_VERSION
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/AbstractAudienceCollection.java b/impl/src/main/java/io/jsonwebtoken/impl/AbstractAudienceCollection.java
new file mode 100644
index 00000000..d2a17edd
--- /dev/null
+++ b/impl/src/main/java/io/jsonwebtoken/impl/AbstractAudienceCollection.java
@@ -0,0 +1,34 @@
+/*
+ * 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.DefaultNestedCollection;
+
+import java.util.Collection;
+
+/**
+ * Abstract NestedCollection that requires the AudienceCollection interface to be implemented.
+ *
+ * @param type of parent to return
+ * @since JJWT_RELEASE_VERSION
+ */
+abstract class AbstractAudienceCollection
extends DefaultNestedCollection
+ implements ClaimsMutator.AudienceCollection {
+ protected AbstractAudienceCollection(P parent, Collection extends String> seed) {
+ super(parent, seed);
+ }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java
index 50cb36c3..93db6612 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJweHeaderMutator.java
@@ -16,19 +16,18 @@
package io.jsonwebtoken.impl;
import io.jsonwebtoken.JweHeaderMutator;
+import io.jsonwebtoken.impl.lang.DefaultNestedCollection;
import io.jsonwebtoken.impl.lang.DelegatingMapMutator;
import io.jsonwebtoken.impl.lang.Parameter;
import io.jsonwebtoken.impl.security.X509BuilderSupport;
import io.jsonwebtoken.lang.Collections;
+import io.jsonwebtoken.lang.NestedCollection;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.PublicJwk;
import java.net.URI;
import java.security.cert.X509Certificate;
-import java.util.Collection;
-import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Set;
/**
* @param return type for method chaining
@@ -105,29 +104,14 @@ public class DefaultJweHeaderMutator>
// =============================================================
@Override
- public T critical(String crit) {
- crit = Strings.clean(crit);
- if (Strings.hasText(crit)) {
- critical(Collections.setOf(crit));
- }
- return self();
- }
-
- @Override
- public T critical(Collection crit) {
- if (!Collections.isEmpty(crit)) {
- Set existing = Collections.nullSafe(this.DELEGATE.get(DefaultProtectedHeader.CRIT));
- Set set = new LinkedHashSet<>(existing.size() + crit.size());
- set.addAll(existing);
- for (String s : crit) {
- s = Strings.clean(s);
- if (s != null) {
- set.add(s);
- }
+ public NestedCollection critical() {
+ return new DefaultNestedCollection(self(), this.DELEGATE.get(DefaultProtectedHeader.CRIT)) {
+ @Override
+ public T and() {
+ put(DefaultProtectedHeader.CRIT, Collections.asSet(getCollection()));
+ return super.and();
}
- put(DefaultProtectedHeader.CRIT, set);
- }
- return self();
+ };
}
@Override
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
index 4865c714..ce9cb2c6 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
@@ -74,7 +74,6 @@ import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
-import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -435,19 +434,8 @@ public class DefaultJwtBuilder implements JwtBuilder {
}
@Override
- public JwtBuilder audienceSingle(String aud) {
- //noinspection deprecation
- return claims().audienceSingle(aud).and();
- }
-
- @Override
- public JwtBuilder audience(String aud) {
- return claims().audience(aud).and();
- }
-
- @Override
- public JwtBuilder audience(Collection aud) {
- return claims().audience(aud).and();
+ public AudienceCollection audience() {
+ return new DelegateAudienceCollection<>((JwtBuilder) this, claims().audience());
}
@Override
@@ -586,7 +574,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
this.headerBuilder.add(DefaultHeader.ALGORITHM.getId(), sigAlg.getId());
if (!this.encodePayload) { // b64 extension:
String id = DefaultJwsHeader.B64.getId();
- this.headerBuilder.critical(id).add(id, false);
+ this.headerBuilder.critical().add(id).and().add(id, false);
}
final JwsHeader header = Assert.isInstanceOf(JwsHeader.class, this.headerBuilder.build());
encodeAndWrite("JWS Protected Header", header, jws);
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
index bd5df7e9..749322b6 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
@@ -59,6 +59,7 @@ import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.DateFormats;
import io.jsonwebtoken.lang.Objects;
+import io.jsonwebtoken.lang.Registry;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.AeadAlgorithm;
import io.jsonwebtoken.security.DecryptAeadRequest;
@@ -188,13 +189,13 @@ public class DefaultJwtParser implements JwtParser {
private final boolean unsecuredDecompression;
- private final Function> sigAlgFn;
+ private final Function> sigAlgs;
- private final Function encAlgFn;
+ private final Function encAlgs;
- private final Function> keyAlgFn;
+ private final Function> keyAlgs;
- private final Function zipAlgFn;
+ private final Function zipAlgs;
private final Locator extends Key> keyLocator;
@@ -224,10 +225,10 @@ public class DefaultJwtParser implements JwtParser {
Decoder base64UrlDecoder,
Deserializer