mirror of https://github.com/jwtk/jjwt.git
Immutables (#790)
* Jwts#header() and JwtBuilder#header() API cleanup * added license headers, removed unused Conjunctor interface concept * impl checkpoint for Registry-to-Map implementation change * Jwts.SIG and Jwts.ENC conversion checkpoint (complete) * Jwts.KEY and Jwks.HASH conversion checkpoint (complete) * File header and Javadoc cleanup. Removed unused SignatureRequest.java concept. * Changed deprecated API usage in test case * - Removed *Accessor concepts where possible, just using the *Header interfaces was sufficient - KeyAlgorithm#getEncryptionKey now accepts a JweHeader that is mutable. Implementations can just use Map#put to modify the header state if desired. * MapMutator method renaming to avoid odd conventions * introduced ProtectedJwt concept and intermediate DefaultProtectedJwt implementation * Removed all usages of CompressionCodecs.java in favor of a new Jwts.ZIP entry. Renamed all Standard***AlgorithmsBridge to Standard***Algorithms * CompressionCodec to CompressionAlgorithm transition (complete, code coverage 100%)
This commit is contained in:
parent
992d75d0b4
commit
529f04dd90
76
CHANGELOG.md
76
CHANGELOG.md
|
@ -6,6 +6,12 @@ This is a big release! JJWT now fully supports Encrypted JSON Web Tokens (JWE) a
|
|||
sections below enumerating all new features as well as important notes on breaking changes or backwards-incompatible
|
||||
changes made in preparation for the upcoming 1.0 release.
|
||||
|
||||
**Because breaking changes are being introduced, it is strongly recommended to wait until the upcoming 1.0 release
|
||||
where you can address breaking changes one time only**.
|
||||
|
||||
Those that need immediate JWE encryption and JWK key support
|
||||
however will likely want to upgrade now and deal with the smaller subset of breaking changes in the 1.0 release.
|
||||
|
||||
#### Simplified Starter Jar
|
||||
|
||||
Those upgrading to new modular JJWT versions from old single-jar versions will transparently obtain everything
|
||||
|
@ -76,11 +82,11 @@ custom code previously written to extend JJWT to use keys from those KeyStores o
|
|||
|
||||
The `io.jsonwebtoken.SignatureAlgorithm` enum has been deprecated in favor of new
|
||||
`io.jsonwebtoken.security.SecureDigestAlgorithm`, `io.jsonwebtoken.security.MacAlgorithm`, and
|
||||
`io.jsonwebtoken.security.SignatureAlgorithm` interfaces to allow custom algorithm implementations. The new
|
||||
`SIG` constant in the `Jwts` helper class is a registry of all standard JWS algorithms as expected, exactly like the
|
||||
`io.jsonwebtoken.security.SignatureAlgorithm` interfaces to allow custom algorithm implementations. The new nested
|
||||
`Jwts.SIG` static inner class is a registry of all standard JWS algorithms as expected, exactly like the
|
||||
old enum. This change was made because enums are a static concept by design and cannot
|
||||
support custom values: those who wanted to use custom signature algorithms could not do so until now. The new
|
||||
interface now allows anyone to plug in and support custom algorithms with JJWT as desired.
|
||||
interfaces now allow anyone to plug in and support custom algorithms with JJWT as desired.
|
||||
|
||||
#### KeyBuilder and KeyPairBuilder
|
||||
|
||||
|
@ -101,37 +107,31 @@ the old enum-based static utility methods did not.
|
|||
|
||||
Now that the JWE and JWK specifications are implemented, only a few things remain for JJWT to be considered at
|
||||
version 1.0. We have been waiting to apply the 1.0 release version number until the entire set of JWT specifications
|
||||
are fully supported and we drop JDK 7 support (to allow users to use JDK 8 APIs). To that end, we have had to
|
||||
deprecate some concepts, or in some rare cases, completely break backwards compatibility to ensure the transition to
|
||||
1.0 (and JDK 8 APIs) are possible. Any backwards-incompatible changes are listed in the next section below.
|
||||
are fully supported **and** we drop JDK 7 support (to allow users to use JDK 8 APIs). To that end, we have had to
|
||||
deprecate some concepts, or in some cases, completely break backwards compatibility to ensure the transition to
|
||||
1.0 (and JDK 8 APIs) are possible. Most backwards-incompatible changes are listed in the next section below.
|
||||
|
||||
#### Backwards Compatibility Breaking Changes, Warnings and Deprecations
|
||||
|
||||
* `io.jsonwebtoken.Jwts`'s `header(Map)`, `jwsHeader()` and `jwsHeader(Map)` methods have been deprecated in favor
|
||||
of the new `header()` builder-based method to support method chaining and dynamic Header type creation.
|
||||
|
||||
|
||||
* `io.jsonwebtoken.Jwt`'s `getBody()` method has been deprecated in favor of a new `getPayload()` method to
|
||||
reflect correct JWT specification nomenclature/taxonomy.
|
||||
|
||||
|
||||
* `io.jsonwebtoken.Jws`'s `getSignature()` method has been deprecated in favor of a new `getDigest()` method to
|
||||
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.Header` has been changed to accept a type-parameter for sub-type method return values, i.e.
|
||||
`io.jsonwebtoken.Header<T extends Header>` and a new `io.jsonwebtoken.UnprotectedHeader` interface has been
|
||||
introduced to represent the concrete type of header without integrity protection. This new `UnprotectedHeader` is
|
||||
to be used where the previous generic `Header` (non-`JweHeader` and non-`JwsHeader`) interface was used.
|
||||
|
||||
|
||||
* Accordingly, the `Jwts.header()` and `Jwts.header(Map<String,?>)` now return instances of `UnprotectedHeader` instead
|
||||
of just `Header`.
|
||||
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* `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.
|
||||
|
||||
|
||||
* **JWTs that do not contain JSON Claims now have a payload type of `byte[]` instead of `String`** (that is,
|
||||
`Jwt<byte[]>` instead of `Jwt<String>`). This is because JWTs, especially when used with the
|
||||
`cty` (Content Type) header, are capable of handling _any_ type of payload, not just Strings. The previous JJWT
|
||||
|
@ -151,7 +151,7 @@ deprecate some concepts, or in some rare cases, completely break backwards compa
|
|||
|
||||
* The `JwtParser`'s `Jwt<Header, String> parsePlaintextJwt(String plaintextJwt)` and
|
||||
`Jws<String> parsePlaintextJws(String plaintextJws)` methods have been changed to
|
||||
`Jwt<UnprotectedHeader, byte[]> parseContentJwt(String plaintextJwt)` and
|
||||
`Jwt<Header, byte[]> parseContentJwt(String plaintextJwt)` and
|
||||
`Jws<byte[]> parseContentJws(String plaintextJws)` respectively.
|
||||
|
||||
* `JwtHandler`'s `onPlaintextJwt(String)` and `onPlaintextJws(String)` methods have been changed to
|
||||
|
@ -165,25 +165,28 @@ deprecate some concepts, or in some rare cases, completely break backwards compa
|
|||
* `io.jsonwebtoken.SigningKeyResolver`'s `resolveSigningKey(JwsHeader, String)` method has been changed to
|
||||
`resolveSigningKey(JwsHeader, byte[])`.
|
||||
|
||||
* `io.jsonwebtoken.Jwts`'s `parser()` method deprecated 4 years ago has been renamed to `legacyParser()` to
|
||||
allow an updated `parser()` method to return a `JwtParserBuilder` instead of a direct `JwtParser` instance.
|
||||
This `legacyParser()` method will be removed entirely for the 1.0 release - please change your code to use the
|
||||
updated `parser()` method that returns a builder as soon as possible.
|
||||
|
||||
* `io.jsonwebtoken.Jwts`'s `header()` method has been renamed to `unprotectedHeader()` to allow a newer/updated
|
||||
`header()` method to return a `DynamicHeaderBuilder` instead of a direct `Header` instance. This new method /
|
||||
return value is the recommended approach for building headers, as it will dynamically create an `UnprotectedHeader`,
|
||||
`JwsHeader` or `JweHeader` automatically based on builder state.
|
||||
* **`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.
|
||||
|
||||
* `io.jsonwebtoken.Jwts`'s `headerBuilder()` method has been renamed to `header()` and returns a
|
||||
`DynamicHeaderBuilder` instead of a direct `Header` instance. This builder method is the recommended approach
|
||||
for building headers in the future, as it will dynamically create an `UnprotectedHeader`, `JwsHeader` or `JweHeader`
|
||||
|
||||
* 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.Jwts`'s `header()` method now returns a `DynamicHeaderBuilder` instead of a
|
||||
direct `Header` instance. This new method / return value is the recommended approach for building headers
|
||||
in the future, as it will dynamically create an `UnprotectedHeader`, `JwsHeader` or `JweHeader` automatically
|
||||
based on builder state.
|
||||
|
||||
* `io.jsonwebtoken.Jwts`'s `parser()` method deprecated 4 years ago has been changed to now return a
|
||||
`JwtParserBuilder` instead of a direct `JwtParser` instance.
|
||||
|
||||
|
||||
* `io.jsonwebtoken.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.
|
||||
|
||||
|
||||
* Prior to this release, if there was a serialization problem when serializing the JWT Header, an `IllegalStateException`
|
||||
was thrown. If there was a problem when serializing the JWT claims, an `IllegalArgumentException` was
|
||||
|
@ -207,6 +210,7 @@ deprecate some concepts, or in some rare cases, completely break backwards compa
|
|||
This is to ensure JWKs have `toString()` and application log safety (do not print secure material), but still
|
||||
serialize to JSON correctly.
|
||||
|
||||
|
||||
* `io.jsonwebtoken.InvalidClaimException` and it's two subclasses (`IncorrectClaimException` and `MissingClaimException`)
|
||||
were previously mutable, allowing the corresponding claim name and claim value to be set on the exception after
|
||||
creation. These should have always been immutable without those setters (just getters), and this was a previous
|
||||
|
|
|
@ -1426,7 +1426,7 @@ key algorithms:
|
|||
|
||||
<sup><b>2</b>. Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
|
||||
|
||||
These are all represented as constants in the `io.jsonwebtoken.Jwts.SIG` registry singleton.
|
||||
These are all represented as constants in the `io.jsonwebtoken.Jwts.SIG` convenience class.
|
||||
|
||||
<a name="jws-key"></a>
|
||||
### Signature Algorithms Keys
|
||||
|
@ -3362,7 +3362,7 @@ AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc.
|
|||
// Create the compact JWE:
|
||||
String jwe = Jwts.builder().setIssuer("me")
|
||||
// Optional work factor is specified in the header:
|
||||
//.setHeader(Jwts.headerBuilder().setPbes2Count(pbkdf2Iterations))
|
||||
//.header().setPbes2Count(pbkdf2Iterations)).and()
|
||||
.encryptWith(password, alg, enc)
|
||||
.compact();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public abstract class ClaimJwtException extends JwtException {
|
|||
/**
|
||||
* The header associated with the Claims that failed validation.
|
||||
*/
|
||||
private final Header<?> header;
|
||||
private final Header header;
|
||||
|
||||
/**
|
||||
* The Claims that failed validation.
|
||||
|
@ -57,7 +57,7 @@ public abstract class ClaimJwtException extends JwtException {
|
|||
* @param claims the claims obtained
|
||||
* @param message the exception message
|
||||
*/
|
||||
protected ClaimJwtException(Header<?> header, Claims claims, String message) {
|
||||
protected ClaimJwtException(Header header, Claims claims, String message) {
|
||||
super(message);
|
||||
this.header = header;
|
||||
this.claims = claims;
|
||||
|
@ -72,7 +72,7 @@ public abstract class ClaimJwtException extends JwtException {
|
|||
* @param message the exception message
|
||||
* @param cause the exception that caused this ClaimJwtException to be thrown.
|
||||
*/
|
||||
protected ClaimJwtException(Header<?> header, Claims claims, String message, Throwable cause) {
|
||||
protected ClaimJwtException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.header = header;
|
||||
this.claims = claims;
|
||||
|
@ -92,7 +92,7 @@ public abstract class ClaimJwtException extends JwtException {
|
|||
*
|
||||
* @return the header associated with the {@link #getClaims() claims} that failed validation.
|
||||
*/
|
||||
public Header<?> getHeader() {
|
||||
public Header getHeader() {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,25 +19,24 @@ import java.util.Date;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4">Claims set</a>.
|
||||
* A JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4">Claims set</a>.
|
||||
*
|
||||
* <p>This is ultimately a JSON map and any values can be added to it, but JWT standard names are provided as
|
||||
* type-safe getters and setters for convenience.</p>
|
||||
* <p>This is an immutable JSON map with convenient type-safe getters for JWT standard claim names.</p>
|
||||
*
|
||||
* <p>Because this interface extends <code>Map<String, Object></code>, if you would like to add your own properties,
|
||||
* you simply use map methods, for example:</p>
|
||||
* <p>Additionally, this interface also extends <code>Map<String, Object></code>, so you can use standard
|
||||
* {@code Map} accessor/iterator methods as desired, for example:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* claims.{@link Map#put(Object, Object) put}("someKey", "someValue");</pre></blockquote>
|
||||
* claims.get("someKey");</pre></blockquote>
|
||||
*
|
||||
* <h2>Creation</h2>
|
||||
*
|
||||
* <p>It is easiest to create a {@code Claims} instance by calling one of the
|
||||
* {@link Jwts#claims() JWTs.claims()} factory methods.</p>
|
||||
* <p>However, because {@code Claims} instances are immutable, calling any of the map mutation methods
|
||||
* (such as {@code Map.}{@link Map#put(Object, Object) put}, etc) will result in a runtime exception. The
|
||||
* {@code Map} interface is implemented specifically for the convenience of working with existing Map-based utilities
|
||||
* and APIs.</p>
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
||||
public interface Claims extends Map<String, Object>, Identifiable {
|
||||
|
||||
/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */
|
||||
String ISSUER = "iss";
|
||||
|
@ -61,7 +60,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
String ID = "jti";
|
||||
|
||||
/**
|
||||
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
|
||||
* Returns the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.1">
|
||||
* <code>iss</code></a> (issuer) value or {@code null} if not present.
|
||||
*
|
||||
* @return the JWT {@code iss} value or {@code null} if not present.
|
||||
|
@ -69,13 +68,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
String getIssuer();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setIssuer(String iss);
|
||||
|
||||
/**
|
||||
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
|
||||
* Returns the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2">
|
||||
* <code>sub</code></a> (subject) value or {@code null} if not present.
|
||||
*
|
||||
* @return the JWT {@code sub} value or {@code null} if not present.
|
||||
|
@ -83,13 +76,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
String getSubject();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setSubject(String sub);
|
||||
|
||||
/**
|
||||
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
|
||||
* Returns the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3">
|
||||
* <code>aud</code></a> (audience) value or {@code null} if not present.
|
||||
*
|
||||
* @return the JWT {@code aud} value or {@code null} if not present.
|
||||
|
@ -97,13 +84,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
String getAudience();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setAudience(String aud);
|
||||
|
||||
/**
|
||||
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
|
||||
* Returns the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4">
|
||||
* <code>exp</code></a> (expiration) timestamp or {@code null} if not present.
|
||||
*
|
||||
* <p>A JWT obtained after this timestamp should not be used.</p>
|
||||
|
@ -113,13 +94,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
Date getExpiration();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setExpiration(Date exp);
|
||||
|
||||
/**
|
||||
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
|
||||
* Returns the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5">
|
||||
* <code>nbf</code></a> (not before) timestamp or {@code null} if not present.
|
||||
*
|
||||
* <p>A JWT obtained before this timestamp should not be used.</p>
|
||||
|
@ -129,13 +104,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
Date getNotBefore();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setNotBefore(Date nbf);
|
||||
|
||||
/**
|
||||
* Returns the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
|
||||
* Returns the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.6">
|
||||
* <code>iat</code></a> (issued at) timestamp or {@code null} if not present.
|
||||
*
|
||||
* <p>If present, this value is the timestamp when the JWT was created.</p>
|
||||
|
@ -145,13 +114,7 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
Date getIssuedAt();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setIssuedAt(Date iat);
|
||||
|
||||
/**
|
||||
* Returns the JWTs <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
|
||||
* Returns the JWTs <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7">
|
||||
* <code>jti</code></a> (JWT ID) value or {@code null} if not present.
|
||||
*
|
||||
* <p>This value is a CaSe-SenSiTiVe unique identifier for the JWT. If available, this value is expected to be
|
||||
|
@ -161,14 +124,9 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
|||
*
|
||||
* @return the JWT {@code jti} value or {@code null} if not present.
|
||||
*/
|
||||
@Override // just for JavaDoc specific to the JWT spec
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override //only for better/targeted JavaDoc
|
||||
Claims setId(String jti);
|
||||
|
||||
/**
|
||||
* Returns the JWTs claim ({@code claimName}) value as a type {@code requiredType}, or {@code null} if not present.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
* 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.
|
||||
|
@ -15,11 +15,15 @@
|
|||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.lang.Builder;
|
||||
import io.jsonwebtoken.lang.MapMutator;
|
||||
|
||||
/**
|
||||
* A JWT {@link Header} that is not integrity protected via either digital signature or encryption. It will
|
||||
* always have an {@link #getAlgorithm() algorithm} of {@code none}.
|
||||
* {@link Builder} used to create an immutable {@link Claims} instance.
|
||||
*
|
||||
* @see JwtBuilder
|
||||
* @see Claims
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface UnprotectedHeader extends Header<UnprotectedHeader> {
|
||||
public interface ClaimsBuilder extends MapMutator<String, Object, ClaimsBuilder>, ClaimsMutator<ClaimsBuilder>, Builder<Claims> {
|
||||
}
|
|
@ -28,7 +28,7 @@ import java.util.Date;
|
|||
public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
|
||||
* 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.
|
||||
|
@ -37,7 +37,7 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
|||
T setIssuer(String iss);
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
|
||||
* 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.
|
||||
|
@ -46,7 +46,7 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
|||
T setSubject(String sub);
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
|
||||
* 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.
|
||||
|
@ -55,7 +55,7 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
|||
T setAudience(String aud);
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
|
||||
* 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>
|
||||
|
@ -66,7 +66,7 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
|||
T setExpiration(Date exp);
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
|
||||
* 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>
|
||||
|
@ -77,7 +77,7 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
|||
T setNotBefore(Date nbf);
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
|
||||
* 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>
|
||||
|
@ -88,7 +88,7 @@ public interface ClaimsMutator<T extends ClaimsMutator<T>> {
|
|||
T setIssuedAt(Date iat);
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
|
||||
* 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
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
|
||||
/**
|
||||
* Compresses and decompresses byte arrays according to a compression algorithm.
|
||||
*
|
||||
|
@ -24,11 +26,13 @@ package io.jsonwebtoken;
|
|||
* {@link Identifiable#getId() getId()} will be used as the JWT
|
||||
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a> header value.</p>
|
||||
*
|
||||
* @see CompressionCodecs#DEFLATE
|
||||
* @see CompressionCodecs#GZIP
|
||||
* @see Jwts.ZIP#DEF
|
||||
* @see Jwts.ZIP#GZIP
|
||||
* @since 0.6.0
|
||||
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link io.jsonwebtoken.io.CompressionAlgorithm} to equal the RFC name for this concept.
|
||||
*/
|
||||
public interface CompressionCodec extends Identifiable {
|
||||
@Deprecated
|
||||
public interface CompressionCodec extends CompressionAlgorithm {
|
||||
|
||||
/**
|
||||
* The algorithm name to use as the JWT
|
||||
|
@ -36,29 +40,10 @@ public interface CompressionCodec extends Identifiable {
|
|||
*
|
||||
* @return the algorithm name to use as the JWT
|
||||
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a> header value.
|
||||
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link Identifiable#getId()} to ensure congruence with
|
||||
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getId()} to ensure congruence with
|
||||
* all other identifiable algorithms.
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
String getAlgorithmName();
|
||||
|
||||
/**
|
||||
* Compresses the specified byte array, returning the compressed byte array result.
|
||||
*
|
||||
* @param content bytes to compress
|
||||
* @return compressed bytes
|
||||
* @throws CompressionException if the specified byte array cannot be compressed.
|
||||
*/
|
||||
byte[] compress(byte[] content) throws CompressionException;
|
||||
|
||||
/**
|
||||
* Decompresses the specified compressed byte array, returning the decompressed byte array result. The
|
||||
* specified byte array must already be in compressed form.
|
||||
*
|
||||
* @param compressed compressed bytes
|
||||
* @return decompressed bytes
|
||||
* @throws CompressionException if the specified byte array cannot be decompressed.
|
||||
*/
|
||||
byte[] decompress(byte[] compressed) throws CompressionException;
|
||||
}
|
|
@ -15,23 +15,25 @@
|
|||
*/
|
||||
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.
|
||||
*
|
||||
* <p>JJWT's default {@link JwtParser} implementation supports both the
|
||||
* {@link CompressionCodecs#DEFLATE DEFLATE}
|
||||
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
|
||||
* {@link Jwts.ZIP#DEF DEFLATE} and {@link Jwts.ZIP#GZIP GZIP} algorithms by default - you do not need to
|
||||
* specify a {@code CompressionCodecResolver} in these cases.</p>
|
||||
*
|
||||
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement
|
||||
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you can implement
|
||||
* your own {@link CompressionCodecResolver} and specify that when
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} and
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(io.jsonwebtoken.io.CompressionAlgorithm) building} and
|
||||
* {@link io.jsonwebtoken.JwtParser#setCompressionCodecResolver(CompressionCodecResolver) parsing} JWTs.</p>
|
||||
*
|
||||
* @see JwtParserBuilder#setCompressionCodecResolver(CompressionCodecResolver)
|
||||
* @see JwtParserBuilder#addCompressionAlgorithms(Collection)
|
||||
* @since 0.6.0
|
||||
* @deprecated in favor of {@link Locator}
|
||||
* @see JwtParserBuilder#setCompressionCodecLocator(Locator)
|
||||
* @deprecated in favor of {@link JwtParserBuilder#addCompressionAlgorithms(Collection)}
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
|
@ -45,6 +47,6 @@ public interface CompressionCodecResolver {
|
|||
* @return CompressionCodec matching the {@code zip} header, or null if there is no {@code zip} header.
|
||||
* @throws CompressionException if a {@code zip} header value is found and not supported.
|
||||
*/
|
||||
CompressionCodec resolveCompressionCodec(Header<?> header) throws CompressionException;
|
||||
CompressionCodec resolveCompressionCodec(Header header) throws CompressionException;
|
||||
|
||||
}
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
|
||||
/**
|
||||
* Provides default implementations of the {@link CompressionCodec} interface.
|
||||
*
|
||||
* @see #DEFLATE
|
||||
* @see #GZIP
|
||||
* @see Jwts.ZIP#DEF
|
||||
* @see Jwts.ZIP#GZIP
|
||||
* @since 0.7.0
|
||||
* @deprecated in favor of {@link Jwts.ZIP}.
|
||||
*/
|
||||
@Deprecated //TODO: delete for 1.0
|
||||
public final class CompressionCodecs {
|
||||
|
||||
private CompressionCodecs() {
|
||||
|
@ -32,9 +32,11 @@ public final class CompressionCodecs {
|
|||
/**
|
||||
* Codec implementing the <a href="https://tools.ietf.org/html/rfc7518">JWA</a> standard
|
||||
* <a href="https://en.wikipedia.org/wiki/DEFLATE">deflate</a> compression algorithm
|
||||
*
|
||||
* @deprecated in favor of {@link Jwts.ZIP#DEF}.
|
||||
*/
|
||||
public static final CompressionCodec DEFLATE =
|
||||
Classes.newInstance("io.jsonwebtoken.impl.compression.DeflateCompressionCodec");
|
||||
@Deprecated
|
||||
public static final CompressionCodec DEFLATE = (CompressionCodec) Jwts.ZIP.DEF;
|
||||
|
||||
/**
|
||||
* Codec implementing the <a href="https://en.wikipedia.org/wiki/Gzip">gzip</a> compression algorithm.
|
||||
|
@ -44,9 +46,11 @@ public final class CompressionCodecs {
|
|||
* <p><b>This is not a standard JWA compression algorithm</b>. Be sure to use this only when you are confident
|
||||
* that all parties accessing the token support the gzip algorithm.</p>
|
||||
*
|
||||
* <p>If you're concerned about compatibility, the {@link #DEFLATE DEFLATE} code is JWA standards-compliant.</p>
|
||||
* <p>If you're concerned about compatibility, the {@link Jwts.ZIP#DEF DEF} code is JWA standards-compliant.</p>
|
||||
*
|
||||
* @deprecated in favor of {@link Jwts.ZIP#GZIP}
|
||||
*/
|
||||
public static final CompressionCodec GZIP =
|
||||
Classes.newInstance("io.jsonwebtoken.impl.compression.GzipCompressionCodec");
|
||||
@Deprecated
|
||||
public static final CompressionCodec GZIP = (CompressionCodec) Jwts.ZIP.GZIP;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.lang.Builder;
|
||||
import io.jsonwebtoken.lang.MapMutator;
|
||||
import io.jsonwebtoken.security.X509Builder;
|
||||
|
||||
/**
|
||||
* A {@link Builder} that dynamically determines the type of {@link Header} to create based on builder state.
|
||||
* <ul>
|
||||
* <li>If only standard {@link Header} properties have been set (that is, no
|
||||
* {@link JwsHeader} or {@link JweHeader} properties have been set), an {@link UnprotectedHeader} will be created.</li>
|
||||
* <li>If any {@link ProtectedHeader} properties have been set (but no {@link JweHeader} properties), a
|
||||
* {@link JwsHeader} will be created.</li>
|
||||
* <li>If any {@link JweHeader} properties have been set, a {@link JweHeader} will be created.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface DynamicHeaderBuilder extends
|
||||
MapMutator<String, Object, DynamicHeaderBuilder>,
|
||||
X509Builder<DynamicHeaderBuilder>,
|
||||
JweHeaderMutator<DynamicHeaderBuilder>,
|
||||
Builder<Header<?>> {
|
||||
}
|
|
@ -29,7 +29,7 @@ public class ExpiredJwtException extends ClaimJwtException {
|
|||
* @param claims jwt claims (body)
|
||||
* @param message the message explaining why the exception is thrown.
|
||||
*/
|
||||
public ExpiredJwtException(Header<?> header, Claims claims, String message) {
|
||||
public ExpiredJwtException(Header header, Claims claims, String message) {
|
||||
super(header, claims, message);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class ExpiredJwtException extends ClaimJwtException {
|
|||
* @param claims jwt claims (body)
|
||||
* @since 0.5
|
||||
*/
|
||||
public ExpiredJwtException(Header<?> header, Claims claims, String message, Throwable cause) {
|
||||
public ExpiredJwtException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(header, claims, message, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,25 +18,31 @@ package io.jsonwebtoken;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5">JOSE header</a>.
|
||||
* A JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-5">JOSE header</a>.
|
||||
*
|
||||
* <p>This is ultimately a JSON map and any values can be added to it, but JWT JOSE standard names are provided as
|
||||
* type-safe getters and setters for convenience.</p>
|
||||
* <p>This is an immutable JSON map with convenient type-safe getters for JWT standard header parameter names.</p>
|
||||
*
|
||||
* <p>Because this interface extends {@code Map<String, Object>}, if you would like to add your own properties,
|
||||
* you simply use map methods, for example:</p>
|
||||
* <p>Because this interface extends <code>Map<String, Object></code>, you can use standard {@code Map}
|
||||
* accessor/iterator methods as desired, for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* header.{@link Map#put(Object, Object) put}("headerParamName", "headerParamValue");
|
||||
* </pre>
|
||||
* <blockquote><pre>
|
||||
* header.get("someKey");</pre></blockquote>
|
||||
*
|
||||
* <h2>Creation</h2>
|
||||
* <p>However, because {@code Header} instances are immutable, calling any of the map mutation methods
|
||||
* (such as {@code Map.}{@link Map#put(Object, Object) put}, etc) will result in a runtime exception.</p>
|
||||
*
|
||||
* <p>It is easiest to create a {@code Header} instance by using {@link Jwts#header()}.</p>
|
||||
* <p><b>Security</b></p>
|
||||
*
|
||||
* <p>The {@code Header} interface itself makes no implications of integrity protection via either digital signatures or
|
||||
* encryption. Instead, {@link JwsHeader} and {@link JweHeader} represent this information for respective
|
||||
* {@link Jws} and {@link Jwe} instances.</p>
|
||||
*
|
||||
* @see ProtectedHeader
|
||||
* @see JwsHeader
|
||||
* @see JweHeader
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface Header<T extends Header<T>> extends Map<String, Object>, HeaderMutator<T> {
|
||||
public interface Header extends Map<String, Object> {
|
||||
|
||||
/**
|
||||
* JWT {@code Type} (typ) value: <code>"JWT"</code>
|
||||
|
@ -74,7 +80,6 @@ public interface Header<T extends Header<T>> extends Map<String, Object>, Header
|
|||
*
|
||||
* @deprecated use {@link #COMPRESSION_ALGORITHM} instead.
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
String DEPRECATED_COMPRESSION_ALGORITHM = "calg";
|
||||
|
||||
|
@ -117,14 +122,14 @@ public interface Header<T extends Header<T>> extends Map<String, Object>, Header
|
|||
* <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</code></a> (Algorithm) header parameter identifies the cryptographic algorithm used to secure the
|
||||
* JWS. Consider using {@link Jwts#SIG}.{@link io.jsonwebtoken.lang.Registry#find(Object) find(id)}
|
||||
* JWS. Consider using {@link Jwts.SIG}.{@link io.jsonwebtoken.lang.Registry#get(Object) get(id)}
|
||||
* to convert this string value to a type-safe {@code SecureDigestAlgorithm} instance.</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. Consider
|
||||
* using {@link Jwts#KEY}.{@link io.jsonwebtoken.lang.Registry#find(Object) find(id)} to convert this string value
|
||||
* using {@link Jwts.KEY}.{@link io.jsonwebtoken.lang.Registry#get(Object) get(id)} to convert this string value
|
||||
* to a type-safe {@link io.jsonwebtoken.security.KeyAlgorithm KeyAlgorithm} instance.</li>
|
||||
* </ul>
|
||||
*
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.lang.MapMutator;
|
||||
|
||||
/**
|
||||
* Mutation (modifications) to a {@link Header Header} instance.
|
||||
*
|
||||
* @param <T> the mutator subtype, for method chaining
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface HeaderMutator<T extends HeaderMutator<T>> {
|
||||
public interface HeaderMutator<T extends HeaderMutator<T>> extends MapMutator<String, Object, T> {
|
||||
|
||||
/**
|
||||
* Sets the JWT <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-5.1">
|
||||
|
|
|
@ -18,10 +18,7 @@ package io.jsonwebtoken;
|
|||
/**
|
||||
* An object that may be uniquely identified by an {@link #getId() id} relative to other instances of the same type.
|
||||
*
|
||||
* <p>All JWT concepts that have a
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html">JWA</a> identifier value implement this interface.
|
||||
* Specifically, there are four JWT concepts that are {@code Identifiable}. The following table indicates how
|
||||
* their {@link #getId() id} values are used.</p>
|
||||
* <p>The following table indicates how various JWT or JWK {@link #getId() getId()} values are used.</p>
|
||||
*
|
||||
* <table>
|
||||
* <caption>JWA Identifiable Concepts</caption>
|
||||
|
@ -33,6 +30,31 @@ package io.jsonwebtoken;
|
|||
* </thead>
|
||||
* <tbody>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.Claims Claims}</td>
|
||||
* <td>JWT's <a href="https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7">{@code jti} (JWT ID)</a>
|
||||
* claim.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.security.Jwk Jwk}</td>
|
||||
* <td>JWK's <a href="https://www.rfc-editor.org/rfc/rfc7517.html#section-4.5">{@code kid} (Key ID)</a>
|
||||
* parameter value.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.CompressionCodec CompressionCodec}</td>
|
||||
* <td>JWE protected header's
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3">{@code zip} (Compression Algorithm)</a>
|
||||
* parameter value.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.security.HashAlgorithm HashAlgorithm}</td>
|
||||
* <td>Within a {@link io.jsonwebtoken.security.JwkThumbprint JwkThumbprint}'s URI value.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.security.MacAlgorithm MacAlgorithm}</td>
|
||||
* <td>JWS protected header's
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">{@code alg} (Algorithm)</a> parameter value.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.security.SignatureAlgorithm SignatureAlgorithm}</td>
|
||||
* <td>JWS protected header's
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">{@code alg} (Algorithm)</a> parameter value.</td>
|
||||
|
@ -49,11 +71,6 @@ package io.jsonwebtoken;
|
|||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">{@code enc} (Encryption Algorithm)</a>
|
||||
* parameter value.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link io.jsonwebtoken.security.Jwk Jwk}</td>
|
||||
* <td>JWK's <a href="https://www.rfc-editor.org/rfc/rfc7517.html#section-4.5">{@code kid} (Key ID)</a>
|
||||
* parameter value.</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
*
|
||||
|
|
|
@ -32,7 +32,7 @@ public class IncorrectClaimException extends InvalidClaimException {
|
|||
* @param claimValue the value of the claim that could not be validated
|
||||
* @param message the exception message
|
||||
*/
|
||||
public IncorrectClaimException(Header<?> header, Claims claims, String claimName, Object claimValue, String message) {
|
||||
public IncorrectClaimException(Header header, Claims claims, String claimName, Object claimValue, String message) {
|
||||
super(header, claims, claimName, claimValue, message);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ public class IncorrectClaimException extends InvalidClaimException {
|
|||
* @param message the exception message
|
||||
* @param cause the underlying cause that resulted in this exception being thrown
|
||||
*/
|
||||
public IncorrectClaimException(Header<?> header, Claims claims, String claimName, Object claimValue, String message, Throwable cause) {
|
||||
public IncorrectClaimException(Header header, Claims claims, String claimName, Object claimValue, String message, Throwable cause) {
|
||||
super(header, claims, claimName, claimValue, message, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class InvalidClaimException extends ClaimJwtException {
|
|||
* @param claimValue the value of the claim that could not be validated
|
||||
* @param message the exception message
|
||||
*/
|
||||
protected InvalidClaimException(Header<?> header, Claims claims, String claimName, Object claimValue, String message) {
|
||||
protected InvalidClaimException(Header header, Claims claims, String claimName, Object claimValue, String message) {
|
||||
super(header, claims, message);
|
||||
this.claimName = claimName;
|
||||
this.claimValue = claimValue;
|
||||
|
@ -60,7 +60,7 @@ public class InvalidClaimException extends ClaimJwtException {
|
|||
* @param message the exception message
|
||||
* @param cause the underlying cause that resulted in this exception being thrown
|
||||
*/
|
||||
protected InvalidClaimException(Header<?> header, Claims claims, String claimName, Object claimValue, String message, Throwable cause) {
|
||||
protected InvalidClaimException(Header header, Claims claims, String claimName, Object claimValue, String message, Throwable cause) {
|
||||
super(header, claims, message, cause);
|
||||
this.claimName = claimName;
|
||||
this.claimValue = claimValue;
|
||||
|
|
|
@ -22,7 +22,7 @@ package io.jsonwebtoken;
|
|||
* @param <B> payload type, either {@link Claims} or {@code byte[]} content.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface Jwe<B> extends Jwt<JweHeader, B> {
|
||||
public interface Jwe<B> extends ProtectedJwt<JweHeader, B> {
|
||||
|
||||
/**
|
||||
* Returns the Initialization Vector used during JWE encryption and decryption.
|
||||
|
@ -30,13 +30,4 @@ public interface Jwe<B> extends Jwt<JweHeader, B> {
|
|||
* @return the Initialization Vector used during JWE encryption and decryption.
|
||||
*/
|
||||
byte[] getInitializationVector();
|
||||
|
||||
/**
|
||||
* Returns the Additional Authenticated Data authentication Tag used for JWE header
|
||||
* authenticity and integrity verification.
|
||||
*
|
||||
* @return the Additional Authenticated Data authentication Tag used for JWE header
|
||||
* authenticity and integrity verification.
|
||||
*/
|
||||
byte[] getAadTag();
|
||||
}
|
||||
|
|
|
@ -18,17 +18,16 @@ package io.jsonwebtoken;
|
|||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
import io.jsonwebtoken.security.StandardKeyAlgorithms;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* A <a href="https://tools.ietf.org/html/rfc7516">JWE</a> header.
|
||||
* A <a href="https://www.rfc-editor.org/rfc/rfc7516.html">JWE</a> header.
|
||||
*
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<JweHeader> {
|
||||
public interface JweHeader extends ProtectedHeader {
|
||||
|
||||
/**
|
||||
* Returns the JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.2">{@code enc} (Encryption
|
||||
|
@ -66,11 +65,11 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* @return the <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">{@code epk} (Ephemeral
|
||||
* Public Key)</a> header value created by the JWE originator for use with key agreement algorithms, or
|
||||
* {@code null} if not present.
|
||||
* @see Jwts#KEY
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
PublicJwk<?> getEphemeralPublicKey();
|
||||
|
||||
|
@ -81,10 +80,10 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* @return any information about the JWE producer for use with key agreement algorithms, or {@code null} if not
|
||||
* present.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.2">JWE <code>apu</code> (Agreement PartyUInfo) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
byte[] getAgreementPartyUInfo();
|
||||
|
||||
|
@ -95,10 +94,10 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* @return any information about the JWE recipient for use with key agreement algorithms, or {@code null} if not
|
||||
* present.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.3">JWE <code>apv</code> (Agreement PartyVInfo) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
byte[] getAgreementPartyVInfo();
|
||||
|
||||
|
@ -114,9 +113,9 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* automatically when producing the encryption key.</p>
|
||||
*
|
||||
* @return the 96-bit initialization vector generated during key encryption, or {@code null} if not present.
|
||||
* @see StandardKeyAlgorithms#A128GCMKW
|
||||
* @see StandardKeyAlgorithms#A192GCMKW
|
||||
* @see StandardKeyAlgorithms#A256GCMKW
|
||||
* @see Jwts.KEY#A128GCMKW
|
||||
* @see Jwts.KEY#A192GCMKW
|
||||
* @see Jwts.KEY#A256GCMKW
|
||||
*/
|
||||
byte[] getInitializationVector();
|
||||
|
||||
|
@ -131,9 +130,9 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* automatically when producing the encryption key.</p>
|
||||
*
|
||||
* @return the 128-bit authentication tag resulting from key encryption, or {@code null} if not present.
|
||||
* @see StandardKeyAlgorithms#A128GCMKW
|
||||
* @see StandardKeyAlgorithms#A192GCMKW
|
||||
* @see StandardKeyAlgorithms#A256GCMKW
|
||||
* @see Jwts.KEY#A128GCMKW
|
||||
* @see Jwts.KEY#A192GCMKW
|
||||
* @see Jwts.KEY#A256GCMKW
|
||||
*/
|
||||
byte[] getAuthenticationTag();
|
||||
|
||||
|
@ -144,9 +143,9 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* @return the number of PBKDF2 iterations necessary to derive the key used during JWE encryption, or {@code null}
|
||||
* if not present.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.2">JWE <code>p2c</code> (PBES2 Count) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#PBES2_HS256_A128KW
|
||||
* @see StandardKeyAlgorithms#PBES2_HS384_A192KW
|
||||
* @see StandardKeyAlgorithms#PBES2_HS512_A256KW
|
||||
* @see Jwts.KEY#PBES2_HS256_A128KW
|
||||
* @see Jwts.KEY#PBES2_HS384_A192KW
|
||||
* @see Jwts.KEY#PBES2_HS512_A256KW
|
||||
*/
|
||||
Integer getPbes2Count();
|
||||
|
||||
|
@ -163,9 +162,9 @@ public interface JweHeader extends ProtectedHeader<JweHeader>, JweHeaderMutator<
|
|||
* @return the PBKDF2 {@code Salt Input} value necessary to derive the key used during JWE encryption, or
|
||||
* {@code null} if not present.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1">JWE <code>p2s</code> (PBES2 Salt Input) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#PBES2_HS256_A128KW
|
||||
* @see StandardKeyAlgorithms#PBES2_HS384_A192KW
|
||||
* @see StandardKeyAlgorithms#PBES2_HS512_A256KW
|
||||
* @see Jwts.KEY#PBES2_HS256_A128KW
|
||||
* @see Jwts.KEY#PBES2_HS384_A192KW
|
||||
* @see Jwts.KEY#PBES2_HS512_A256KW
|
||||
*/
|
||||
byte[] getPbes2Salt();
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.StandardKeyAlgorithms;
|
||||
|
||||
/**
|
||||
* Mutation (modifications) to a {@link JweHeader} instance.
|
||||
|
@ -26,20 +25,6 @@ import io.jsonwebtoken.security.StandardKeyAlgorithms;
|
|||
*/
|
||||
public interface JweHeaderMutator<T extends JweHeaderMutator<T>> extends ProtectedHeaderMutator<T> {
|
||||
|
||||
// /**
|
||||
// * Sets the JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.2">{@code enc} (Encryption
|
||||
// * Algorithm)</a> header value. A {@code null} value will remove the property from the JSON map.
|
||||
// *
|
||||
// * <p>This should almost never be set by JJWT users directly - JJWT will always set this value to the value
|
||||
// * returned by {@link AeadAlgorithm#getId()} when performing encryption, overwriting any potential previous
|
||||
// * value.</p>
|
||||
// *
|
||||
// * @param enc the encryption algorithm identifier obtained from {@link AeadAlgorithm#getId()}.
|
||||
// * @return this header for method chaining
|
||||
// */
|
||||
// @SuppressWarnings("UnusedReturnValue")
|
||||
// JweHeader setEncryptionAlgorithm(String enc);
|
||||
|
||||
/**
|
||||
* Sets any information about the JWE producer for use with key agreement algorithms. A {@code null} or empty value
|
||||
* removes the property from the JSON map.
|
||||
|
@ -47,10 +32,10 @@ public interface JweHeaderMutator<T extends JweHeaderMutator<T>> extends Protect
|
|||
* @param info information about the JWE producer to use with key agreement algorithms.
|
||||
* @return the header for method chaining.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.2">JWE <code>apu</code> (Agreement PartyUInfo) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
T setAgreementPartyUInfo(byte[] info);
|
||||
|
||||
|
@ -65,10 +50,10 @@ public interface JweHeaderMutator<T extends JweHeaderMutator<T>> extends Protect
|
|||
* @param info information about the JWE producer to use with key agreement algorithms.
|
||||
* @return the header for method chaining.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.2">JWE <code>apu</code> (Agreement PartyUInfo) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
T setAgreementPartyUInfo(String info);
|
||||
|
||||
|
@ -79,10 +64,10 @@ public interface JweHeaderMutator<T extends JweHeaderMutator<T>> extends Protect
|
|||
* @param info information about the JWE recipient to use with key agreement algorithms.
|
||||
* @return the header for method chaining.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.3">JWE <code>apv</code> (Agreement PartyVInfo) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
T setAgreementPartyVInfo(byte[] info);
|
||||
|
||||
|
@ -97,10 +82,10 @@ public interface JweHeaderMutator<T extends JweHeaderMutator<T>> extends Protect
|
|||
* @param info information about the JWE recipient to use with key agreement algorithms.
|
||||
* @return the header for method chaining.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.3">JWE <code>apv</code> (Agreement PartyVInfo) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#ECDH_ES
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A128KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A192KW
|
||||
* @see StandardKeyAlgorithms#ECDH_ES_A256KW
|
||||
* @see Jwts.KEY#ECDH_ES
|
||||
* @see Jwts.KEY#ECDH_ES_A128KW
|
||||
* @see Jwts.KEY#ECDH_ES_A192KW
|
||||
* @see Jwts.KEY#ECDH_ES_A256KW
|
||||
*/
|
||||
T setAgreementPartyVInfo(String info);
|
||||
|
||||
|
@ -122,25 +107,10 @@ public interface JweHeaderMutator<T extends JweHeaderMutator<T>> extends Protect
|
|||
* greater than or equal to 1000 (one thousand).
|
||||
* @return the header for method chaining
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.2">JWE <code>p2c</code> (PBES2 Count) Header Parameter</a>
|
||||
* @see StandardKeyAlgorithms#PBES2_HS256_A128KW
|
||||
* @see StandardKeyAlgorithms#PBES2_HS384_A192KW
|
||||
* @see StandardKeyAlgorithms#PBES2_HS512_A256KW
|
||||
* @see Jwts.KEY#PBES2_HS256_A128KW
|
||||
* @see Jwts.KEY#PBES2_HS384_A192KW
|
||||
* @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);
|
||||
|
||||
// /**
|
||||
// * Sets the PBKDF2 {@code Salt Input} value necessary to derive the key used during JWE encryption. This should
|
||||
// * almost never be used by JJWT users directly - it should instead be automatically generated and set within a
|
||||
// * PBKDF2-based {@link io.jsonwebtoken.security.KeyAlgorithm KeyAlgorithm} implementation.
|
||||
// *
|
||||
// * @param salt the PBKDF2 {@code Salt Input} value necessary to derive the key used during JWE encryption.
|
||||
// * @return the header for method chaining
|
||||
// * @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1">JWE <code>p2s</code> (PBES2 Salt Input) Header Parameter</a>
|
||||
// * @see Jwts.KEY#PBES2_HS256_A128KW
|
||||
// * @see Jwts.KEY#PBES2_HS384_A192KW
|
||||
// * @see Jwts.KEY#PBES2_HS512_A256KW
|
||||
// */
|
||||
// JweHeader setPbes2Salt(byte[] salt);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,12 +21,14 @@ package io.jsonwebtoken;
|
|||
* @param <B> the type of the JWS body contents, either a String or a {@link Claims} instance.
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface Jws<B> extends Jwt<JwsHeader, B> {
|
||||
public interface Jws<B> extends ProtectedJwt<JwsHeader, B> {
|
||||
|
||||
/**
|
||||
* Returns the verified JWS signature as a Base64Url string.
|
||||
*
|
||||
* @return the verified JWS signature as a Base64Url string.
|
||||
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #getDigest() getDigest()}.
|
||||
*/
|
||||
@Deprecated
|
||||
String getSignature(); //TODO for 1.0: return a byte[]
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.jsonwebtoken;
|
|||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface JwsHeader extends ProtectedHeader<JwsHeader> {
|
||||
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>
|
||||
|
|
|
@ -18,10 +18,11 @@ package io.jsonwebtoken;
|
|||
/**
|
||||
* An expanded (not compact/serialized) JSON Web Token.
|
||||
*
|
||||
* @param <P> the type of the JWT payload, either a byte array or a {@link Claims} instance.
|
||||
* @param <H> the type of the JWT header
|
||||
* @param <P> the type of the JWT payload, either a content byte array or a {@link Claims} instance.
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface Jwt<H extends Header<H>, P> {
|
||||
public interface Jwt<H extends Header, P> {
|
||||
|
||||
/**
|
||||
* Returns the JWT {@link Header} or {@code null} if not present.
|
||||
|
|
|
@ -15,20 +15,19 @@
|
|||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.io.Encoder;
|
||||
import io.jsonwebtoken.io.Serializer;
|
||||
import io.jsonwebtoken.lang.Builder;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.InvalidKeyException;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.Password;
|
||||
import io.jsonwebtoken.security.SecureDigestAlgorithm;
|
||||
import io.jsonwebtoken.security.StandardKeyAlgorithms;
|
||||
import io.jsonwebtoken.security.StandardSecureDigestAlgorithms;
|
||||
import io.jsonwebtoken.security.WeakKeyException;
|
||||
import io.jsonwebtoken.security.X509Builder;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.Key;
|
||||
|
@ -70,32 +69,38 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
JwtBuilder setSecureRandom(SecureRandom secureRandom);
|
||||
|
||||
/**
|
||||
* Sets (and replaces) any existing header with the specified header. If you do not want to replace the existing
|
||||
* header and only want to append to it, use the {@link #setHeaderParams(java.util.Map)} method instead.
|
||||
* 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.
|
||||
* For example:
|
||||
*
|
||||
* @param header the header to set (and potentially replace any existing header).
|
||||
* @return the builder for method chaining.
|
||||
*/
|
||||
JwtBuilder setHeader(Header<?> header); //replaces any existing header with the specified header.
|
||||
|
||||
/**
|
||||
* Sets (and replaces) any existing header with the specified header. If you do not want to replace the existing
|
||||
* header and only want to append to it, use the {@link #setHeaderParams(java.util.Map)} method instead.
|
||||
* <blockquote><pre>
|
||||
* String jwt = Jwts.builder()
|
||||
*
|
||||
* @param header the header to set (and potentially replace any existing header).
|
||||
* @return the builder for method chaining.
|
||||
*/
|
||||
JwtBuilder setHeader(Map<String, ?> header);
|
||||
|
||||
/**
|
||||
* Sets (and replaces) any existing header with the header resulting from the specified builder's
|
||||
* {@link Builder#build()} result.
|
||||
* <b>.header()
|
||||
* .setKeyId("keyId")
|
||||
* .set(myHeaderMap)
|
||||
* // ... other header params ...
|
||||
* .{@link JwtBuilder.Header#and() and()}</b> //return back to the JwtBuilder
|
||||
*
|
||||
* @param builder the builder to use to obtain the header
|
||||
* @return the JwtBuilder for method chaining.
|
||||
* .setSubject("Joe") // resume JwtBuilder calls
|
||||
* // ... etc ...
|
||||
* .compact();</pre></blockquote>
|
||||
*
|
||||
* @return the {@link JwtBuilder.Header} to use for header construction.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
JwtBuilder setHeader(Builder<? extends Header<?>> builder);
|
||||
JwtBuilder.Header header();
|
||||
|
||||
/**
|
||||
* Sets (and replaces) any existing header with the specified name/value pairs. If you do not want to replace the
|
||||
* existing header and only want to append to it, call
|
||||
* {@link #header()}{@code .}{@link io.jsonwebtoken.lang.MapMutator#set(Map) set(map)}
|
||||
* instead.
|
||||
*
|
||||
* @param map the name/value pairs to set as (and potentially replace) the constructed JWT header.
|
||||
* @return the builder for method chaining.
|
||||
*/
|
||||
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
|
||||
|
@ -118,7 +123,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
|
||||
/**
|
||||
* Sets the JWT payload to the string's UTF-8-encoded bytes. It is strongly recommended to also set the
|
||||
* {@link Header#getContentType() contentType} header value so the JWT recipient may inspect that value to
|
||||
* {@link Header#setContentType(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.
|
||||
*
|
||||
|
@ -173,7 +178,15 @@ 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 {@link Header#setContentType(String)} independently.</p>
|
||||
* method - instead call {@link #setContent(byte[])} and set the header's
|
||||
* {@link Header#setContentType(String) contentType} independently. For example:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* Jwts.builder()
|
||||
* .header().setContentType("application/whatever").and()
|
||||
* .setContent(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>
|
||||
|
@ -229,7 +242,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <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#setIssuer(String) issuer} field with the specified value. This allows you to write
|
||||
* the Claims {@link Claims#getIssuer() issuer} field with the specified value. This allows you to write
|
||||
* code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
|
@ -238,7 +251,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
*
|
||||
* <p>instead of this:</p>
|
||||
* <pre>
|
||||
* Claims claims = Jwts.claims().setIssuer("Joe");
|
||||
* Claims claims = Jwts.claims().setIssuer("Joe").build();
|
||||
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||
* </pre>
|
||||
* <p>if desired.</p>
|
||||
|
@ -256,18 +269,16 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <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#setSubject(String) subject} field with the specified value. This allows you to write
|
||||
* the Claims {@link Claims#getSubject() subject} field with the specified value. This allows you to write
|
||||
* code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* String jwt = Jwts.builder().setSubject("Me").compact();
|
||||
* </pre>
|
||||
* <blockquote><pre>
|
||||
* String jwt = Jwts.builder().setSubject("Me").compact();</pre></blockquote>
|
||||
*
|
||||
* <p>instead of this:</p>
|
||||
* <pre>
|
||||
* Claims claims = Jwts.claims().setSubject("Me");
|
||||
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||
* </pre>
|
||||
* <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.
|
||||
|
@ -283,7 +294,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <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#setAudience(String) audience} field with the specified value. This allows you to write
|
||||
* the Claims {@link Claims#getAudience() audience} field with the specified value. This allows you to write
|
||||
* code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
|
@ -312,7 +323,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <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#setExpiration(java.util.Date) expiration} field with the specified value. This allows
|
||||
* the Claims {@link Claims#getExpiration() expiration} field with the specified value. This allows
|
||||
* you to write code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
|
@ -341,7 +352,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <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#setNotBefore(java.util.Date) notBefore} field with the specified value. This allows
|
||||
* the Claims {@link Claims#getNotBefore() notBefore} field with the specified value. This allows
|
||||
* you to write code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
|
@ -370,7 +381,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <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#setIssuedAt(java.util.Date) issuedAt} field with the specified value. This allows
|
||||
* the Claims {@link Claims#getIssuedAt() issuedAt} field with the specified value. This allows
|
||||
* you to write code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
|
@ -401,7 +412,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* 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#setId(String) id} field with the specified value. This allows
|
||||
* the Claims {@link Claims#getId() id} field with the specified value. This allows
|
||||
* you to write code like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
|
@ -475,67 +486,67 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <td>{@link SecretKey}</td>
|
||||
* <td><code>{@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA256")</code><sup>1</sup></td>
|
||||
* <td>256 <= size <= 383 <sup>2</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#HS256 HS256}</td>
|
||||
* <td>{@link Jwts.SIG#HS256 HS256}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link SecretKey}</td>
|
||||
* <td><code>{@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA384")</code><sup>1</sup></td>
|
||||
* <td>384 <= size <= 511</td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#HS384 HS384}</td>
|
||||
* <td>{@link Jwts.SIG#HS384 HS384}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link SecretKey}</td>
|
||||
* <td><code>{@link Key#getAlgorithm() getAlgorithm()}.equals("HmacSHA512")</code><sup>1</sup></td>
|
||||
* <td>512 <= size</td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#HS512 HS512}</td>
|
||||
* <td>{@link Jwts.SIG#HS512 HS512}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link ECKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>256 <= size <= 383 <sup>3</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#ES256 ES256}</td>
|
||||
* <td>{@link Jwts.SIG#ES256 ES256}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link ECKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>384 <= size <= 520 <sup>4</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#ES384 ES384}</td>
|
||||
* <td>{@link Jwts.SIG#ES384 ES384}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link ECKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td><b>521</b> <= size <sup>4</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#ES512 ES512}</td>
|
||||
* <td>{@link Jwts.SIG#ES512 ES512}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link RSAKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>2048 <= size <= 3071 <sup>5,6</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#RS256 RS256}</td>
|
||||
* <td>{@link Jwts.SIG#RS256 RS256}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link RSAKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>3072 <= size <= 4095 <sup>6</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#RS384 RS384}</td>
|
||||
* <td>{@link Jwts.SIG#RS384 RS384}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link RSAKey}</td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>4096 <= size <sup>5</sup></td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#RS512 RS512}</td>
|
||||
* <td>{@link Jwts.SIG#RS512 RS512}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECKey.html">EdECKey</a><sup>7</sup></td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>256</td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#Ed25519 Ed25519}</td>
|
||||
* <td>{@link Jwts.SIG#Ed25519 Ed25519}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECKey.html">EdECKey</a><sup>7</sup></td>
|
||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||
* <td>456</td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms#Ed448 Ed448}</td>
|
||||
* <td>{@link Jwts.SIG#Ed448 Ed448}</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
|
@ -561,18 +572,18 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* {@code RSAKey}s with key lengths less than 2048 bits will be rejected with a
|
||||
* {@link WeakKeyException}.</li>
|
||||
* <li>Technically any RSA key of length >= 2048 bits may be used with the
|
||||
* {@link StandardSecureDigestAlgorithms#RS256 RS256}, {@link StandardSecureDigestAlgorithms#RS384 RS384}, and
|
||||
* {@link StandardSecureDigestAlgorithms#RS512 RS512} algorithms, so we assume an RSA signature algorithm based on the key
|
||||
* {@link Jwts.SIG#RS256 RS256}, {@link Jwts.SIG#RS384 RS384}, and
|
||||
* {@link Jwts.SIG#RS512 RS512} algorithms, so we assume an RSA signature algorithm based on the key
|
||||
* length to parallel similar decisions in the JWT specification for HMAC and ECDSA signature algorithms.
|
||||
* This is not required - just a convenience.</li>
|
||||
* <li><a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECKey.html">EdECKey</a>s
|
||||
* require JDK >= 15 or BouncyCastle in the runtime classpath.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>This implementation does not use the {@link StandardSecureDigestAlgorithms#PS256 PS256},
|
||||
* {@link StandardSecureDigestAlgorithms#PS384 PS384}, or {@link StandardSecureDigestAlgorithms#PS512 PS512} RSA variants for any
|
||||
* specified {@link RSAKey} because the the {@link StandardSecureDigestAlgorithms#RS256 RS256},
|
||||
* {@link StandardSecureDigestAlgorithms#RS384 RS384}, and {@link StandardSecureDigestAlgorithms#RS512 RS512} algorithms are
|
||||
* <p>This implementation does not use the {@link Jwts.SIG#PS256 PS256},
|
||||
* {@link Jwts.SIG#PS384 PS384}, or {@link Jwts.SIG#PS512 PS512} RSA variants for any
|
||||
* specified {@link RSAKey} because the the {@link Jwts.SIG#RS256 RS256},
|
||||
* {@link Jwts.SIG#RS384 RS384}, and {@link Jwts.SIG#RS512 RS512} algorithms are
|
||||
* available in the JDK by default while the {@code PS}* variants require either JDK 11 or an additional JCA
|
||||
* Provider (like BouncyCastle). If you wish to use a {@code PS}* variant with your key, use the
|
||||
* {@link #signWith(Key, SecureDigestAlgorithm)} method instead.</p>
|
||||
|
@ -585,7 +596,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* @return the builder instance for method chaining.
|
||||
* @throws InvalidKeyException if the Key is insufficient, unsupported, or explicitly disallowed by the JWT
|
||||
* specification as described above in <em>recommended signature algorithms</em>.
|
||||
* @see Jwts#SIG
|
||||
* @see Jwts.SIG
|
||||
* @see #signWith(Key, SecureDigestAlgorithm)
|
||||
* @since 0.10.0
|
||||
*/
|
||||
|
@ -686,7 +697,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
*
|
||||
* <p><b>This has been deprecated since JJWT_RELEASE_VERSION. Use
|
||||
* {@link #signWith(Key, SecureDigestAlgorithm)} instead</b>. Standard JWA algorithms
|
||||
* are represented as instances of this new interface in the {@link Jwts#SIG}
|
||||
* are represented as instances of this new interface in the {@link Jwts.SIG}
|
||||
* algorithm registry.</p>
|
||||
*
|
||||
* <p>Signs the constructed JWT with the specified key using the specified algorithm, producing a JWS.</p>
|
||||
|
@ -710,7 +721,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
/**
|
||||
* Signs the constructed JWT with the specified key using the specified algorithm, producing a JWS.
|
||||
*
|
||||
* <p>The {@link Jwts#SIG} registry makes available all standard signature
|
||||
* <p>The {@link Jwts.SIG} registry makes available all standard signature
|
||||
* algorithms defined in the JWA specification.</p>
|
||||
*
|
||||
* <p>It is typically recommended to call the {@link #signWith(Key)} instead for simplicity.
|
||||
|
@ -724,10 +735,10 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* @throws InvalidKeyException if the Key is insufficient or explicitly disallowed by the JWT specification for
|
||||
* the specified algorithm.
|
||||
* @see #signWith(Key)
|
||||
* @see Jwts#SIG
|
||||
* @see Jwts.SIG
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
<K extends Key> JwtBuilder signWith(K key, io.jsonwebtoken.security.SecureDigestAlgorithm<? super K, ?> alg) throws InvalidKeyException;
|
||||
<K extends Key> JwtBuilder signWith(K key, SecureDigestAlgorithm<? super K, ?> alg) throws InvalidKeyException;
|
||||
|
||||
/**
|
||||
* Encrypts the constructed JWT with the specified symmetric {@code key} using the provided {@code enc}ryption
|
||||
|
@ -740,12 +751,12 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <ul>
|
||||
* <li>If the provided {@code key} is a {@link Password Password} instance,
|
||||
* the {@code KeyAlgorithm} used will be one of the three JWA-standard password-based key algorithms
|
||||
* ({@link StandardKeyAlgorithms#PBES2_HS256_A128KW PBES2_HS256_A128KW},
|
||||
* {@link StandardKeyAlgorithms#PBES2_HS384_A192KW PBES2_HS384_A192KW}, or
|
||||
* {@link StandardKeyAlgorithms#PBES2_HS512_A256KW PBES2_HS512_A256KW}) as determined by the {@code enc} algorithm's
|
||||
* ({@link Jwts.KEY#PBES2_HS256_A128KW PBES2_HS256_A128KW},
|
||||
* {@link Jwts.KEY#PBES2_HS384_A192KW PBES2_HS384_A192KW}, or
|
||||
* {@link Jwts.KEY#PBES2_HS512_A256KW PBES2_HS512_A256KW}) as determined by the {@code enc} algorithm's
|
||||
* {@link AeadAlgorithm#getKeyBitLength() key length} requirement.</li>
|
||||
* <li>If the {@code key} is otherwise a standard {@code SecretKey}, the {@code KeyAlgorithm} will be
|
||||
* {@link StandardKeyAlgorithms#DIRECT}, indicating that {@code key} should be used directly with the
|
||||
* {@link Jwts.KEY#DIRECT DIRECT}, indicating that {@code key} should be used directly with the
|
||||
* {@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
|
||||
|
@ -754,9 +765,9 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
*
|
||||
* @param key the symmetric encryption key to use with the {@code enc} algorithm.
|
||||
* @param enc the {@link AeadAlgorithm} algorithm used to encrypt the JWE, usually one of the JWA-standard
|
||||
* algorithms accessible via {@link Jwts#ENC}.
|
||||
* algorithms accessible via {@link Jwts.ENC}.
|
||||
* @return the JWE builder for method chaining.
|
||||
* @see Jwts#ENC
|
||||
* @see Jwts.ENC
|
||||
*/
|
||||
JwtBuilder encryptWith(SecretKey key, AeadAlgorithm enc);
|
||||
|
||||
|
@ -777,7 +788,7 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* </ol>
|
||||
*
|
||||
* <p>Most application developers will reference one of the JWA
|
||||
* {@link Jwts#KEY standard key algorithms} and {@link Jwts#ENC standard encryption algorithms}
|
||||
* {@link Jwts.KEY standard key algorithms} and {@link Jwts.ENC standard encryption algorithms}
|
||||
* when invoking this method, but custom implementations are also supported.</p>
|
||||
*
|
||||
* @param <K> the type of key that must be used with the specified {@code keyAlg} instance.
|
||||
|
@ -786,13 +797,13 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* {@code enc} algorithm
|
||||
* @param enc the {@link AeadAlgorithm} algorithm used to encrypt the JWE
|
||||
* @return the JWE builder for method chaining.
|
||||
* @see Jwts#ENC
|
||||
* @see Jwts#KEY
|
||||
* @see Jwts.ENC
|
||||
* @see Jwts.KEY
|
||||
*/
|
||||
<K extends Key> JwtBuilder encryptWith(K key, KeyAlgorithm<? super K, ?> keyAlg, AeadAlgorithm enc);
|
||||
|
||||
/**
|
||||
* Compresses the JWT payload using the specified {@link CompressionCodec}.
|
||||
* Compresses the JWT payload using the specified {@link CompressionAlgorithm}.
|
||||
*
|
||||
* <p>If your compact JWTs are large, and you want to reduce their total size during network transmission, this
|
||||
* can be useful. For example, when embedding JWTs in URLs, some browsers may not support URLs longer than a
|
||||
|
@ -809,12 +820,12 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* <p>Compression when creating JWE tokens however should be universally accepted for any
|
||||
* library that supports JWE.</p>
|
||||
*
|
||||
* @param codec implementation of the {@link CompressionCodec} to be used.
|
||||
* @param alg implementation of the {@link CompressionAlgorithm} to be used.
|
||||
* @return the builder for method chaining.
|
||||
* @see io.jsonwebtoken.CompressionCodecs
|
||||
* @since 0.6.0
|
||||
* @see Jwts.ZIP
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
JwtBuilder compressWith(CompressionCodec codec);
|
||||
JwtBuilder compressWith(CompressionAlgorithm alg);
|
||||
|
||||
/**
|
||||
* Perform Base64Url encoding with the specified Encoder.
|
||||
|
@ -850,4 +861,21 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
|||
* @return A compact URL-safe JWT string.
|
||||
*/
|
||||
String compact();
|
||||
|
||||
/**
|
||||
* Editable header for use with a {@link JwtBuilder} that supports method chaining for any/all
|
||||
* 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> {
|
||||
|
||||
/**
|
||||
* Returns the associated JwtBuilder for continued configuration.
|
||||
*
|
||||
* @return the associated JwtBuilder for continued configuration.
|
||||
*/
|
||||
JwtBuilder and();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public interface JwtHandler<T> {
|
|||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
* an Unprotected content JWT. An Unprotected content JWT has a byte array payload that is not
|
||||
* an unprotected content JWT. An unprotected content JWT has a byte array payload that is not
|
||||
* cryptographically signed or encrypted. If the JWT creator set the (optional)
|
||||
* {@link Header#getContentType() contentType} header value, the application may inspect that value to determine
|
||||
* how to convert the byte array to the final content type as desired.
|
||||
|
@ -34,7 +34,7 @@ public interface JwtHandler<T> {
|
|||
* @param jwt the parsed Unprotected content JWT
|
||||
* @return any object to be used after inspecting the JWT, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
T onContentJwt(Jwt<UnprotectedHeader, byte[]> jwt);
|
||||
T onContentJwt(Jwt<Header, byte[]> jwt);
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
|
@ -43,7 +43,7 @@ public interface JwtHandler<T> {
|
|||
* @param jwt the parsed claims JWT
|
||||
* @return any object to be used after inspecting the JWT, or {@code null} if no return value is necessary.
|
||||
*/
|
||||
T onClaimsJwt(Jwt<UnprotectedHeader, Claims> jwt);
|
||||
T onClaimsJwt(Jwt<Header, Claims> jwt);
|
||||
|
||||
/**
|
||||
* This method is invoked when a {@link io.jsonwebtoken.JwtParser JwtParser} determines that the parsed JWT is
|
||||
|
|
|
@ -31,12 +31,12 @@ package io.jsonwebtoken;
|
|||
public abstract class JwtHandlerAdapter<T> implements JwtHandler<T> {
|
||||
|
||||
@Override
|
||||
public T onContentJwt(Jwt<UnprotectedHeader, byte[]> jwt) {
|
||||
public T onContentJwt(Jwt<Header, byte[]> jwt) {
|
||||
throw new UnsupportedJwtException("Unprotected content JWTs are not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T onClaimsJwt(Jwt<UnprotectedHeader, Claims> jwt) {
|
||||
public T onClaimsJwt(Jwt<Header, Claims> jwt) {
|
||||
throw new UnsupportedJwtException("Unprotected Claims JWTs are not supported.");
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import io.jsonwebtoken.security.SecurityException;
|
|||
import io.jsonwebtoken.security.SignatureException;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -344,18 +345,17 @@ public interface JwtParser {
|
|||
*
|
||||
* <p><b>Default Support</b></p>
|
||||
*
|
||||
* <p>JJWT's default {@link JwtParser} implementation supports both the
|
||||
* {@link CompressionCodecs#DEFLATE DEFLATE}
|
||||
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
|
||||
* <p>JJWT's default {@link JwtParser} implementation supports both the {@link Jwts.ZIP#DEF DEFLATE}
|
||||
* and {@link Jwts.ZIP#GZIP GZIP} algorithms by default - you do not need to
|
||||
* specify a {@code CompressionCodecResolver} in these cases.</p>
|
||||
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement
|
||||
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you may implement
|
||||
* your own {@link CompressionCodecResolver} and specify that via this method and also when
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} JWTs.</p>
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(io.jsonwebtoken.io.CompressionAlgorithm) building} JWTs.</p>
|
||||
*
|
||||
* @param compressionCodecResolver the compression codec resolver used to decompress the JWT payload.
|
||||
* @return the parser for method chaining.
|
||||
* @since 0.6.0
|
||||
* @deprecated in favor of {@link JwtParserBuilder#setCompressionCodecLocator(Locator)}.
|
||||
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link JwtParserBuilder#addCompressionAlgorithms(Collection)}.
|
||||
* To construct a JwtParser use the corresponding builder via {@link Jwts#parserBuilder()}. This will construct an
|
||||
* immutable JwtParser.
|
||||
* <p><b>NOTE: this method will be removed before version 1.0</b>
|
||||
|
@ -529,7 +529,7 @@ public interface JwtParser {
|
|||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
Jwt<UnprotectedHeader, byte[]> parseContentJwt(String jwt) throws UnsupportedJwtException, MalformedJwtException,
|
||||
Jwt<Header, byte[]> parseContentJwt(String jwt) throws UnsupportedJwtException, MalformedJwtException,
|
||||
SignatureException, SecurityException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
|
@ -559,7 +559,7 @@ public interface JwtParser {
|
|||
* @see #parse(String)
|
||||
* @since 0.2
|
||||
*/
|
||||
Jwt<UnprotectedHeader, Claims> parseClaimsJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException,
|
||||
Jwt<Header, Claims> parseClaimsJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException,
|
||||
MalformedJwtException, SignatureException, SecurityException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,14 +15,13 @@
|
|||
*/
|
||||
package io.jsonwebtoken;
|
||||
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Deserializer;
|
||||
import io.jsonwebtoken.lang.Builder;
|
||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||
import io.jsonwebtoken.security.SecureDigestAlgorithm;
|
||||
import io.jsonwebtoken.security.StandardKeyAlgorithms;
|
||||
import io.jsonwebtoken.security.StandardSecureDigestAlgorithms;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.Provider;
|
||||
|
@ -57,7 +56,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
* @return the builder for method chaining.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-8.5">Unsecured JWS Security Considerations</a>
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6">Using the Algorithm "none"</a>
|
||||
* @see StandardSecureDigestAlgorithms#NONE
|
||||
* @see Jwts.SIG#NONE
|
||||
* @see #enableUnsecuredDecompression()
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
|
@ -86,7 +85,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-8.5">Unsecured JWS Security Considerations</a>
|
||||
* @see <a href="https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf">In the
|
||||
* Compression Hornet’s Nest: A Security Study of Data Compression in Network Services</a>
|
||||
* @see StandardSecureDigestAlgorithms#NONE
|
||||
* @see Jwts.SIG#NONE
|
||||
* @see #enableUnsecuredJws()
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
|
@ -427,27 +426,24 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
JwtParserBuilder setSigningKeyResolver(SigningKeyResolver signingKeyResolver);
|
||||
|
||||
/**
|
||||
* Adds the specified compression codecs to the parser's total set of supported compression codecs,
|
||||
* overwriting any previously-added compression codecs with the same {@link CompressionCodec#getId() id}s. If the
|
||||
* parser encounters a JWT {@code zip} header value that matches a compression codec's
|
||||
* {@link CompressionCodec#getId() CompressionCodec.getId()}, that codec will be used for decompression.
|
||||
* 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.
|
||||
*
|
||||
* <p>There may be only one registered {@code CompressionCodec} per {@code id}, and the {@code codecs}
|
||||
* collection is added in iteration order; if a duplicate id is found when iterating the {@code codecs}
|
||||
* <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>Finally, {@link CompressionCodecs#DEFLATE} and {@link CompressionCodecs#GZIP} are added last,
|
||||
* <em>after</em> those in the {@code codecs} collection, to ensure that JWA standard algorithms cannot be
|
||||
* <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>This method is a simpler alternative than creating and registering a custom locator via the
|
||||
* {@link #setCompressionCodecLocator(Locator)} method.</p>
|
||||
*
|
||||
* @param codecs collection of compression codecs to add to the parser's total set of supported compression codecs.
|
||||
* @param algs collection of compression algorithms to add to the parser's total set of supported compression algorithms.
|
||||
* @return the builder for method chaining.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
JwtParserBuilder addCompressionCodecs(Collection<? extends CompressionCodec> codecs);
|
||||
JwtParserBuilder addCompressionAlgorithms(Collection<? extends CompressionAlgorithm> algs);
|
||||
|
||||
/**
|
||||
* Adds the specified AEAD encryption algorithms to the parser's total set of supported encryption algorithms,
|
||||
|
@ -457,7 +453,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
* 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>Finally, the {@link Jwts#ENC JWA standard encryption algorithms} are added last,
|
||||
* <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>
|
||||
*
|
||||
|
@ -478,7 +474,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
* {@code sigAlgs} collection, the later element will evict any previously-added algorithm with the same
|
||||
* {@code id}.</p>
|
||||
*
|
||||
* <p>Finally, the {@link Jwts#SIG JWA standard signature and MAC algorithms} are
|
||||
* <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>
|
||||
*
|
||||
|
@ -497,7 +493,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
* 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>Finally, the {@link StandardKeyAlgorithms#values() JWA standard key management algorithms}
|
||||
* <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>
|
||||
*
|
||||
|
@ -509,70 +505,35 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
|||
JwtParserBuilder addKeyAlgorithms(Collection<? extends KeyAlgorithm<?, ?>> keyAlgs);
|
||||
|
||||
/**
|
||||
* <p><b>Deprecated as of JJWT JJWT_RELEASE_VERSION. This method will be removed before the 1.0 release.</b></p>
|
||||
*
|
||||
* <p>This method has been deprecated as of JJWT version JJWT_RELEASE_VERSION because it imposed unnecessary
|
||||
* implementation requirements on application developers when simply adding to a compression algorithm collection
|
||||
* would suffice. Use the {@link #addCompressionAlgorithms(Collection)} method instead to add
|
||||
* any custom algorithm implementations without needing to also implement a Locator implementation.</p>
|
||||
*
|
||||
* <p><b>Previous Documentation</b></p>
|
||||
* <p>
|
||||
* Sets the {@link CompressionCodecResolver} used to acquire the {@link CompressionCodec} that should be used to
|
||||
* decompress the JWT body. If the parsed JWT is not compressed, this resolver is not used.
|
||||
*
|
||||
* <p><b>NOTE:</b> Compression is not defined by the JWS Specification - only the JWE Specification - and it is
|
||||
* <p><b>WARNING:</b> Compression is not defined by the JWS Specification - only the JWE Specification - and it is
|
||||
* not expected that other libraries (including JJWT versions < 0.6.0) are able to consume a compressed JWS
|
||||
* body correctly. This method is only useful if the compact JWS was compressed with JJWT >= 0.6.0 or
|
||||
* another library that you know implements the same behavior.</p>
|
||||
* body correctly.</p>
|
||||
*
|
||||
* <p><b>Default Support</b></p>
|
||||
*
|
||||
* <p>JJWT's default {@link JwtParser} implementation supports both the
|
||||
* {@link CompressionCodecs#DEFLATE DEFLATE}
|
||||
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
|
||||
* <p>JJWT's default {@link JwtParser} implementation supports both the {@link Jwts.ZIP#DEF DEF}
|
||||
* and {@link Jwts.ZIP#GZIP GZIP} algorithms by default - you do not need to
|
||||
* specify a {@code CompressionCodecResolver} in these cases.</p>
|
||||
*
|
||||
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must
|
||||
* implement your own {@link CompressionCodecResolver} and specify that via this method and also when
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} JWTs.</p>
|
||||
*
|
||||
* @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 #setCompressionCodecLocator(Locator)} to use the
|
||||
* congruent {@code Locator} concept used elsewhere (such as {@link #setKeyLocator(Locator)}).
|
||||
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #addCompressionAlgorithms(Collection)}.
|
||||
*/
|
||||
@Deprecated
|
||||
JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver);
|
||||
|
||||
/**
|
||||
* Sets the {@link CompressionCodec} {@code Locator} used to acquire the {@code CompressionCodec} that should be
|
||||
* used to decompress the JWT body.
|
||||
*
|
||||
* <p><b>NOTE:</b> Compression is not defined by the JWS Specification - only the JWE Specification - and it is
|
||||
* not expected that other libraries (including JJWT versions < 0.6.0) are able to consume a compressed JWS
|
||||
* body correctly. This method is only useful if the compact JWS was compressed with JJWT >= 0.6.0 or
|
||||
* another library that you know implements the same behavior.</p>
|
||||
*
|
||||
* <p><b>Simple Registration</b></p>
|
||||
*
|
||||
* <p>If a CompressionCodec can be resolved in the JWT Header via a simple {@code zip} header value lookup, it is
|
||||
* recommended to call the {@link #addCompressionCodecs(Collection)} method instead of this one. That method
|
||||
* will add the codec to the total set of supported codecs and lookup will achieved by matching the
|
||||
* {@link CompressionCodec#getId() CompressionCodec.getId()} against the {@code zip} header value automatically.</p>
|
||||
*
|
||||
* <p>You only need to call this method with a custom locator if compression codec lookup cannot be based on the
|
||||
* {@code zip} header value.</p>
|
||||
*
|
||||
* <p><b>Default Support</b></p>
|
||||
*
|
||||
* <p>JJWT's default {@link JwtParser} implementation supports both the
|
||||
* {@link CompressionCodecs#DEFLATE DEFLATE}
|
||||
* and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
|
||||
* specify a {@code CompressionCodec} {@link Locator} in these cases.</p>
|
||||
*
|
||||
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, and
|
||||
* {@link #addCompressionCodecs(Collection)} is not sufficient, you must
|
||||
* implement your own {@code CompressionCodec} {@link Locator} and specify that via this method and also when
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionCodec) building} JWTs.</p>
|
||||
*
|
||||
* @param locator the compression codec locator used to decompress the JWT body.
|
||||
* @return the parser builder for method chaining.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
JwtParserBuilder setCompressionCodecLocator(Locator<CompressionCodec> locator);
|
||||
|
||||
/**
|
||||
* Perform Base64Url decoding with the specified Decoder
|
||||
*
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -37,5 +37,5 @@ public interface Locator<T> {
|
|||
* {@link JweHeader} depending on if the respective JWT is an unprotected JWT, JWS or JWE.
|
||||
* @return an object referenced in the specified {@code header}, or {@code null} if the object couldn't be found.
|
||||
*/
|
||||
T locate(Header<?> header);
|
||||
T locate(Header header);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import io.jsonwebtoken.lang.Assert;
|
|||
|
||||
/**
|
||||
* Adapter pattern implementation for the {@link Locator} interface. Subclasses can override any of the
|
||||
* {@link #locate(UnprotectedHeader)}, {@link #locate(ProtectedHeader)}, {@link #locate(JwsHeader)}, or
|
||||
* {@link #doLocate(Header)}, {@link #locate(ProtectedHeader)}, {@link #locate(JwsHeader)}, or
|
||||
* {@link #locate(JweHeader)} methods for type-specific logic if desired when the encountered header is an
|
||||
* unprotected JWT, or an integrity-protected JWT (either a JWS or JWE).
|
||||
*
|
||||
|
@ -34,25 +34,23 @@ public abstract class LocatorAdapter<T> implements Locator<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Inspects the specified header, and delegates to the {@link #locate(UnprotectedHeader)} method if the header
|
||||
* is an {@link UnprotectedHeader} or the {@link #locate(ProtectedHeader)} method if the header is either a
|
||||
* {@link JwsHeader} or {@link JweHeader}.
|
||||
* Inspects the specified header, and delegates to the {@link #locate(ProtectedHeader)} method if the header
|
||||
* is protected (either a {@link JwsHeader} or {@link JweHeader}), or the {@link #doLocate(Header)} method
|
||||
* if the header is not integrity protected.
|
||||
*
|
||||
* @param header the JWT header to inspect; may be an instance of {@link UnprotectedHeader}, {@link JwsHeader} or
|
||||
* @param header the JWT header to inspect; may be an instance of {@link Header}, {@link JwsHeader}, or
|
||||
* {@link JweHeader} depending on if the respective JWT is an unprotected JWT, JWS or JWE.
|
||||
* @return an object referenced in the specified header, or {@code null} if the referenced object cannot be found
|
||||
* or does not exist.
|
||||
*/
|
||||
@Override
|
||||
public final T locate(Header<?> header) {
|
||||
public final T locate(Header header) {
|
||||
Assert.notNull(header, "Header cannot be null.");
|
||||
if (header instanceof ProtectedHeader<?>) {
|
||||
ProtectedHeader<?> protectedHeader = (ProtectedHeader<?>) header;
|
||||
if (header instanceof ProtectedHeader) {
|
||||
ProtectedHeader protectedHeader = (ProtectedHeader) header;
|
||||
return locate(protectedHeader);
|
||||
} else {
|
||||
Assert.isInstanceOf(UnprotectedHeader.class, header, "Unrecognized Header type.");
|
||||
return locate((UnprotectedHeader) header);
|
||||
}
|
||||
return doLocate(header);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +63,7 @@ public abstract class LocatorAdapter<T> implements Locator<T> {
|
|||
* @return an object referenced in the specified {@link ProtectedHeader}, or {@code null} if the referenced
|
||||
* object cannot be found or does not exist.
|
||||
*/
|
||||
protected T locate(ProtectedHeader<?> header) {
|
||||
protected T locate(ProtectedHeader header) {
|
||||
if (header instanceof JwsHeader) {
|
||||
return locate((JwsHeader) header);
|
||||
} else {
|
||||
|
@ -99,14 +97,15 @@ public abstract class LocatorAdapter<T> implements Locator<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an object referenced in the specified Unprotected JWT header, or {@code null} if the referenced
|
||||
* Returns an object referenced in the specified unprotected JWT header, or {@code null} if the referenced
|
||||
* object cannot be found or does not exist. Default implementation simply returns {@code null}.
|
||||
*
|
||||
* @param header the header of an encountered JWE.
|
||||
* @return an object referenced in the specified Unprotected JWT header, or {@code null} if the referenced
|
||||
* @param header the header of an encountered JWT.
|
||||
* @return an object referenced in the specified unprotected JWT header, or {@code null} if the referenced
|
||||
* object cannot be found or does not exist.
|
||||
*/
|
||||
protected T locate(UnprotectedHeader header) {
|
||||
@SuppressWarnings("unused")
|
||||
protected T doLocate(Header header) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class MissingClaimException extends InvalidClaimException {
|
|||
* @param claimValue the value of the claim that could not be validated
|
||||
* @param message the message explaining why the exception is thrown.
|
||||
*/
|
||||
public MissingClaimException(Header<?> header, Claims claims, String claimName, Object claimValue, String message) {
|
||||
public MissingClaimException(Header header, Claims claims, String claimName, Object claimValue, String message) {
|
||||
super(header, claims, claimName, claimValue, message);
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,10 @@ public class MissingClaimException extends InvalidClaimException {
|
|||
* @param claimValue the value of the claim that could not be validated
|
||||
* @param message the message explaining why the exception is thrown.
|
||||
* @param cause the underlying cause that resulted in this exception being thrown.
|
||||
* @deprecated since JJWT_RELEASE_VERSION since it is not used in JJWT's codebase
|
||||
*/
|
||||
public MissingClaimException(Header<?> header, Claims claims, String claimName, Object claimValue, String message, Throwable cause) {
|
||||
@Deprecated
|
||||
public MissingClaimException(Header header, Claims claims, String claimName, Object claimValue, String message, Throwable cause) {
|
||||
super(header, claims, claimName, claimValue, message, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class PrematureJwtException extends ClaimJwtException {
|
|||
* @param claims jwt claims (body)
|
||||
* @param message the message explaining why the exception is thrown.
|
||||
*/
|
||||
public PrematureJwtException(Header<?> header, Claims claims, String message) {
|
||||
public PrematureJwtException(Header header, Claims claims, String message) {
|
||||
super(header, claims, message);
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,10 @@ public class PrematureJwtException extends ClaimJwtException {
|
|||
* @param message exception message
|
||||
* @param cause cause
|
||||
* @since 0.5
|
||||
* @deprecated since JJWT_RELEASE_VERSION since it is not used in JJWT's codebase
|
||||
*/
|
||||
public PrematureJwtException(Header<?> header, Claims claims, String message, Throwable cause) {
|
||||
@Deprecated
|
||||
public PrematureJwtException(Header header, Claims claims, String message, Throwable cause) {
|
||||
super(header, claims, message, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,11 @@ import java.util.Set;
|
|||
/**
|
||||
* A JWT header that is integrity protected, either by JWS digital signature or JWE AEAD encryption.
|
||||
*
|
||||
* @param <T> The exact header subtype returned during mutation (setter) operations.
|
||||
* @see JwsHeader
|
||||
* @see JweHeader
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface ProtectedHeader<T extends ProtectedHeader<T>> extends Header<T>, ProtectedHeaderMutator<T>, X509Accessor {
|
||||
public interface ProtectedHeader extends Header, X509Accessor {
|
||||
|
||||
/**
|
||||
* Returns the {@code jku} (JWK Set URL) value that refers to a
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import io.jsonwebtoken.security.DigestSupplier;
|
||||
|
||||
/**
|
||||
* A {@code ProtectedJwt} is a {@link Jwt} that is integrity protected via a cryptographic algorithm that produces
|
||||
* a cryptographic digest, such as a MAC, Digital Signature or Authentication Tag.
|
||||
*
|
||||
* <p><b>Cryptographic Digest</b></p>
|
||||
* <p>This interface extends DigestSupplier to make available the {@code ProtectedJwt}'s associated cryptographic
|
||||
* digest:</p>
|
||||
* <ul>
|
||||
* <li>If the JWT is a {@link Jws}, {@link #getDigest() getDigest() } returns the JWS signature.</li>
|
||||
* <li>If the JWT is a {@link Jwe}, {@link #getDigest() getDigest() } returns the AAD Authentication Tag.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <H> the type of the JWT protected header
|
||||
* @param <P> the type of the JWT payload, either a content byte array or a {@link Claims} instance.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface ProtectedJwt<H extends ProtectedHeader, P> extends Jwt<H, P>, DigestSupplier {
|
||||
}
|
|
@ -18,7 +18,6 @@ package io.jsonwebtoken;
|
|||
import io.jsonwebtoken.security.InvalidKeyException;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
import io.jsonwebtoken.security.StandardSecureDigestAlgorithms;
|
||||
import io.jsonwebtoken.security.WeakKeyException;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
@ -35,7 +34,7 @@ import java.util.List;
|
|||
* <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31">JSON Web Algorithms</a> specification.
|
||||
*
|
||||
* @since 0.1
|
||||
* @deprecated since JJWT_RELEASE_VERSION; use {@link StandardSecureDigestAlgorithms} instead.
|
||||
* @deprecated since JJWT_RELEASE_VERSION; use {@link Jwts.SIG} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum SignatureAlgorithm {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.io;
|
||||
|
||||
import io.jsonwebtoken.CompressionException;
|
||||
import io.jsonwebtoken.Identifiable;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Compresses and decompresses byte arrays.
|
||||
*
|
||||
* <p><b>"zip" identifier</b></p>
|
||||
*
|
||||
* <p>{@code CompressionAlgorithm} extends {@code Identifiable}; the value returned from
|
||||
* {@link Identifiable#getId() getId()} will be used as the JWT
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3"><code>zip</code></a> header value.</p>
|
||||
*
|
||||
* <p><b>Custom Implementations</b></p>
|
||||
* <p>A custom implementation of this interface may be used when creating a JWT by calling the
|
||||
* {@link io.jsonwebtoken.JwtBuilder#compressWith(CompressionAlgorithm)} method. To ensure that parsing is
|
||||
* possible, the parser must be aware of the implementation by calling
|
||||
* {@link io.jsonwebtoken.JwtParserBuilder#addCompressionAlgorithms(Collection)} during parser construction.</p>
|
||||
*
|
||||
* @see Jwts.ZIP#DEF
|
||||
* @see Jwts.ZIP#GZIP
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-7.3">JSON Web Encryption Compression Algorithms Registry</a>
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface CompressionAlgorithm extends Identifiable {
|
||||
|
||||
/**
|
||||
* Compresses the specified byte array, returning the compressed byte array result.
|
||||
*
|
||||
* @param content bytes to compress
|
||||
* @return compressed bytes
|
||||
* @throws CompressionException if the specified byte array cannot be compressed.
|
||||
*/
|
||||
byte[] compress(byte[] content) throws CompressionException;
|
||||
|
||||
/**
|
||||
* Decompresses the specified compressed byte array, returning the decompressed byte array result. The
|
||||
* specified byte array must already be in compressed form.
|
||||
*
|
||||
* @param compressed compressed bytes
|
||||
* @return decompressed bytes
|
||||
* @throws CompressionException if the specified byte array cannot be decompressed.
|
||||
*/
|
||||
byte[] decompress(byte[] compressed) throws CompressionException;
|
||||
}
|
|
@ -495,6 +495,8 @@ public final class Assert {
|
|||
*
|
||||
* @param value value to assert is not null
|
||||
* @param msg exception message to use if {@code value} is null
|
||||
* @param <T> value type
|
||||
* @return the non-null value
|
||||
* @throws IllegalStateException with the specified {@code msg} if {@code value} is null.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
|
|
|
@ -18,7 +18,7 @@ package io.jsonwebtoken.lang;
|
|||
/**
|
||||
* Type-safe interface that reflects the <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder pattern</a>.
|
||||
*
|
||||
* @param <T> The type of object that will be created each time {@link #build()} is invoked.
|
||||
* @param <T> The type of object that will be created when {@link #build()} is invoked.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface Builder<T> {
|
||||
|
|
|
@ -29,37 +29,45 @@ import java.util.Map;
|
|||
*/
|
||||
public interface MapMutator<K, V, T extends MapMutator<K, V, T>> {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* method chaining.</p>
|
||||
*
|
||||
* @return the mutator/builder for method chaining.
|
||||
*/
|
||||
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.
|
||||
* <p>This method is the same as {@link Map#put Map.put}, but instead returns the mutator instance for
|
||||
* method chaining.</p>
|
||||
*
|
||||
* @param key the map key
|
||||
* @param value the value to set for the specified header parameter name
|
||||
* @return the mutator/builder for method chaining.
|
||||
*/
|
||||
T put(K key, V value);
|
||||
|
||||
/**
|
||||
* Removes the map entry with the specified key
|
||||
*
|
||||
* @param key the key for the map entry to remove.
|
||||
* @return the mutator/builder for method chaining.
|
||||
*/
|
||||
T remove(K key);
|
||||
T set(K key, V value);
|
||||
|
||||
/**
|
||||
* Sets the specified name/value pairs in the map. If any name has a {@code null} or empty value, that
|
||||
* map entry will be removed from the map entirely.
|
||||
* <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 putAll(Map<? extends K, ? extends V> m);
|
||||
T set(Map<? extends K, ? extends V> m);
|
||||
|
||||
/**
|
||||
* Removes all entries from the map. The map will be empty after this call returns.
|
||||
* 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 clear();
|
||||
T delete(K key);
|
||||
}
|
||||
|
|
|
@ -15,41 +15,37 @@
|
|||
*/
|
||||
package io.jsonwebtoken.lang;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An immutable read-only repository of key-value pairs.
|
||||
* An immutable (read-only) repository of key-value pairs. In addition to {@link Map} read methods, this interface also
|
||||
* provides guaranteed/expected lookup via the {@link #forKey(Object)} method.
|
||||
*
|
||||
* <p><b>Immutability</b></p>
|
||||
*
|
||||
* <p>Registries are immutable and cannot be changed. {@code Registry} extends the
|
||||
* {@link Map} interface purely out of convenience: to allow easy key/value
|
||||
* pair access and iteration, and other conveniences provided by the Map interface, as well as for seamless use with
|
||||
* existing Map-based APIs. Attempting to call any of
|
||||
* the {@link Map} interface's mutation methods however (such as {@link Map#put(Object, Object) put},
|
||||
* {@link Map#remove(Object) remove}, {@link Map#clear() clear}, etc) will throw an
|
||||
* {@link UnsupportedOperationException}.</p>
|
||||
*
|
||||
* @param <K> key type
|
||||
* @param <V> value type
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface Registry<K, V> {
|
||||
|
||||
/**
|
||||
* Returns all registry values as a read-only collection.
|
||||
*
|
||||
* @return all registry values as a read-only collection.
|
||||
*/
|
||||
Collection<V> values();
|
||||
public interface Registry<K, V> extends Map<K, V> {
|
||||
|
||||
/**
|
||||
* Returns the value assigned the specified key or throws an {@code IllegalArgumentException} if there is no
|
||||
* associated value. If a value is not required, consider using the {@link #find(Object)} method instead.
|
||||
* associated value. If a value is not required, consider using the {@link #get(Object)} method instead.
|
||||
*
|
||||
* @param key the registry key assigned to the required value
|
||||
* @return the value assigned the specified key
|
||||
* @throws IllegalArgumentException if there is no value assigned the specified key
|
||||
* @see #find(Object)
|
||||
*/
|
||||
V get(K key) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns the value assigned the specified key or {@code null} if there is no associated value.
|
||||
*
|
||||
* @param key the registry key assigned to the required value
|
||||
* @return the value assigned the specified key or {@code null} if there is no associated value.
|
||||
* @see #get(Object)
|
||||
*/
|
||||
V find(K key);
|
||||
V forKey(K key) throws IllegalArgumentException;
|
||||
|
||||
}
|
||||
|
|
|
@ -231,6 +231,32 @@ public final class Strings {
|
|||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified string's UTF-8 bytes, or {@code null} if the string is {@code null}.
|
||||
*
|
||||
* @param s the string to obtain UTF-8 bytes
|
||||
* @return the specified string's UTF-8 bytes, or {@code null} if the string is {@code null}.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public static byte[] utf8(String s) {
|
||||
byte[] bytes = null;
|
||||
if (s != null) {
|
||||
bytes = s.getBytes(UTF_8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code new String(utf8Bytes, StandardCharsets.UTF_8)}.
|
||||
*
|
||||
* @param utf8Bytes UTF-8 bytes to use with the {@code String} constructor.
|
||||
* @return {@code new String(utf8Bytes, StandardCharsets.UTF_8)}.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public static String utf8(byte[] utf8Bytes) {
|
||||
return new String(utf8Bytes, UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation (1s and 0s) of the specified byte.
|
||||
*
|
||||
|
@ -1281,6 +1307,7 @@ public final class Strings {
|
|||
* <p>To this:</p>
|
||||
* <blockquote><pre>
|
||||
* nespace(sb).append(nextWord);</pre></blockquote>
|
||||
*
|
||||
* @param sb the string builder to append a space to if non-empty
|
||||
* @return the string builder argument for method chaining.
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
|
|
|
@ -26,7 +26,7 @@ import javax.crypto.SecretKey;
|
|||
* Per <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.2">JWE RFC 7516, Section 4.1.2</a>, all JWEs
|
||||
* <em>MUST</em> use an AEAD algorithm to encrypt or decrypt the JWE payload/content. Consequently, all
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">JWA "enc" algorithms</a> are AEAD
|
||||
* algorithms, and they are accessible as concrete instances via {@link Jwts#ENC}.
|
||||
* algorithms, and they are accessible as concrete instances via {@link Jwts.ENC}.
|
||||
*
|
||||
* <p><b>"enc" identifier</b></p>
|
||||
*
|
||||
|
@ -57,7 +57,7 @@ import javax.crypto.SecretKey;
|
|||
* <p>The resulting {@code key} is guaranteed to have the correct algorithm parameters and strength/length necessary for
|
||||
* that exact {@code aeadAlgorithm} instance.</p>
|
||||
*
|
||||
* @see Jwts#ENC
|
||||
* @see Jwts.ENC
|
||||
* @see Identifiable#getId()
|
||||
* @see KeyLengthSupplier
|
||||
* @see KeyBuilderSupplier
|
||||
|
|
|
@ -40,18 +40,18 @@ import java.security.PublicKey;
|
|||
* <tbody>
|
||||
* <tr>
|
||||
* <td>{@link HashAlgorithm}</td>
|
||||
* <td>{@link StandardHashAlgorithms}</td>
|
||||
* <td>{@link Jwks.HASH}</td>
|
||||
* <td>Unsecured (unkeyed), does not require a key to compute or verify digests.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link MacAlgorithm}</td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms}</td>
|
||||
* <td>{@link io.jsonwebtoken.Jwts.SIG Jwts.SIG}</td>
|
||||
* <td>Requires a {@link SecretKey} to both compute and verify digests (aka
|
||||
* "Message Authentication Codes").</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link SignatureAlgorithm}</td>
|
||||
* <td>{@link StandardSecureDigestAlgorithms}</td>
|
||||
* <td>{@link io.jsonwebtoken.Jwts.SIG Jwts.SIG}</td>
|
||||
* <td>Requires a {@link PrivateKey} to compute and {@link PublicKey} to verify digests
|
||||
* (aka "Digital Signatures").</td>
|
||||
* </tr>
|
||||
|
@ -71,8 +71,8 @@ import java.security.PublicKey;
|
|||
*
|
||||
* @param <R> the type of {@link Request} used when computing a digest.
|
||||
* @param <V> the type of {@link VerifyDigestRequest} used when verifying a digest.
|
||||
* @see StandardHashAlgorithms
|
||||
* @see StandardSecureDigestAlgorithms
|
||||
* @see Jwks.HASH
|
||||
* @see io.jsonwebtoken.Jwts.SIG Jwts.SIG
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface DigestAlgorithm<R extends Request<byte[]>, V extends VerifyDigestRequest> extends Identifiable {
|
||||
|
|
|
@ -34,9 +34,9 @@ import io.jsonwebtoken.Identifiable;
|
|||
*
|
||||
* <p>Constant definitions and utility methods for common (<em>but not all</em>)
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> are available via the {@link StandardHashAlgorithms} singleton.</p>
|
||||
* Algorithms</a> are available via {@link Jwks.HASH}.</p>
|
||||
*
|
||||
* @see StandardHashAlgorithms
|
||||
* @see Jwks.HASH
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface HashAlgorithm extends DigestAlgorithm<Request<byte[]>, VerifyDigestRequest> {
|
||||
|
|
|
@ -82,10 +82,10 @@ public interface JwkBuilder<K extends Key, J extends Jwk<K>, T extends JwkBuilde
|
|||
/**
|
||||
* Sets the JWK's {@link #setId(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 StandardHashAlgorithms#SHA256 SHA256}).{@link JwkThumbprint#toString() toString()}</code>.
|
||||
* <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
|
||||
* {@link Jwks#HASH}{@code .}{@link StandardHashAlgorithms#SHA256 SHA256}.</p>
|
||||
* {@link Jwks.HASH}{@code .}{@link Jwks.HASH#SHA256 SHA256}.</p>
|
||||
*
|
||||
* @return the builder for method chaining.
|
||||
*/
|
||||
|
@ -99,7 +99,7 @@ public interface JwkBuilder<K extends Key, J extends Jwk<K>, T extends JwkBuilde
|
|||
*
|
||||
* @param alg the hash algorithm to use to compute the thumbprint.
|
||||
* @return the builder for method chaining.
|
||||
* @see StandardHashAlgorithms
|
||||
* @see Jwks.HASH
|
||||
*/
|
||||
T setIdFromThumbprint(HashAlgorithm alg);
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
import io.jsonwebtoken.Identifiable;
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
/**
|
||||
* Utility methods for creating
|
||||
|
@ -25,10 +27,10 @@ import io.jsonwebtoken.lang.Classes;
|
|||
* <p>Standard <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> commonly used to compute {@link JwkThumbprint JWK Thumbprint}s and ensure valid
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9278#name-hash-algorithms-identifier">JWK Thumbprint URIs</a>
|
||||
* are available via the {@link #HASH} registry constant to allow for easy code-completion in IDEs. For example, when
|
||||
* are available via the {@link Jwks.HASH} registry constants to allow for easy code-completion in IDEs. For example, when
|
||||
* typing:</p>
|
||||
* <blockquote><pre>
|
||||
* Jwts.{@link #HASH}.// press hotkeys to suggest individual hash algorithms or utility methods</pre></blockquote>
|
||||
* Jwks.{@link Jwks.HASH HASH}.// press hotkeys to suggest individual hash algorithms or utility methods</pre></blockquote>
|
||||
*
|
||||
* @see #builder()
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
|
@ -43,27 +45,107 @@ public final class Jwks {
|
|||
private static final String PARSERBUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultJwkParserBuilder";
|
||||
|
||||
/**
|
||||
* Registry of various (<em>but not all</em>)
|
||||
* Various (<em>but not all</em>)
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> commonly used to compute {@link JwkThumbprint JWK Thumbprint}s and ensure valid
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9278#name-hash-algorithms-identifier">JWK Thumbprint URIs</a>. For
|
||||
* example:
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9278#name-hash-algorithms-identifier">JWK Thumbprint URIs</a>.
|
||||
* Each algorithm is made available as a ({@code public static final}) constant for direct type-safe
|
||||
* reference in application code. For example:
|
||||
* <blockquote><pre>
|
||||
* Jwks.{@link Jwks#builder}()
|
||||
* // ... etc ...
|
||||
* .{@link JwkBuilder#setIdFromThumbprint(HashAlgorithm) setIdFromThumbprint}(Jwts.HASH.{@link StandardHashAlgorithms#SHA256 SHA256}) // <---
|
||||
* .{@link JwkBuilder#setIdFromThumbprint(HashAlgorithm) setIdFromThumbprint}(Jwts.HASH.{@link Jwks.HASH#SHA256 SHA256}) // <---
|
||||
* .build()</pre></blockquote>
|
||||
* <p>or</p>
|
||||
* <blockquote><pre>
|
||||
* HashAlgorithm hashAlg = Jwks.HASH.{@link StandardHashAlgorithms#SHA256 SHA256};
|
||||
* HashAlgorithm hashAlg = Jwks.HASH.{@link Jwks.HASH#SHA256 SHA256};
|
||||
* {@link JwkThumbprint} thumbprint = aJwk.{@link Jwk#thumbprint(HashAlgorithm) thumbprint}(hashAlg);
|
||||
* String <a href="https://www.rfc-editor.org/rfc/rfc9278#section-3">rfcMandatoryPrefix</a> = "urn:ietf:params:oauth:jwk-thumbprint:" + hashAlg.getId();
|
||||
* assert thumbprint.toURI().toString().startsWith(rfcMandatoryPrefix);
|
||||
* </pre></blockquote>
|
||||
* <p>They are also available together as a {@link Registry} instance via the {@link #get()} method.</p>
|
||||
*
|
||||
* @see #get()
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public static final StandardHashAlgorithms HASH = StandardHashAlgorithms.get();
|
||||
public static final class HASH {
|
||||
|
||||
private static final String IMPL_CLASSNAME = "io.jsonwebtoken.impl.security.StandardHashAlgorithms";
|
||||
private static final Registry<String, HashAlgorithm> REGISTRY = Classes.newInstance(IMPL_CLASSNAME);
|
||||
|
||||
/**
|
||||
* Returns a registry of various (<em>but not all</em>)
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> commonly used to compute {@link JwkThumbprint JWK Thumbprint}s and ensure valid
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9278#name-hash-algorithms-identifier">JWK Thumbprint URIs</a>.
|
||||
*
|
||||
* @return a registry of various (<em>but not all</em>)
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> commonly used to compute {@link JwkThumbprint JWK Thumbprint}s and ensure valid
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9278#name-hash-algorithms-identifier">JWK Thumbprint URIs</a>.
|
||||
*/
|
||||
public static Registry<String, HashAlgorithm> get() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha-256}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA-256} {@code MessageDigest} algorithm.
|
||||
*/
|
||||
public static final HashAlgorithm SHA256 = get().forKey("sha-256");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha-384}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA-384} {@code MessageDigest} algorithm.
|
||||
*/
|
||||
public static final HashAlgorithm SHA384 = get().forKey("sha-384");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha-512}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA-512} {@code MessageDigest} algorithm.
|
||||
*/
|
||||
public static final HashAlgorithm SHA512 = get().forKey("sha-512");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha3-256}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA3-256} {@code MessageDigest} algorithm.
|
||||
* <p><b>This algorithm requires at least JDK 9 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public static final HashAlgorithm SHA3_256 = get().forKey("sha3-256");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha3-384}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA3-384} {@code MessageDigest} algorithm.
|
||||
* <p><b>This algorithm requires at least JDK 9 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public static final HashAlgorithm SHA3_384 = get().forKey("sha3-384");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha3-512}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA3-512} {@code MessageDigest} algorithm.
|
||||
* <p><b>This algorithm requires at least JDK 9 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public static final HashAlgorithm SHA3_512 = get().forKey("sha3-512");
|
||||
|
||||
//prevent instantiation
|
||||
private HASH() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new JWK builder instance, allowing for type-safe JWK builder coercion based on a provided key or key pair.
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.security.Key;
|
|||
*
|
||||
* <p>All standard Key Algorithms are defined in
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1">JWA (RFC 7518), Section 4.1</a>,
|
||||
* and they are all available as concrete instances via {@link Jwts#KEY}.</p>
|
||||
* and they are all available as concrete instances via {@link Jwts.KEY}.</p>
|
||||
*
|
||||
* <p><b>"alg" identifier</b></p>
|
||||
*
|
||||
|
@ -40,7 +40,7 @@ import java.security.Key;
|
|||
*
|
||||
* @param <E> The type of key to use to obtain the AEAD encryption key
|
||||
* @param <D> The type of key to use to obtain the AEAD decryption key
|
||||
* @see Jwts#KEY
|
||||
* @see Jwts.KEY
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7516#section-2">RFC 7561, Section 2: JWE Key (Management) Algorithms</a>
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
|
|
|
@ -58,8 +58,8 @@ public interface KeyRequest<T> extends Request<T> {
|
|||
AeadAlgorithm getEncryptionAlgorithm();
|
||||
|
||||
/**
|
||||
* Returns the {@link JweHeader} that will be used to construct the final JWE, available for reading or writing
|
||||
* any {@link KeyAlgorithm}-specific information.
|
||||
* Returns the {@link JweHeader} that will be used to construct the final JWE header, available for
|
||||
* reading or writing any {@link KeyAlgorithm}-specific information.
|
||||
*
|
||||
* <p>For an encryption key request, any <em>public</em> information specific to the called {@code KeyAlgorithm}
|
||||
* implementation that is required to be transmitted in the JWE (such as an initialization vector,
|
||||
|
@ -71,8 +71,8 @@ public interface KeyRequest<T> extends Request<T> {
|
|||
* (such as an initialization vector, authentication tag, ephemeral key, etc) is expected to be available in
|
||||
* this header.</p>
|
||||
*
|
||||
* @return the {@link JweHeader} that will be used to construct the final JWE, available for reading or writing
|
||||
* any {@link KeyAlgorithm}-specific information.
|
||||
* @return the {@link JweHeader} that will be used to construct the final JWE header, available for
|
||||
* reading or writing any {@link KeyAlgorithm}-specific information.
|
||||
*/
|
||||
JweHeader getHeader();
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ 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 StandardSecureDigestAlgorithms.HS256.keyBuilder() method (or HS384.keyBuilder() " +
|
||||
"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 " +
|
||||
"algorithm. See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
|
||||
throw new WeakKeyException(msg);
|
||||
|
@ -81,9 +81,9 @@ public final class Keys {
|
|||
* length for that specific algorithm by calling their {@code keyBuilder()} method directly. For example:</p>
|
||||
*
|
||||
* <pre><code>
|
||||
* {@link StandardSecureDigestAlgorithms#HS256}.keyBuilder().build();
|
||||
* {@link StandardSecureDigestAlgorithms#HS384}.keyBuilder().build();
|
||||
* {@link StandardSecureDigestAlgorithms#HS512}.keyBuilder().build();
|
||||
* {@link Jwts.SIG#HS256}.keyBuilder().build();
|
||||
* {@link Jwts.SIG#HS384}.keyBuilder().build();
|
||||
* {@link Jwts.SIG#HS512}.keyBuilder().build();
|
||||
* </code></pre>
|
||||
*
|
||||
* <p>Call those methods as needed instead of this static {@code secretKeyFor} helper method - the returned
|
||||
|
@ -130,7 +130,7 @@ public final class Keys {
|
|||
@Deprecated
|
||||
public static SecretKey secretKeyFor(io.jsonwebtoken.SignatureAlgorithm alg) throws IllegalArgumentException {
|
||||
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
|
||||
SecureDigestAlgorithm<?, ?> salg = Jwts.SIG.get(alg.name());
|
||||
SecureDigestAlgorithm<?, ?> salg = Jwts.SIG.get().get(alg.name());
|
||||
if (!(salg instanceof MacAlgorithm)) {
|
||||
String msg = "The " + alg.name() + " algorithm does not support shared secret keys.";
|
||||
throw new IllegalArgumentException(msg);
|
||||
|
@ -145,11 +145,11 @@ public final class Keys {
|
|||
* for that specific algorithm by calling their {@code keyPairBuilder()} method directly. For example:</p>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* Jwts.SIG.{@link StandardSecureDigestAlgorithms#RS256 RS256}.keyPairBuilder().build();
|
||||
* Jwts.SIG.{@link StandardSecureDigestAlgorithms#RS384 RS384}.keyPairBuilder().build();
|
||||
* Jwts.SIG.{@link StandardSecureDigestAlgorithms#RS512 RS512}.keyPairBuilder().build();
|
||||
* 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();
|
||||
* ... etc ...
|
||||
* Jwts.SIG.{@link StandardSecureDigestAlgorithms#ES512 ES512}.keyPairBuilder().build();</pre></blockquote>
|
||||
* Jwts.SIG.{@link Jwts.SIG#ES512 ES512}.keyPairBuilder().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
|
||||
|
@ -235,7 +235,7 @@ public final class Keys {
|
|||
@Deprecated
|
||||
public static KeyPair keyPairFor(io.jsonwebtoken.SignatureAlgorithm alg) throws IllegalArgumentException {
|
||||
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
|
||||
SecureDigestAlgorithm<?, ?> salg = Jwts.SIG.get(alg.name());
|
||||
SecureDigestAlgorithm<?, ?> salg = Jwts.SIG.get().get(alg.name());
|
||||
if (!(salg instanceof SignatureAlgorithm)) {
|
||||
String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
|
||||
throw new IllegalArgumentException(msg);
|
||||
|
|
|
@ -55,9 +55,9 @@ import javax.crypto.SecretKey;
|
|||
* <p><b>JWA Standard Implementations</b></p>
|
||||
*
|
||||
* <p>Constant definitions and utility methods for all JWA (RFC 7518) standard MAC algorithms are
|
||||
* available via the {@link StandardSecureDigestAlgorithms} registry singleton.</p>
|
||||
* available via {@link io.jsonwebtoken.Jwts.SIG Jwts.SIG}.</p>
|
||||
*
|
||||
* @see StandardSecureDigestAlgorithms
|
||||
* @see io.jsonwebtoken.Jwts.SIG Jwts.SIG
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface MacAlgorithm extends SecureDigestAlgorithm<SecretKey, SecretKey>,
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.security.PublicKey;
|
|||
* <p><b>JWK Private Key vs Java {@code PrivateKey} differences</b></p>
|
||||
*
|
||||
* <p>Unlike the Java cryptography APIs, the JWK specification requires all public key <em>and</em> private key
|
||||
* properties to be contained within every private JWK. As such, a {@code PrivateJwk} of course represents
|
||||
* properties to be contained within every private JWK. As such, a {@code PrivateJwk} indeed represents
|
||||
* private key fields as its name implies, but it is probably more similar to the Java JCA concept of a
|
||||
* {@link java.security.KeyPair} since it contains everything for both keys.</p>
|
||||
*
|
||||
|
|
|
@ -36,7 +36,7 @@ import java.security.Key;
|
|||
*
|
||||
* <p>Constant definitions and utility methods for all JWA (RFC 7518) standard
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3">Cryptographic Algorithms for Digital Signatures and
|
||||
* MACs</a> are available via the {@link StandardSecureDigestAlgorithms} utility class.</p>
|
||||
* MACs</a> are available via {@link io.jsonwebtoken.Jwts.SIG Jwts.SIG}.</p>
|
||||
*
|
||||
* <p><b>"alg" identifier</b></p>
|
||||
*
|
||||
|
|
|
@ -46,9 +46,9 @@ import java.security.PublicKey;
|
|||
* <p><b>JWA Standard Implementations</b></p>
|
||||
*
|
||||
* <p>Constant definitions and utility methods for all JWA (RFC 7518) standard signature algorithms are
|
||||
* available via the {@link StandardSecureDigestAlgorithms} registry singleton.</p>
|
||||
* available via {@link io.jsonwebtoken.Jwts.SIG Jwts.SIG}.</p>
|
||||
*
|
||||
* @see StandardSecureDigestAlgorithms
|
||||
* @see io.jsonwebtoken.Jwts.SIG Jwts.SIG
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface SignatureAlgorithm extends SecureDigestAlgorithm<PrivateKey, PublicKey>, KeyPairBuilderSupplier {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.security;
|
||||
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* A request to a {@link SignatureAlgorithm} to compute a digital signature or
|
||||
* <a href="https://en.wikipedia.org/wiki/Digital_signature">digital signature</a> or
|
||||
* <a href="https://en.wikipedia.org/wiki/Message_authentication_code">message
|
||||
* authentication code</a>.
|
||||
* <p>The content for signature input will be available via {@link #getPayload()}, and the key used to compute
|
||||
* the signature will be available via {@link #getKey()}.</p>
|
||||
*
|
||||
* @param <K> the type of {@link Key} used to compute a digital signature or message authentication code
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface SignatureRequest<K extends Key> extends SecureRequest<byte[], K> {
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* 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.security;
|
||||
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* {@link Registry} singleton containing all standard JWE
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">Encryption Algorithms</a>
|
||||
* codified in the <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-7.1">
|
||||
* JSON Web Signature and Encryption Algorithms Registry</a>. These are most commonly accessed via the
|
||||
* {@link io.jsonwebtoken.Jwts#ENC} convenience alias when creating a JWE. For example:
|
||||
* <blockquote><pre>
|
||||
* {@link Jwts#builder()}.
|
||||
* // ... etc ...
|
||||
* .encryptWith(secretKey, <b>{@link Jwts#ENC}.A256GCM</b>) // or A128GCM, A192GCM, etc...
|
||||
* .build()</pre></blockquote>
|
||||
* <p>Direct type-safe references as shown above are often better than calling {@link #get(String)} or
|
||||
* {@link #find(String)} which can be susceptible to misspelled or otherwise invalid string values.</p>
|
||||
*
|
||||
* @see #get()
|
||||
* @see #get(String)
|
||||
* @see #find(String)
|
||||
* @see #values()
|
||||
* @see AeadAlgorithm
|
||||
*
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public final class StandardEncryptionAlgorithms implements Registry<String, AeadAlgorithm> {
|
||||
|
||||
private static final Registry<String, AeadAlgorithm> DELEGATE =
|
||||
Classes.newInstance("io.jsonwebtoken.impl.security.StandardEncryptionAlgorithmsBridge");
|
||||
|
||||
private static final StandardEncryptionAlgorithms INSTANCE = new StandardEncryptionAlgorithms();
|
||||
|
||||
/**
|
||||
* Returns this registry (a static singleton).
|
||||
*
|
||||
* @return this registry (a static singleton).
|
||||
*/
|
||||
public static StandardEncryptionAlgorithms get() { // named `get` to mimic java.util.function.Supplier
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code AES_128_CBC_HMAC_SHA_256} authenticated encryption algorithm as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.2.3">RFC 7518, Section 5.2.3</a>. This algorithm
|
||||
* requires a 256-bit (32 byte) key.
|
||||
*/
|
||||
public final AeadAlgorithm A128CBC_HS256 = get("A128CBC-HS256");
|
||||
|
||||
/**
|
||||
* {@code AES_192_CBC_HMAC_SHA_384} authenticated encryption algorithm, as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.2.4">RFC 7518, Section 5.2.4</a>. This algorithm
|
||||
* requires a 384-bit (48 byte) key.
|
||||
*/
|
||||
public final AeadAlgorithm A192CBC_HS384 = get("A192CBC-HS384");
|
||||
|
||||
/**
|
||||
* {@code AES_256_CBC_HMAC_SHA_512} authenticated encryption algorithm, as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.2.5">RFC 7518, Section 5.2.5</a>. This algorithm
|
||||
* requires a 512-bit (64 byte) key.
|
||||
*/
|
||||
public final AeadAlgorithm A256CBC_HS512 = get("A256CBC-HS512");
|
||||
|
||||
/**
|
||||
* "AES GCM using 128-bit key" as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.3">RFC 7518, Section 5.3</a><b><sup>1</sup></b>. This
|
||||
* algorithm requires a 128-bit (16 byte) key.
|
||||
*
|
||||
* <p><b><sup>1</sup></b> Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath. If on Java 7 or earlier, BouncyCastle will be used automatically if found in the runtime
|
||||
* classpath.</p>
|
||||
*/
|
||||
public final AeadAlgorithm A128GCM = get("A128GCM");
|
||||
|
||||
/**
|
||||
* "AES GCM using 192-bit key" as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.3">RFC 7518, Section 5.3</a><b><sup>1</sup></b>. This
|
||||
* algorithm requires a 192-bit (24 byte) key.
|
||||
*
|
||||
* <p><b><sup>1</sup></b> Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath. If on Java 7 or earlier, BouncyCastle will be used automatically if found in the runtime
|
||||
* classpath.</p>
|
||||
*/
|
||||
public final AeadAlgorithm A192GCM = get("A192GCM");
|
||||
|
||||
/**
|
||||
* "AES GCM using 256-bit key" as defined by
|
||||
* <a href="https://tools.ietf.org/html/rfc7518#section-5.3">RFC 7518, Section 5.3</a><b><sup>1</sup></b>. This
|
||||
* algorithm requires a 256-bit (32 byte) key.
|
||||
*
|
||||
* <p><b><sup>1</sup></b> Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath. If on Java 7 or earlier, BouncyCastle will be used automatically if found in the runtime
|
||||
* classpath.</p>
|
||||
*/
|
||||
public final AeadAlgorithm A256GCM = get("A256GCM");
|
||||
|
||||
/**
|
||||
* Prevent external instantiation.
|
||||
*/
|
||||
private StandardEncryptionAlgorithms() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all JWE-standard AEAD encryption algorithms as an unmodifiable collection.
|
||||
*
|
||||
* @return all JWE-standard AEAD encryption algorithms as an unmodifiable collection.
|
||||
*/
|
||||
public Collection<AeadAlgorithm> values() {
|
||||
return DELEGATE.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWE-standard Encryption Algorithm with the specified
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">{@code enc} algorithm identifier</a> or
|
||||
* throws an {@link IllegalArgumentException} if there is no JWE-standard algorithm for the specified
|
||||
* {@code id}. If a JWE-standard instance result is not mandatory, consider using the {@link #find(String)}
|
||||
* method instead.
|
||||
*
|
||||
* @param id a JWE standard {@code enc} algorithm identifier
|
||||
* @return the associated Encryption Algorithm instance.
|
||||
* @throws IllegalArgumentException if there is no JWE-standard algorithm for the specified identifier.
|
||||
* @see #find(String)
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">RFC 7518, Section 5.1</a>
|
||||
*/
|
||||
@Override
|
||||
public AeadAlgorithm get(String id) {
|
||||
return DELEGATE.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWE Encryption Algorithm with the specified
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">{@code enc} algorithm identifier</a> or
|
||||
* {@code null} if a JWE-standard algorithm for the specified {@code id} cannot be found. If a JWE-standard
|
||||
* instance must be resolved, consider using the {@link #get(String)} method instead.
|
||||
*
|
||||
* @param id a JWE standard {@code enc} algorithm identifier
|
||||
* @return the associated standard Encryption Algorithm instance or {@code null} otherwise.
|
||||
* @see #get(String)
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-5.1">RFC 7518, Section 5.1</a>
|
||||
*/
|
||||
@Override
|
||||
public AeadAlgorithm find(String id) {
|
||||
return DELEGATE.find(id);
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* 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.security;
|
||||
|
||||
import io.jsonwebtoken.Identifiable;
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Registry of various (<em>but not all</em>)
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> commonly used to compute {@link JwkThumbprint JWK Thumbprint}s and ensure valid
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc9278#name-hash-algorithms-identifier">JWK Thumbprint URIs</a>. For
|
||||
* example:
|
||||
* <blockquote><pre>
|
||||
* Jwks.{@link JwkBuilder builder}()
|
||||
* // ... etc ...
|
||||
* .{@link JwkBuilder#setIdFromThumbprint(HashAlgorithm) setIdFromThumbprint}(Jwks.HASH.{@link StandardHashAlgorithms#SHA256 SHA256}) // <---
|
||||
* .build()</pre></blockquote>
|
||||
* <p>or</p>
|
||||
* <blockquote><pre>
|
||||
* HashAlgorithm hashAlg = Jwks.HASH.{@link StandardHashAlgorithms#SHA256 SHA256};
|
||||
* {@link JwkThumbprint} thumbprint = aJwk.{@link Jwk#thumbprint(HashAlgorithm) thumbprint}(hashAlg);
|
||||
* String <a href="https://www.rfc-editor.org/rfc/rfc9278#section-3">rfcMandatoryPrefix</a> = "urn:ietf:params:oauth:jwk-thumbprint:" + hashAlg.getId();
|
||||
* assert thumbprint.toURI().toString().startsWith(rfcMandatoryPrefix);
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @see #get()
|
||||
* @see #values()
|
||||
* @see #find(String)
|
||||
* @see #get(String)
|
||||
* @see HashAlgorithm
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public final class StandardHashAlgorithms implements Registry<String, HashAlgorithm> {
|
||||
|
||||
private static final Registry<String, HashAlgorithm> DELEGATE =
|
||||
Classes.newInstance("io.jsonwebtoken.impl.security.StandardHashAlgorithmsBridge");
|
||||
|
||||
private static final StandardHashAlgorithms INSTANCE = new StandardHashAlgorithms();
|
||||
|
||||
/**
|
||||
* Returns this registry (a static singleton).
|
||||
*
|
||||
* @return this registry (a static singleton).
|
||||
*/
|
||||
public static StandardHashAlgorithms get() { // named `get` to mimic java.util.function.Supplier
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha-256}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA-256} {@code MessageDigest} algorithm.
|
||||
*/
|
||||
public final HashAlgorithm SHA256 = get("sha-256");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha-384}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA-384} {@code MessageDigest} algorithm.
|
||||
*/
|
||||
public final HashAlgorithm SHA384 = get("sha-384");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha-512}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA-512} {@code MessageDigest} algorithm.
|
||||
*/
|
||||
public final HashAlgorithm SHA512 = get("sha-512");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha3-256}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA3-256} {@code MessageDigest} algorithm.
|
||||
* <p><b>This algorithm requires at least JDK 9 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public final HashAlgorithm SHA3_256 = get("sha3-256");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha3-384}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA3-384} {@code MessageDigest} algorithm.
|
||||
* <p><b>This algorithm requires at least JDK 9 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public final HashAlgorithm SHA3_384 = get("sha3-384");
|
||||
|
||||
/**
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA
|
||||
* hash algorithm</a> with an {@link Identifiable#getId() id} (aka IANA "{@code Hash Name String}")
|
||||
* value of {@code sha3-512}. It is a {@code HashAlgorithm} alias for the native
|
||||
* Java JCA {@code SHA3-512} {@code MessageDigest} algorithm.
|
||||
* <p><b>This algorithm requires at least JDK 9 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public final HashAlgorithm SHA3_512 = get("sha3-512");
|
||||
|
||||
/**
|
||||
* Prevent external instantiation.
|
||||
*/
|
||||
private StandardHashAlgorithms() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns common
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> as an unmodifiable collection.
|
||||
*
|
||||
* @return common
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||
* Algorithms</a> as an unmodifiable collection.
|
||||
*/
|
||||
public Collection<HashAlgorithm> values() {
|
||||
return DELEGATE.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code HashAlgorithm} instance with the specified IANA algorithm {@code id}, or throws an
|
||||
* {@link IllegalArgumentException} if there is no supported algorithm for the specified {@code id}. The
|
||||
* {@code id} parameter is expected to equal one of the string values in the <b>{@code Hash Name String}</b>
|
||||
* column within the
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml">IANA Named Information
|
||||
* Hash Algorithm Registry</a> table. If a supported instance result is not mandatory, consider using the
|
||||
* {@link #find(String)} method instead.
|
||||
*
|
||||
* @param id an IANA {@code Hash Name String} hash algorithm identifier.
|
||||
* @return the associated {@code HashAlgorithm} instance.
|
||||
* @throws IllegalArgumentException if there is no supported algorithm for the specified identifier.
|
||||
* @see #find(String)
|
||||
* @see <a href="https://www.iana.org/assignments/named-information/named-information.xhtml">IANA Named
|
||||
* Information Hash Algorithm Registry</a>
|
||||
*/
|
||||
@Override
|
||||
public HashAlgorithm get(String id) {
|
||||
return DELEGATE.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code HashAlgorithm} instance with the specified IANA algorithm {@code id}, or {@code null} if
|
||||
* the specified {@code id} cannot be found. The {@code id} parameter is expected to equal one of the string
|
||||
* values in the <b>{@code Hash Name String}</b> column within the
|
||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml">IANA Named Information
|
||||
* Hash Algorithm Registry</a> table. If a standard instance must be resolved, consider using the
|
||||
* {@link #get(String)} method instead.
|
||||
*
|
||||
* @param id an IANA {@code Hash Name String} hash algorithm identifier
|
||||
* @return the associated {@code HashAlgorithm} instance if found or {@code null} otherwise.
|
||||
* @see <a href="https://www.iana.org/assignments/named-information/named-information.xhtml">IANA Named Information
|
||||
* Hash Algorithm Registry</a>
|
||||
* @see #get(String)
|
||||
*/
|
||||
@Override
|
||||
public HashAlgorithm find(String id) {
|
||||
return DELEGATE.find(id);
|
||||
}
|
||||
}
|
|
@ -1,712 +0,0 @@
|
|||
/*
|
||||
* 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.security;
|
||||
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* {@link Registry} singleton containing all standard JWE
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4">Key Management Algorithms</a>. These are most
|
||||
* commonly accessed via the {@link io.jsonwebtoken.Jwts#KEY} convenience alias when creating a JWE. For example:
|
||||
* <blockquote><pre>
|
||||
* {@link Jwts#builder()}.
|
||||
* // ... etc ...
|
||||
* .encryptWith(rsaPublicKey, <b>{@link Jwts#KEY}.RSA_OAEP</b>, Jwts.ENC.A256GCM) // <--
|
||||
* .build()</pre></blockquote>
|
||||
* <p>Direct type-safe references as shown above are often better than calling {@link #get(String)} or
|
||||
* {@link #find(String)} which can be susceptible to misspelled or otherwise invalid string values.</p>
|
||||
*
|
||||
* @see #get()
|
||||
* @see #get(String)
|
||||
* @see #find(String)
|
||||
* @see #values()
|
||||
* @see KeyAlgorithm
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public final class StandardKeyAlgorithms implements Registry<String, KeyAlgorithm<?, ?>> {
|
||||
|
||||
private static final Registry<String, KeyAlgorithm<?, ?>> REGISTRY =
|
||||
Classes.newInstance("io.jsonwebtoken.impl.security.StandardKeyAlgorithmsBridge");
|
||||
|
||||
private static final StandardKeyAlgorithms INSTANCE = new StandardKeyAlgorithms();
|
||||
|
||||
/**
|
||||
* Returns this registry (a static singleton).
|
||||
*
|
||||
* @return this registry (a static singleton).
|
||||
*/
|
||||
public static StandardKeyAlgorithms get() { // named `get` to mimic java.util.function.Supplier
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key algorithm reflecting direct use of a shared symmetric key as the JWE AEAD encryption key, as defined
|
||||
* by <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.5">RFC 7518 (JWA), Section 4.5</a>. This
|
||||
* algorithm does not produce encrypted key ciphertext.
|
||||
*/
|
||||
public final KeyAlgorithm<SecretKey, SecretKey> DIRECT = doGet("dir");
|
||||
|
||||
/**
|
||||
* AES Key Wrap algorithm with default initial value using a 128-bit key, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.4">RFC 7518 (JWA), Section 4.4</a>.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the 128-bit shared symmetric key,
|
||||
* using the AES Key Unwrap algorithm, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final SecretKeyAlgorithm A128KW = doGet("A128KW");
|
||||
|
||||
/**
|
||||
* AES Key Wrap algorithm with default initial value using a 192-bit key, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.4">RFC 7518 (JWA), Section 4.4</a>.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the 192-bit shared symmetric key,
|
||||
* using the AES Key Unwrap algorithm, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final SecretKeyAlgorithm A192KW = doGet("A192KW");
|
||||
|
||||
/**
|
||||
* AES Key Wrap algorithm with default initial value using a 256-bit key, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.4">RFC 7518 (JWA), Section 4.4</a>.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the 256-bit shared symmetric key,
|
||||
* using the AES Key Unwrap algorithm, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final SecretKeyAlgorithm A256KW = doGet("A256KW");
|
||||
|
||||
/**
|
||||
* Key wrap algorithm with AES GCM using a 128-bit key, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7">RFC 7518 (JWA), Section 4.7</a>.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* and GCM authentication tag.</li>
|
||||
* <li>Sets the generated initialization vector as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.1">"iv"
|
||||
* (Initialization Vector) Header Parameter</a></li>
|
||||
* <li>Sets the resulting GCM authentication tag as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.2">"tag"
|
||||
* (Authentication Tag) Header Parameter</a></li>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Obtains the required initialization vector from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.1">"iv"
|
||||
* (Initialization Vector) Header Parameter</a></li>
|
||||
* <li>Obtains the required GCM authentication tag from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.2">"tag"
|
||||
* (Authentication Tag) Header Parameter</a></li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the 128-bit shared symmetric key, the initialization vector
|
||||
* and GCM authentication tag using the AES GCM Key Unwrap algorithm, producing the decryption key
|
||||
* plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final SecretKeyAlgorithm A128GCMKW = doGet("A128GCMKW");
|
||||
|
||||
/**
|
||||
* Key wrap algorithm with AES GCM using a 192-bit key, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7">RFC 7518 (JWA), Section 4.7</a>.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* and GCM authentication tag.</li>
|
||||
* <li>Sets the generated initialization vector as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.1">"iv"
|
||||
* (Initialization Vector) Header Parameter</a></li>
|
||||
* <li>Sets the resulting GCM authentication tag as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.2">"tag"
|
||||
* (Authentication Tag) Header Parameter</a></li>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Obtains the required initialization vector from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.1">"iv"
|
||||
* (Initialization Vector) Header Parameter</a></li>
|
||||
* <li>Obtains the required GCM authentication tag from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.2">"tag"
|
||||
* (Authentication Tag) Header Parameter</a></li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the 192-bit shared symmetric key, the initialization vector
|
||||
* and GCM authentication tag using the AES GCM Key Unwrap algorithm, producing the decryption key \
|
||||
* plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final SecretKeyAlgorithm A192GCMKW = doGet("A192GCMKW");
|
||||
|
||||
/**
|
||||
* Key wrap algorithm with AES GCM using a 256-bit key, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7">RFC 7518 (JWA), Section 4.7</a>.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* and GCM authentication tag.</li>
|
||||
* <li>Sets the generated initialization vector as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.1">"iv"
|
||||
* (Initialization Vector) Header Parameter</a></li>
|
||||
* <li>Sets the resulting GCM authentication tag as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.2">"tag"
|
||||
* (Authentication Tag) Header Parameter</a></li>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Obtains the required initialization vector from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.1">"iv"
|
||||
* (Initialization Vector) Header Parameter</a></li>
|
||||
* <li>Obtains the required GCM authentication tag from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.7.1.2">"tag"
|
||||
* (Authentication Tag) Header Parameter</a></li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the 256-bit shared symmetric key, the initialization vector
|
||||
* and GCM authentication tag using the AES GCM Key Unwrap algorithm, producing the decryption key \
|
||||
* plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final SecretKeyAlgorithm A256GCMKW = doGet("A256GCMKW");
|
||||
|
||||
/**
|
||||
* Key encryption algorithm using <code>PBES2 with HMAC SHA-256 and "A128KW" wrapping</code>
|
||||
* as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8">RFC 7518 (JWA), Section 4.8</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Determines the number of PBDKF2 iterations via the JWE header's
|
||||
* {@link JweHeader#getPbes2Count() pbes2Count} value. If that value is not set, a suitable number of
|
||||
* iterations will be chosen based on
|
||||
* <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2">OWASP
|
||||
* PBKDF2 recommendations</a> and then that value is set as the JWE header {@code pbes2Count} value.</li>
|
||||
* <li>Generates a new secure-random salt input and sets it as the JWE header
|
||||
* {@link JweHeader#getPbes2Salt() pbes2Salt} value.</li>
|
||||
* <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>
|
||||
* <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>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* Content Encryption {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated
|
||||
* {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required PBKDF2 input salt from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1">"p2s"
|
||||
* (PBES2 Salt Input) Header Parameter</a></li>
|
||||
* <li>Obtains the required PBKDF2 iteration count from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.2">"p2c"
|
||||
* (PBES2 Count) Header Parameter</a></li>
|
||||
* <li>Derives the 128-bit Key Encryption Key with the PBES2-HS256 password-based key derivation algorithm,
|
||||
* using the provided password, obtained salt input, and obtained iteration count as arguments.</li>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with with the {@code A128KW} key unwrap
|
||||
* algorithm using the 128-bit derived password-based Key Encryption Key from step {@code #3},
|
||||
* producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<Password, Password> PBES2_HS256_A128KW = doGet("PBES2-HS256+A128KW");
|
||||
|
||||
/**
|
||||
* Key encryption algorithm using <code>PBES2 with HMAC SHA-384 and "A192KW" wrapping</code>
|
||||
* as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8">RFC 7518 (JWA), Section 4.8</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Determines the number of PBDKF2 iterations via the JWE header's
|
||||
* {@link JweHeader#getPbes2Count() pbes2Count} value. If that value is not set, a suitable number of
|
||||
* iterations will be chosen based on
|
||||
* <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2">OWASP
|
||||
* PBKDF2 recommendations</a> and then that value is set as the JWE header {@code pbes2Count} value.</li>
|
||||
* <li>Generates a new secure-random salt input and sets it as the JWE header
|
||||
* {@link JweHeader#getPbes2Salt() pbes2Salt} value.</li>
|
||||
* <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>
|
||||
* <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>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* Content Encryption {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated
|
||||
* {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required PBKDF2 input salt from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1">"p2s"
|
||||
* (PBES2 Salt Input) Header Parameter</a></li>
|
||||
* <li>Obtains the required PBKDF2 iteration count from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.2">"p2c"
|
||||
* (PBES2 Count) Header Parameter</a></li>
|
||||
* <li>Derives the 192-bit Key Encryption Key with the PBES2-HS384 password-based key derivation algorithm,
|
||||
* using the provided password, obtained salt input, and obtained iteration count as arguments.</li>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with with the {@code A192KW} key unwrap
|
||||
* algorithm using the 192-bit derived password-based Key Encryption Key from step {@code #3},
|
||||
* producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<Password, Password> PBES2_HS384_A192KW = doGet("PBES2-HS384+A192KW");
|
||||
|
||||
/**
|
||||
* Key encryption algorithm using <code>PBES2 with HMAC SHA-512 and "A256KW" wrapping</code>
|
||||
* as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8">RFC 7518 (JWA), Section 4.8</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Determines the number of PBDKF2 iterations via the JWE header's
|
||||
* {@link JweHeader#getPbes2Count() pbes2Count} value. If that value is not set, a suitable number of
|
||||
* iterations will be chosen based on
|
||||
* <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2">OWASP
|
||||
* PBKDF2 recommendations</a> and then that value is set as the JWE header {@code pbes2Count} value.</li>
|
||||
* <li>Generates a new secure-random salt input and sets it as the JWE header
|
||||
* {@link JweHeader#getPbes2Salt() pbes2Salt} value.</li>
|
||||
* <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>
|
||||
* <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>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* Content Encryption {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated
|
||||
* {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required PBKDF2 input salt from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.1">"p2s"
|
||||
* (PBES2 Salt Input) Header Parameter</a></li>
|
||||
* <li>Obtains the required PBKDF2 iteration count from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.8.1.2">"p2c"
|
||||
* (PBES2 Count) Header Parameter</a></li>
|
||||
* <li>Derives the 256-bit Key Encryption Key with the PBES2-HS512 password-based key derivation algorithm,
|
||||
* using the provided password, obtained salt input, and obtained iteration count as arguments.</li>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with with the {@code A256KW} key unwrap
|
||||
* algorithm using the 256-bit derived password-based Key Encryption Key from step {@code #3},
|
||||
* producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<Password, Password> PBES2_HS512_A256KW = doGet("PBES2-HS512+A256KW");
|
||||
|
||||
/**
|
||||
* Key Encryption with {@code RSAES-PKCS1-v1_5}, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.2">RFC 7518 (JWA), Section 4.2</a>.
|
||||
* This algorithm requires a key size of 2048 bits or larger.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Receives the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the RSA key unwrap algorithm, using the JWE recipient's
|
||||
* RSA Private Key, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}. </li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> RSA1_5 = doGet("RSA1_5");
|
||||
|
||||
/**
|
||||
* Key Encryption with {@code RSAES OAEP using default parameters}, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.3">RFC 7518 (JWA), Section 4.3</a>.
|
||||
* This algorithm requires a key size of 2048 bits or larger.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Receives the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the RSA OAEP with SHA-1 and MGF1 key unwrap algorithm,
|
||||
* using the JWE recipient's RSA Private Key, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}. </li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> RSA_OAEP = doGet("RSA-OAEP");
|
||||
|
||||
/**
|
||||
* Key Encryption with {@code RSAES OAEP using SHA-256 and MGF1 with SHA-256}, as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.3">RFC 7518 (JWA), Section 4.3</a>.
|
||||
* This algorithm requires a key size of 2048 bits or larger.
|
||||
*
|
||||
* <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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Receives the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the RSA OAEP with SHA-256 and MGF1 key unwrap algorithm,
|
||||
* using the JWE recipient's RSA Private Key, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}. </li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> RSA_OAEP_256 = doGet("RSA-OAEP-256");
|
||||
|
||||
/**
|
||||
* Key Agreement with {@code ECDH-ES using Concat KDF} as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6">RFC 7518 (JWA), Section 4.6</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Generates a new secure-random Elliptic Curve public/private key pair on the same curve as the
|
||||
* JWE recipient's EC Public Key.</li>
|
||||
* <li>Generates a shared secret with the ECDH key agreement algorithm using the generated EC Private Key
|
||||
* and the JWE recipient's EC Public Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> a symmetric Content
|
||||
* Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* generated shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Sets the generated EC key pair's Public Key as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (Ephemeral Public Key) Header Parameter</a> to be transmitted in the JWE.</li>
|
||||
* <li>Returns the derived symmetric {@code SecretKey} for JJWT to use to encrypt the entire JWE with the
|
||||
* associated {@link AeadAlgorithm}. Encrypted key ciphertext is not produced with this algorithm, so
|
||||
* the resulting JWE will not contain any embedded key ciphertext.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required ephemeral Elliptic Curve Public Key from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (Ephemeral Public Key) Header Parameter</a>.</li>
|
||||
* <li>Validates that the ephemeral Public Key is on the same curve as the recipient's EC Private Key.</li>
|
||||
* <li>Obtains the shared secret with the ECDH key agreement algorithm using the obtained EC Public Key
|
||||
* and the JWE recipient's EC Private Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> the symmetric Content
|
||||
* Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* obtained shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Returns the derived symmetric {@code SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> ECDH_ES = doGet("ECDH-ES");
|
||||
|
||||
/**
|
||||
* Key Agreement with Key Wrapping via
|
||||
* <code>ECDH-ES using Concat KDF and CEK wrapped with "A128KW"</code> as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6">RFC 7518 (JWA), Section 4.6</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Generates a new secure-random Elliptic Curve public/private key pair on the same curve as the
|
||||
* JWE recipient's EC Public Key.</li>
|
||||
* <li>Generates a shared secret with the ECDH key agreement algorithm using the generated EC Private Key
|
||||
* and the JWE recipient's EC Public Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> a 128-bit symmetric Key
|
||||
* Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* generated shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Sets the generated EC key pair's Public Key as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (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>
|
||||
* <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
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required ephemeral Elliptic Curve Public Key from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (Ephemeral Public Key) Header Parameter</a>.</li>
|
||||
* <li>Validates that the ephemeral Public Key is on the same curve as the recipient's EC Private Key.</li>
|
||||
* <li>Obtains the shared secret with the ECDH key agreement algorithm using the obtained EC Public Key
|
||||
* and the JWE recipient's EC Private Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> the symmetric Key
|
||||
* Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* obtained shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the AES Key Unwrap algorithm using the
|
||||
* 128-bit derived symmetric key from step {@code #4}, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> ECDH_ES_A128KW = doGet("ECDH-ES+A128KW");
|
||||
|
||||
/**
|
||||
* Key Agreement with Key Wrapping via
|
||||
* <code>ECDH-ES using Concat KDF and CEK wrapped with "A192KW"</code> as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6">RFC 7518 (JWA), Section 4.6</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Generates a new secure-random Elliptic Curve public/private key pair on the same curve as the
|
||||
* JWE recipient's EC Public Key.</li>
|
||||
* <li>Generates a shared secret with the ECDH key agreement algorithm using the generated EC Private Key
|
||||
* and the JWE recipient's EC Public Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> a 192-bit symmetric Key
|
||||
* Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* generated shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Sets the generated EC key pair's Public Key as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (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>
|
||||
* <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>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required ephemeral Elliptic Curve Public Key from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (Ephemeral Public Key) Header Parameter</a>.</li>
|
||||
* <li>Validates that the ephemeral Public Key is on the same curve as the recipient's EC Private Key.</li>
|
||||
* <li>Obtains the shared secret with the ECDH key agreement algorithm using the obtained EC Public Key
|
||||
* and the JWE recipient's EC Private Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> the 192-bit symmetric
|
||||
* Key Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* obtained shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the AES Key Unwrap algorithm using the
|
||||
* 192-bit derived symmetric key from step {@code #4}, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> ECDH_ES_A192KW = doGet("ECDH-ES+A192KW");
|
||||
|
||||
/**
|
||||
* Key Agreement with Key Wrapping via
|
||||
* <code>ECDH-ES using Concat KDF and CEK wrapped with "A256KW"</code> as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6">RFC 7518 (JWA), Section 4.6</a>.
|
||||
*
|
||||
* <p>During JWE creation, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Generates a new secure-random Elliptic Curve public/private key pair on the same curve as the
|
||||
* JWE recipient's EC Public Key.</li>
|
||||
* <li>Generates a shared secret with the ECDH key agreement algorithm using the generated EC Private Key
|
||||
* and the JWE recipient's EC Public Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> a 256-bit symmetric Key
|
||||
* Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* generated shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Sets the generated EC key pair's Public Key as the required
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (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>
|
||||
* <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>
|
||||
* <li>Returns the encrypted key ciphertext for inclusion in the final JWE as well as the newly-generated
|
||||
* {@code SecretKey} for JJWT to use to encrypt the entire JWE with associated {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
* <p>For JWE decryption, this algorithm:</p>
|
||||
* <ol>
|
||||
* <li>Obtains the required ephemeral Elliptic Curve Public Key from the
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1">"epk"
|
||||
* (Ephemeral Public Key) Header Parameter</a>.</li>
|
||||
* <li>Validates that the ephemeral Public Key is on the same curve as the recipient's EC Private Key.</li>
|
||||
* <li>Obtains the shared secret with the ECDH key agreement algorithm using the obtained EC Public Key
|
||||
* and the JWE recipient's EC Private Key.</li>
|
||||
* <li><a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.2">Derives</a> the 256-bit symmetric
|
||||
* Key Encryption {@code SecretKey} with the Concat KDF algorithm using the
|
||||
* obtained shared secret and any available
|
||||
* {@link JweHeader#getAgreementPartyUInfo() PartyUInfo} and
|
||||
* {@link JweHeader#getAgreementPartyVInfo() PartyVInfo}.</li>
|
||||
* <li>Obtains the encrypted key ciphertext embedded in the received JWE.</li>
|
||||
* <li>Decrypts the encrypted key ciphertext with the AES Key Unwrap algorithm using the
|
||||
* 256-bit derived symmetric key from step {@code #4}, producing the decryption key plaintext.</li>
|
||||
* <li>Returns the decryption key plaintext as a {@link SecretKey} for JJWT to use to decrypt the entire
|
||||
* JWE using the JWE's identified "enc" {@link AeadAlgorithm}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public final KeyAlgorithm<PublicKey, PrivateKey> ECDH_ES_A256KW = doGet("ECDH-ES+A256KW");
|
||||
|
||||
//prevent instantiation
|
||||
private StandardKeyAlgorithms() {
|
||||
}
|
||||
|
||||
// do not change this visibility. Raw type method signature not be publicly exposed
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T doGet(String id) {
|
||||
Assert.hasText(id, "id cannot be null or empty.");
|
||||
return (T) get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all JWA-standard
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4">Key Management Algorithms</a> as an
|
||||
* unmodifiable collection.
|
||||
*
|
||||
* @return all JWA-standard
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4">Key Management Algorithms</a> as an
|
||||
* unmodifiable collection.
|
||||
*/
|
||||
public Collection<KeyAlgorithm<?, ?>> values() {
|
||||
return REGISTRY.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWE Key Management Algorithm with the specified
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1">{@code alg} key algorithm identifier</a> or
|
||||
* {@code null} if an algorithm for the specified {@code id} cannot be found. If a JWA-standard
|
||||
* instance must be resolved, consider using the {@link #get(String)} method instead.
|
||||
*
|
||||
* @param id a JWA standard {@code alg} key algorithm identifier
|
||||
* @return the associated KeyAlgorithm instance or {@code null} otherwise.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1">RFC 7518, Section 4.1</a>
|
||||
* @see #get(String)
|
||||
*/
|
||||
public KeyAlgorithm<?, ?> find(String id) {
|
||||
return REGISTRY.find(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWE Key Management Algorithm with the specified
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1">{@code alg} key algorithm identifier</a> or
|
||||
* throws an {@link IllegalArgumentException} if there is no JWE-standard algorithm for the specified
|
||||
* {@code id}. If a JWE-standard instance result is not mandatory, consider using the {@link #find(String)}
|
||||
* method instead.
|
||||
*
|
||||
* @param id a JWA standard {@code alg} key algorithm identifier
|
||||
* @return the associated {@code KeyAlgorithm} instance.
|
||||
* @throws IllegalArgumentException if there is no JWA-standard algorithm for the specified identifier.
|
||||
* @see #find(String)
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1">RFC 7518, Section 4.1</a>
|
||||
*/
|
||||
public KeyAlgorithm<?, ?> get(String id) throws IllegalArgumentException {
|
||||
return REGISTRY.get(id);
|
||||
}
|
||||
}
|
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* 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.security;
|
||||
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Classes;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Registry of all standard JWS
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3">Cryptographic Algorithms for Digital
|
||||
* Signatures and MACs</a>. These are most commonly accessed via the {@link io.jsonwebtoken.Jwts#SIG} convenience
|
||||
* alias when creating a JWS. For example:
|
||||
* <blockquote><pre>
|
||||
* {@link Jwts#builder()}.
|
||||
* // ... etc ...
|
||||
* .{@link io.jsonwebtoken.JwtBuilder#signWith(Key, SecureDigestAlgorithm) signWith}(aKey, {@link Jwts#SIG}.HS256) // <--
|
||||
* .build()</pre></blockquote>
|
||||
*
|
||||
* @see #get()
|
||||
* @see #get(String)
|
||||
* @see #find(String)
|
||||
* @see #values()
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public final class StandardSecureDigestAlgorithms implements Registry<String, SecureDigestAlgorithm<?, ?>> {
|
||||
|
||||
private static final Registry<String, SecureDigestAlgorithm<?, ?>> IMPL =
|
||||
Classes.newInstance("io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithmsBridge");
|
||||
|
||||
private static final StandardSecureDigestAlgorithms INSTANCE = new StandardSecureDigestAlgorithms();
|
||||
|
||||
/**
|
||||
* Returns this registry (a static singleton).
|
||||
*
|
||||
* @return this registry (a static singleton).
|
||||
*/
|
||||
public static StandardSecureDigestAlgorithms get() { // named `get` to mimic java.util.function.Supplier
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "none" signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.6">RFC 7518, Section 3.6</a>. This algorithm
|
||||
* is used only when creating unsecured (not integrity protected) JWSs and is not usable in any other scenario.
|
||||
* Any attempt to call its methods will result in an exception being thrown.
|
||||
*/
|
||||
public final SecureDigestAlgorithm<Key, Key> NONE = doGet("none");
|
||||
|
||||
/**
|
||||
* {@code HMAC using SHA-256} message authentication algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.2">RFC 7518, Section 3.2</a>. This algorithm
|
||||
* requires a 256-bit (32 byte) key.
|
||||
*/
|
||||
public final MacAlgorithm HS256 = doGet("HS256");
|
||||
|
||||
/**
|
||||
* {@code HMAC using SHA-384} message authentication algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.2">RFC 7518, Section 3.2</a>. This algorithm
|
||||
* requires a 384-bit (48 byte) key.
|
||||
*/
|
||||
public final MacAlgorithm HS384 = doGet("HS384");
|
||||
|
||||
/**
|
||||
* {@code HMAC using SHA-512} message authentication algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.2">RFC 7518, Section 3.2</a>. This algorithm
|
||||
* requires a 512-bit (64 byte) key.
|
||||
*/
|
||||
public final MacAlgorithm HS512 = doGet("HS512");
|
||||
|
||||
/**
|
||||
* {@code RSASSA-PKCS1-v1_5 using SHA-256} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.3">RFC 7518, Section 3.3</a>. This algorithm
|
||||
* requires a 2048-bit key.
|
||||
*/
|
||||
public final SignatureAlgorithm RS256 = doGet("RS256");
|
||||
|
||||
/**
|
||||
* {@code RSASSA-PKCS1-v1_5 using SHA-384} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.3">RFC 7518, Section 3.3</a>. This algorithm
|
||||
* requires a 2048-bit key, but the JJWT team recommends a 3072-bit key.
|
||||
*/
|
||||
public final SignatureAlgorithm RS384 = doGet("RS384");
|
||||
|
||||
/**
|
||||
* {@code RSASSA-PKCS1-v1_5 using SHA-512} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.3">RFC 7518, Section 3.3</a>. This algorithm
|
||||
* requires a 2048-bit key, but the JJWT team recommends a 4096-bit key.
|
||||
*/
|
||||
public final SignatureAlgorithm RS512 = doGet("RS512");
|
||||
|
||||
/**
|
||||
* {@code RSASSA-PSS using SHA-256 and MGF1 with SHA-256} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.5">RFC 7518, Section 3.5</a><b><sup>1</sup></b>.
|
||||
* This algorithm requires a 2048-bit key.
|
||||
*
|
||||
* <p><b><sup>1</sup></b> Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath. If on Java 10 or earlier, BouncyCastle will be used automatically if found in the runtime
|
||||
* classpath.</p>
|
||||
*/
|
||||
public final SignatureAlgorithm PS256 = doGet("PS256");
|
||||
|
||||
/**
|
||||
* {@code RSASSA-PSS using SHA-384 and MGF1 with SHA-384} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.5">RFC 7518, Section 3.5</a><b><sup>1</sup></b>.
|
||||
* This algorithm requires a 2048-bit key, but the JJWT team recommends a 3072-bit key.
|
||||
*
|
||||
* <p><b><sup>1</sup></b> Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath. If on Java 10 or earlier, BouncyCastle will be used automatically if found in the runtime
|
||||
* classpath.</p>
|
||||
*/
|
||||
public final SignatureAlgorithm PS384 = doGet("PS384");
|
||||
|
||||
/**
|
||||
* {@code RSASSA-PSS using SHA-512 and MGF1 with SHA-512} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.5">RFC 7518, Section 3.5</a><b><sup>1</sup></b>.
|
||||
* This algorithm requires a 2048-bit key, but the JJWT team recommends a 4096-bit key.
|
||||
*
|
||||
* <p><b><sup>1</sup></b> Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath. If on Java 10 or earlier, BouncyCastle will be used automatically if found in the runtime
|
||||
* classpath.</p>
|
||||
*/
|
||||
public final SignatureAlgorithm PS512 = doGet("PS512");
|
||||
|
||||
/**
|
||||
* {@code ECDSA using P-256 and SHA-256} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4">RFC 7518, Section 3.4</a>. This algorithm
|
||||
* requires a 256-bit key.
|
||||
*/
|
||||
public final SignatureAlgorithm ES256 = doGet("ES256");
|
||||
|
||||
/**
|
||||
* {@code ECDSA using P-384 and SHA-384} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4">RFC 7518, Section 3.4</a>. This algorithm
|
||||
* requires a 384-bit key.
|
||||
*/
|
||||
public final SignatureAlgorithm ES384 = doGet("ES384");
|
||||
|
||||
/**
|
||||
* {@code ECDSA using P-521 and SHA-512} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.4">RFC 7518, Section 3.4</a>. This algorithm
|
||||
* requires a 521-bit key.
|
||||
*/
|
||||
public final SignatureAlgorithm ES512 = doGet("ES512");
|
||||
|
||||
/**
|
||||
* {@code EdDSA} signature algorithm as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>. This algorithm
|
||||
* requires either {@code Ed25519} or {@code Ed448} Edwards Curve keys.
|
||||
* <p><b>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public final SignatureAlgorithm EdDSA = doGet("EdDSA");
|
||||
|
||||
/**
|
||||
* {@code EdDSA} signature algorithm using Curve {@code Ed25519} as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>. This algorithm
|
||||
* requires {@code Ed25519} Edwards Curve keys to create signatures. <b>This is a convenience alias for
|
||||
* {@link #EdDSA}</b> that defaults key generation to {@code Ed25519} keys.
|
||||
* <p><b>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public final SignatureAlgorithm Ed25519 = doGet("Ed25519");
|
||||
|
||||
/**
|
||||
* {@code EdDSA} signature algorithm using Curve {@code Ed448} as defined by
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>. This algorithm
|
||||
* requires {@code Ed448} Edwards Curve keys to create signatures. <b>This is a convenience alias for
|
||||
* {@link #EdDSA}</b> that defaults key generation to {@code Ed448} keys.
|
||||
* <p><b>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||
* classpath.</b></p>
|
||||
*/
|
||||
public final SignatureAlgorithm Ed448 = doGet("Ed448");
|
||||
|
||||
/**
|
||||
* Prevent external instantiation.
|
||||
*/
|
||||
private StandardSecureDigestAlgorithms() {
|
||||
}
|
||||
|
||||
// do not change this visibility. Raw type method signature not be publicly exposed
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T doGet(String id) {
|
||||
Assert.hasText(id, "id cannot be null or empty.");
|
||||
return (T) get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all standard JWS
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">Digital Signature and MAC Algorithms</a>
|
||||
* as an unmodifiable collection.
|
||||
*
|
||||
* @return all standard JWS
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">Digital Signature and MAC Algorithms</a>
|
||||
* as an unmodifiable collection.
|
||||
*/
|
||||
public Collection<SecureDigestAlgorithm<?, ?>> values() {
|
||||
return IMPL.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SignatureAlgorithm} or {@link MacAlgorithm} instance with the specified
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">{@code alg} algorithm identifier</a> or
|
||||
* {@code null} if an algorithm for the specified {@code id} cannot be found. If a JWA-standard
|
||||
* instance must be resolved, consider using the {@link #get(String)} method instead.
|
||||
*
|
||||
* @param id a JWA-standard identifier defined in
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">JWA RFC 7518, Section 3.1</a>
|
||||
* in the <code>"alg" Param Value</code> column.
|
||||
* @return the {@code SecureDigestAlgorithm} instance with the specified JWA-standard identifier, or
|
||||
* {@code null} if no algorithm with that identifier exists.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">RFC 7518, Section 3.1</a>
|
||||
* @see #get(String)
|
||||
*/
|
||||
public SecureDigestAlgorithm<?, ?> find(String id) {
|
||||
return IMPL.find(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SignatureAlgorithm} or {@link MacAlgorithm} instance with the specified
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">{@code alg} algorithm identifier</a> or
|
||||
* throws an {@link IllegalArgumentException} if there is no JWA-standard algorithm for the specified
|
||||
* {@code id}. If a JWA-standard instance result is not mandatory, consider using the {@link #find(String)}
|
||||
* method instead.
|
||||
*
|
||||
* @param id a JWA-standard identifier defined in
|
||||
* <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">JWA RFC 7518, Section 3.1</a>
|
||||
* in the <code>"alg" Param Value</code> column.
|
||||
* @return the associated {@code SecureDigestAlgorithm} instance.
|
||||
* @throws IllegalArgumentException if there is no JWA-standard algorithm for the specified identifier.
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1">RFC 7518, Section 3.1</a>
|
||||
* @see #find(String)
|
||||
*/
|
||||
public SecureDigestAlgorithm<?, ?> get(String id) throws IllegalArgumentException {
|
||||
return IMPL.get(id);
|
||||
}
|
||||
}
|
|
@ -23,9 +23,12 @@ import java.security.cert.X509Certificate;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Accessor methods of X.509-specific properties of an associated JWT Header or JWK, guaranteeing consistent behavior
|
||||
* Accessor methods of X.509-specific properties of a
|
||||
* {@link io.jsonwebtoken.ProtectedHeader ProtectedHeader} or {@link AsymmetricJwk}, guaranteeing consistent behavior
|
||||
* across similar but distinct JWT concepts with identical parameter names.
|
||||
*
|
||||
* @see io.jsonwebtoken.ProtectedHeader
|
||||
* @see AsymmetricJwk
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface X509Accessor {
|
||||
|
@ -39,8 +42,8 @@ public interface X509Accessor {
|
|||
* with each certificate delimited as specified in
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc4945#section-6.1">Section 6.1 of RFC 4945</a>.
|
||||
* The key in the first certificate <em>MUST</em> match the public key represented by other members of the
|
||||
* associated JWT or JWK. The protocol used to acquire the resource <em>MUST</em> provide integrity protection;
|
||||
* an HTTP GET request to retrieve the certificate <em>MUST</em> use
|
||||
* associated ProtectedHeader or JWK. The protocol used to acquire the resource <em>MUST</em> provide integrity
|
||||
* protection; an HTTP GET request to retrieve the certificate <em>MUST</em> use
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc2818">HTTP over TLS</a>; the identity of the server
|
||||
* <em>MUST</em> be validated, as per
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc6125#section-6">Section 6 of RFC 6125</a>.</p>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Deserializer using a Jackson {@link ObjectMapper}.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class JacksonDeserializer<T> implements Deserializer<T> {
|
||||
|
@ -36,6 +38,9 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
|||
private final Class<T> returnType;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* Constructor using JJWT's default {@link ObjectMapper} singleton for deserialization.
|
||||
*/
|
||||
public JacksonDeserializer() {
|
||||
this(JacksonSerializer.DEFAULT_OBJECT_MAPPER);
|
||||
}
|
||||
|
@ -76,6 +81,11 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
|||
objectMapper.registerModule(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using the specified Jackson {@link ObjectMapper}.
|
||||
*
|
||||
* @param objectMapper the ObjectMapper to use for deserialization.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper
|
||||
public JacksonDeserializer(ObjectMapper objectMapper) {
|
||||
this(objectMapper, (Class<T>) Object.class);
|
||||
|
@ -98,6 +108,13 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the specified byte array value to the desired typed instance using the Jackson {@link ObjectMapper}.
|
||||
*
|
||||
* @param bytes the byte array value to convert
|
||||
* @return the desired typed instance
|
||||
* @throws IOException if there is a problem during reading or instance creation
|
||||
*/
|
||||
protected T readValue(byte[] bytes) throws IOException {
|
||||
return objectMapper.readValue(bytes, returnType);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import io.jsonwebtoken.io.Serializer;
|
|||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
/**
|
||||
* Serializer using a Jackson {@link ObjectMapper}.
|
||||
*
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public class JacksonSerializer<T> implements Serializer<T> {
|
||||
|
@ -41,11 +43,19 @@ public class JacksonSerializer<T> implements Serializer<T> {
|
|||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* Constructor using JJWT's default {@link ObjectMapper} singleton for serialization.
|
||||
*/
|
||||
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
||||
public JacksonSerializer() {
|
||||
this(DEFAULT_OBJECT_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Jackson Serializer that uses the specified {@link ObjectMapper} for serialization.
|
||||
*
|
||||
* @param objectMapper the ObjectMapper to use for serialization.
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom ObjectMapper
|
||||
public JacksonSerializer(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
||||
|
@ -63,6 +73,13 @@ public class JacksonSerializer<T> implements Serializer<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the specified instance value to a byte array using the underlying Jackson {@link ObjectMapper}.
|
||||
*
|
||||
* @param t the instance to serialize to a byte array
|
||||
* @return the byte array serialization of the specified instance
|
||||
* @throws JsonProcessingException if there is a problem during serialization
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess") //for testing
|
||||
protected byte[] writeValueAsBytes(T t) throws JsonProcessingException {
|
||||
return this.objectMapper.writeValueAsBytes(t);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Header;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public abstract class AbstractHeaderBuilder<H extends Header<H>, T extends HeaderBuilder<H, T>>
|
||||
implements HeaderBuilder<H, T> {
|
||||
|
||||
protected final H header;
|
||||
|
||||
protected AbstractHeaderBuilder() {
|
||||
this.header = newHeader();
|
||||
onNewHeader(this.header);
|
||||
}
|
||||
|
||||
protected abstract H newHeader();
|
||||
|
||||
protected void onNewHeader(H header) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final T tthis() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setType(String typ) {
|
||||
this.header.setType(typ);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setContentType(String cty) {
|
||||
this.header.setContentType(cty);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setAlgorithm(String alg) {
|
||||
this.header.setAlgorithm(alg);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setCompressionAlgorithm(String zip) {
|
||||
this.header.setCompressionAlgorithm(zip);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public H build() {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T put(String key, Object value) {
|
||||
this.header.put(key, value);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T remove(String key) {
|
||||
this.header.remove(key);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T putAll(Map<? extends String, ?> m) {
|
||||
this.header.putAll(m);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T clear() {
|
||||
this.header.clear();
|
||||
return tthis();
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.ProtectedHeader;
|
||||
import io.jsonwebtoken.impl.security.DefaultX509Builder;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public abstract class AbstractProtectedHeaderBuilder<H extends ProtectedHeader<H>,
|
||||
T extends ProtectedHeaderBuilder<H, T>>
|
||||
extends AbstractHeaderBuilder<H, T> implements ProtectedHeaderBuilder<H, T> {
|
||||
|
||||
private DefaultX509Builder<T> x509Builder;
|
||||
|
||||
@Override
|
||||
protected void onNewHeader(H header) {
|
||||
this.x509Builder = new DefaultX509Builder<>(header, tthis(), IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setJwkSetUrl(URI uri) {
|
||||
this.header.setJwkSetUrl(uri);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setJwk(PublicJwk<?> jwk) {
|
||||
this.header.setJwk(jwk);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setKeyId(String kid) {
|
||||
this.header.setKeyId(kid);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509Url(URI uri) {
|
||||
return this.x509Builder.setX509Url(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateChain(List<X509Certificate> chain) {
|
||||
return this.x509Builder.setX509CertificateChain(chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateSha1Thumbprint(byte[] thumbprint) {
|
||||
this.header.setX509CertificateSha1Thumbprint(thumbprint);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateSha256Thumbprint(byte[] thumbprint) {
|
||||
this.header.setX509CertificateSha256Thumbprint(thumbprint);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setCritical(Set<String> crit) {
|
||||
this.header.setCritical(crit);
|
||||
return tthis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T withX509Sha1Thumbprint(boolean enable) {
|
||||
return x509Builder.withX509Sha1Thumbprint(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T withX509Sha256Thumbprint(boolean enable) {
|
||||
return x509Builder.withX509Sha256Thumbprint(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public H build() {
|
||||
this.x509Builder.apply();
|
||||
return this.header;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (C) 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.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.security.AbstractAsymmetricJwk;
|
||||
import io.jsonwebtoken.security.X509Mutator;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class AbstractX509Context<T extends X509Mutator<T>> extends FieldMap implements X509Context<T> {
|
||||
|
||||
public AbstractX509Context(Set<Field<?>> fieldSet) {
|
||||
super(fieldSet);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T self() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getX509Url() {
|
||||
return get(AbstractAsymmetricJwk.X5U);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509Url(URI uri) {
|
||||
put(AbstractAsymmetricJwk.X5U, uri);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<X509Certificate> getX509CertificateChain() {
|
||||
return get(AbstractAsymmetricJwk.X5C);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateChain(List<X509Certificate> chain) {
|
||||
put(AbstractAsymmetricJwk.X5C, chain);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getX509CertificateSha1Thumbprint() {
|
||||
return get(AbstractAsymmetricJwk.X5T);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateSha1Thumbprint(byte[] thumbprint) {
|
||||
put(AbstractAsymmetricJwk.X5T, thumbprint);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getX509CertificateSha256Thumbprint() {
|
||||
return get(AbstractAsymmetricJwk.X5T_S256);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateSha256Thumbprint(byte[] thumbprint) {
|
||||
put(AbstractAsymmetricJwk.X5T_S256, thumbprint);
|
||||
return self();
|
||||
}
|
||||
}
|
|
@ -15,14 +15,15 @@
|
|||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.CompressionCodec;
|
||||
import io.jsonwebtoken.CompressionCodecResolver;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Locator;
|
||||
import io.jsonwebtoken.impl.lang.Function;
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
|
||||
public class CompressionCodecLocator implements Function<Header<?>, CompressionCodec>, Locator<CompressionCodec> {
|
||||
//TODO: delete when deleting CompressionCodecResolver
|
||||
public class CompressionCodecLocator implements Function<Header, CompressionAlgorithm>, Locator<CompressionAlgorithm> {
|
||||
|
||||
private final CompressionCodecResolver resolver;
|
||||
|
||||
|
@ -31,12 +32,12 @@ public class CompressionCodecLocator implements Function<Header<?>, CompressionC
|
|||
}
|
||||
|
||||
@Override
|
||||
public CompressionCodec apply(Header<?> header) {
|
||||
return resolver.resolveCompressionCodec(header);
|
||||
public CompressionAlgorithm apply(Header header) {
|
||||
return locate(header);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompressionCodec locate(Header<?> header) {
|
||||
return apply(header);
|
||||
public CompressionAlgorithm locate(Header header) {
|
||||
return resolver.resolveCompressionCodec(header);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,12 @@ import io.jsonwebtoken.impl.lang.Field;
|
|||
import io.jsonwebtoken.impl.lang.Fields;
|
||||
import io.jsonwebtoken.impl.lang.JwtDateConverter;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class DefaultClaims extends JwtMap implements Claims {
|
||||
public class DefaultClaims extends FieldMap implements Claims {
|
||||
|
||||
private static final String CONVERSION_ERROR_MSG = "Cannot convert existing claim value of type '%s' to desired type " +
|
||||
"'%s'. JJWT only converts simple String, Date, Long, Integer, Short and Byte types automatically. " +
|
||||
|
@ -45,11 +44,10 @@ public class DefaultClaims extends JwtMap implements Claims {
|
|||
static final Field<Date> ISSUED_AT = Fields.rfcDate(Claims.ISSUED_AT, "Issued At");
|
||||
static final Field<String> JTI = Fields.string(Claims.ID, "JWT ID");
|
||||
|
||||
static final Set<Field<?>> FIELDS = Collections.<Field<?>>setOf(
|
||||
ISSUER, SUBJECT, AUDIENCE, EXPIRATION, NOT_BEFORE, ISSUED_AT, JTI
|
||||
);
|
||||
static final Registry<String, Field<?>> FIELDS =
|
||||
Fields.registry(ISSUER, SUBJECT, AUDIENCE, EXPIRATION, NOT_BEFORE, ISSUED_AT, JTI);
|
||||
|
||||
public DefaultClaims() {
|
||||
protected DefaultClaims() { // visibility for testing
|
||||
super(FIELDS);
|
||||
}
|
||||
|
||||
|
@ -64,86 +62,44 @@ public class DefaultClaims extends JwtMap implements Claims {
|
|||
|
||||
@Override
|
||||
public String getIssuer() {
|
||||
return idiomaticGet(ISSUER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setIssuer(String iss) {
|
||||
put(ISSUER, iss);
|
||||
return this;
|
||||
return get(ISSUER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubject() {
|
||||
return idiomaticGet(SUBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setSubject(String sub) {
|
||||
put(SUBJECT, sub);
|
||||
return this;
|
||||
return get(SUBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAudience() {
|
||||
return idiomaticGet(AUDIENCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setAudience(String aud) {
|
||||
put(AUDIENCE, aud);
|
||||
return this;
|
||||
return get(AUDIENCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getExpiration() {
|
||||
return idiomaticGet(EXPIRATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setExpiration(Date exp) {
|
||||
put(EXPIRATION, exp);
|
||||
return this;
|
||||
return get(EXPIRATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getNotBefore() {
|
||||
return idiomaticGet(NOT_BEFORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setNotBefore(Date nbf) {
|
||||
put(NOT_BEFORE, nbf);
|
||||
return this;
|
||||
return get(NOT_BEFORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getIssuedAt() {
|
||||
return idiomaticGet(ISSUED_AT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setIssuedAt(Date iat) {
|
||||
put(ISSUED_AT, iat);
|
||||
return this;
|
||||
return get(ISSUED_AT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return idiomaticGet(JTI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims setId(String jti) {
|
||||
put(JTI, jti);
|
||||
return this;
|
||||
return get(JTI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(String claimName, Class<T> requiredType) {
|
||||
Assert.notNull(requiredType, "requiredType argument cannot be null.");
|
||||
|
||||
Object value = idiomaticGet(claimName);
|
||||
Object value = this.idiomaticValues.get(claimName);
|
||||
if (requiredType.isInstance(value)) {
|
||||
return requiredType.cast(value);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.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>
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Claims build() {
|
||||
// ensure a new instance is returned so that the builder may be re-used:
|
||||
return new DefaultClaims(this.DELEGATE);
|
||||
}
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.DynamicHeaderBuilder;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.ProtectedHeader;
|
||||
import io.jsonwebtoken.impl.security.DefaultX509Builder;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class DefaultDynamicHeaderBuilder implements DynamicHeaderBuilder {
|
||||
|
||||
private Header<?> header;
|
||||
|
||||
private DefaultX509Builder<DynamicHeaderBuilder> x509Builder;
|
||||
|
||||
public DefaultDynamicHeaderBuilder() {
|
||||
this.header = new DefaultUnprotectedHeader();
|
||||
this.x509Builder = null;
|
||||
}
|
||||
|
||||
private ProtectedHeader<?> ensureProtected() {
|
||||
ProtectedHeader<?> ph;
|
||||
if (this.header instanceof ProtectedHeader<?>) {
|
||||
ph = (ProtectedHeader<?>) this.header;
|
||||
} else {
|
||||
this.header = ph = new DefaultJwsHeader(this.header);
|
||||
this.x509Builder = new DefaultX509Builder<DynamicHeaderBuilder>(ph, this, IllegalStateException.class);
|
||||
}
|
||||
return ph;
|
||||
}
|
||||
|
||||
private JweHeader ensureJwe() {
|
||||
JweHeader h;
|
||||
if (this.header instanceof JweHeader) {
|
||||
h = (JweHeader) this.header;
|
||||
} else {
|
||||
this.header = h = new DefaultJweHeader(this.header);
|
||||
this.x509Builder = new DefaultX509Builder<DynamicHeaderBuilder>(h, this, IllegalStateException.class);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder put(String key, Object value) {
|
||||
this.header.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder remove(String key) {
|
||||
this.header.remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder putAll(Map<? extends String, ?> m) {
|
||||
this.header.putAll(m);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder clear() {
|
||||
this.header.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setType(String typ) {
|
||||
this.header.setType(typ);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setContentType(String cty) {
|
||||
this.header.setContentType(cty);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setAlgorithm(String alg) {
|
||||
this.header.setAlgorithm(alg);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setCompressionAlgorithm(String zip) {
|
||||
this.header.setCompressionAlgorithm(zip);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setJwkSetUrl(URI uri) {
|
||||
ensureProtected().setJwkSetUrl(uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setJwk(PublicJwk<?> jwk) {
|
||||
ensureProtected().setJwk(jwk);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setKeyId(String kid) {
|
||||
ensureProtected().setKeyId(kid);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setCritical(Set<String> crit) {
|
||||
ensureProtected().setCritical(crit);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder withX509Sha1Thumbprint(boolean enable) {
|
||||
ensureProtected();
|
||||
return this.x509Builder.withX509Sha1Thumbprint(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder withX509Sha256Thumbprint(boolean enable) {
|
||||
ensureProtected();
|
||||
return this.x509Builder.withX509Sha256Thumbprint(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setX509Url(URI uri) {
|
||||
ensureProtected();
|
||||
return this.x509Builder.setX509Url(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setX509CertificateChain(List<X509Certificate> chain) {
|
||||
ensureProtected();
|
||||
return this.x509Builder.setX509CertificateChain(chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setX509CertificateSha1Thumbprint(byte[] thumbprint) {
|
||||
ensureProtected();
|
||||
return this.x509Builder.setX509CertificateSha1Thumbprint(thumbprint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setX509CertificateSha256Thumbprint(byte[] thumbprint) {
|
||||
ensureProtected();
|
||||
return this.x509Builder.setX509CertificateSha256Thumbprint(thumbprint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setAgreementPartyUInfo(byte[] info) {
|
||||
ensureJwe().setAgreementPartyUInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setAgreementPartyUInfo(String info) {
|
||||
ensureJwe().setAgreementPartyUInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setAgreementPartyVInfo(byte[] info) {
|
||||
ensureJwe().setAgreementPartyVInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setAgreementPartyVInfo(String info) {
|
||||
ensureJwe().setAgreementPartyVInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicHeaderBuilder setPbes2Count(int count) {
|
||||
ensureJwe().setPbes2Count(count);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Header<?> build() {
|
||||
if (this.x509Builder != null) {
|
||||
this.x509Builder.apply();
|
||||
}
|
||||
return this.header;
|
||||
}
|
||||
}
|
|
@ -18,13 +18,12 @@ package io.jsonwebtoken.impl;
|
|||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.lang.Fields;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractHeader<T extends Header<T>> extends JwtMap implements Header<T> {
|
||||
public class DefaultHeader extends FieldMap implements Header {
|
||||
|
||||
static final Field<String> TYPE = Fields.string(Header.TYPE, "Type");
|
||||
static final Field<String> CONTENT_TYPE = Fields.string(Header.CONTENT_TYPE, "Content Type");
|
||||
|
@ -34,14 +33,14 @@ public abstract class AbstractHeader<T extends Header<T>> extends JwtMap impleme
|
|||
@Deprecated // TODO: remove for 1.0.0:
|
||||
static final Field<String> DEPRECATED_COMPRESSION_ALGORITHM = Fields.string(Header.DEPRECATED_COMPRESSION_ALGORITHM, "Deprecated Compression Algorithm");
|
||||
|
||||
static final Set<Field<?>> FIELDS = Collections.<Field<?>>setOf(TYPE, CONTENT_TYPE, ALGORITHM, COMPRESSION_ALGORITHM, DEPRECATED_COMPRESSION_ALGORITHM);
|
||||
static final Registry<String, Field<?>> FIELDS = Fields.registry(TYPE, CONTENT_TYPE, ALGORITHM, COMPRESSION_ALGORITHM, DEPRECATED_COMPRESSION_ALGORITHM);
|
||||
|
||||
protected AbstractHeader(Set<Field<?>> fieldSet) {
|
||||
super(fieldSet);
|
||||
public DefaultHeader(Map<String, ?> values) {
|
||||
super(FIELDS, values);
|
||||
}
|
||||
|
||||
protected AbstractHeader(Set<Field<?>> fieldSet, Map<String, ?> values) {
|
||||
super(fieldSet, values);
|
||||
protected DefaultHeader(Registry<String, Field<?>> fields, Map<String, ?> values) {
|
||||
super(fields, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,56 +48,27 @@ public abstract class AbstractHeader<T extends Header<T>> extends JwtMap impleme
|
|||
return "JWT header";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T tthis() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return idiomaticGet(TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setType(String typ) {
|
||||
put(TYPE, typ);
|
||||
return tthis();
|
||||
return get(TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return idiomaticGet(CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setContentType(String cty) {
|
||||
put(CONTENT_TYPE, cty);
|
||||
return tthis();
|
||||
return get(CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return idiomaticGet(ALGORITHM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setAlgorithm(String alg) {
|
||||
put(ALGORITHM, alg);
|
||||
return tthis();
|
||||
return get(ALGORITHM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCompressionAlgorithm() {
|
||||
String s = idiomaticGet(COMPRESSION_ALGORITHM);
|
||||
String s = get(COMPRESSION_ALGORITHM);
|
||||
if (!Strings.hasText(s)) {
|
||||
s = idiomaticGet(DEPRECATED_COMPRESSION_ALGORITHM);
|
||||
s = get(DEPRECATED_COMPRESSION_ALGORITHM);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setCompressionAlgorithm(String compressionAlgorithm) {
|
||||
put(COMPRESSION_ALGORITHM, compressionAlgorithm);
|
||||
return tthis();
|
||||
}
|
||||
}
|
|
@ -21,33 +21,27 @@ import io.jsonwebtoken.io.Encoders;
|
|||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Objects;
|
||||
|
||||
public class DefaultJwe<P> extends DefaultJwt<JweHeader, P> implements Jwe<P> {
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class DefaultJwe<P> extends DefaultProtectedJwt<JweHeader, P> implements Jwe<P> {
|
||||
|
||||
private static final String DIGEST_NAME = "tag";
|
||||
|
||||
private final byte[] iv;
|
||||
private final byte[] aadTag;
|
||||
|
||||
public DefaultJwe(JweHeader header, P body, byte[] iv, byte[] aadTag) {
|
||||
super(header, body);
|
||||
super(header, body, aadTag, DIGEST_NAME);
|
||||
this.iv = Assert.notEmpty(iv, "Initialization vector cannot be null or empty.");
|
||||
this.aadTag = Assert.notEmpty(aadTag, "AAD tag cannot be null or empty.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getInitializationVector() {
|
||||
return this.iv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAadTag() {
|
||||
return this.aadTag;
|
||||
return this.iv.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder toStringBuilder() {
|
||||
StringBuilder sb = super.toStringBuilder();
|
||||
sb.append(",iv=").append(Encoders.BASE64URL.encode(this.iv));
|
||||
sb.append(",tag=").append(Encoders.BASE64URL.encode(this.aadTag));
|
||||
return sb;
|
||||
return super.toStringBuilder().append(",iv=").append(Encoders.BASE64URL.encode(this.iv));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,15 +51,13 @@ public class DefaultJwe<P> extends DefaultJwt<JweHeader, P> implements Jwe<P> {
|
|||
}
|
||||
if (obj instanceof Jwe) {
|
||||
Jwe<?> jwe = (Jwe<?>) obj;
|
||||
return super.equals(jwe) &&
|
||||
Objects.nullSafeEquals(iv, jwe.getInitializationVector()) &&
|
||||
Objects.nullSafeEquals(aadTag, jwe.getAadTag());
|
||||
return super.equals(jwe) && MessageDigest.isEqual(this.iv, jwe.getInitializationVector());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.nullSafeHashCode(getHeader(), getPayload(), iv, aadTag);
|
||||
return Objects.nullSafeHashCode(getHeader(), getPayload(), this.iv, this.digest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.impl.lang.Bytes;
|
||||
import io.jsonwebtoken.impl.lang.Converters;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.lang.Fields;
|
||||
|
@ -23,19 +24,18 @@ import io.jsonwebtoken.impl.lang.PositiveIntegerConverter;
|
|||
import io.jsonwebtoken.impl.lang.RequiredBitLengthConverter;
|
||||
import io.jsonwebtoken.impl.security.JwkConverter;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Header implementation satisfying JWE header parameter requirements.
|
||||
*
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class DefaultJweHeader extends AbstractProtectedHeader<JweHeader> implements JweHeader {
|
||||
public class DefaultJweHeader extends DefaultProtectedHeader implements JweHeader {
|
||||
|
||||
static final Field<String> ENCRYPTION_ALGORITHM = Fields.string("enc", "Encryption Algorithm");
|
||||
|
||||
|
@ -60,10 +60,18 @@ public class DefaultJweHeader extends AbstractProtectedHeader<JweHeader> impleme
|
|||
public static final Field<Integer> P2C = Fields.builder(Integer.class)
|
||||
.setConverter(PositiveIntegerConverter.INSTANCE).setId("p2c").setName("PBES2 Count").build();
|
||||
|
||||
static final Set<Field<?>> FIELDS = Collections.concat(AbstractProtectedHeader.FIELDS, ENCRYPTION_ALGORITHM, EPK, APU, APV, IV, TAG, P2S, P2C);
|
||||
static final Registry<String, Field<?>> FIELDS =
|
||||
Fields.registry(DefaultProtectedHeader.FIELDS, ENCRYPTION_ALGORITHM, EPK, APU, APV, IV, TAG, P2S, P2C);
|
||||
|
||||
public DefaultJweHeader() {
|
||||
super(FIELDS);
|
||||
static boolean isCandidate(FieldMap fields) {
|
||||
return Strings.hasText(fields.get(ENCRYPTION_ALGORITHM)) || // MUST have at least an `enc` header
|
||||
!Collections.isEmpty(fields.get(EPK)) ||
|
||||
!Bytes.isEmpty(fields.get(APU)) ||
|
||||
!Bytes.isEmpty(fields.get(APV)) ||
|
||||
!Bytes.isEmpty(fields.get(IV)) ||
|
||||
!Bytes.isEmpty(fields.get(TAG)) ||
|
||||
!Bytes.isEmpty(fields.get(P2S)) ||
|
||||
(fields.get(P2C) != null && fields.get(P2C) > 0);
|
||||
}
|
||||
|
||||
public DefaultJweHeader(Map<String, ?> map) {
|
||||
|
@ -77,70 +85,40 @@ public class DefaultJweHeader extends AbstractProtectedHeader<JweHeader> impleme
|
|||
|
||||
@Override
|
||||
public String getEncryptionAlgorithm() {
|
||||
return idiomaticGet(ENCRYPTION_ALGORITHM);
|
||||
return get(ENCRYPTION_ALGORITHM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicJwk<?> getEphemeralPublicKey() {
|
||||
return idiomaticGet(EPK);
|
||||
return get(EPK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAgreementPartyUInfo() {
|
||||
return idiomaticGet(APU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeader setAgreementPartyUInfo(byte[] info) {
|
||||
put(APU, info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeader setAgreementPartyUInfo(String info) {
|
||||
byte[] bytes = Strings.hasText(info) ? info.getBytes(StandardCharsets.UTF_8) : null;
|
||||
return setAgreementPartyUInfo(bytes);
|
||||
return get(APU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAgreementPartyVInfo() {
|
||||
return idiomaticGet(APV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeader setAgreementPartyVInfo(byte[] info) {
|
||||
put(APV, info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeader setAgreementPartyVInfo(String info) {
|
||||
byte[] bytes = Strings.hasText(info) ? info.getBytes(StandardCharsets.UTF_8) : null;
|
||||
return setAgreementPartyVInfo(bytes);
|
||||
return get(APV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getInitializationVector() {
|
||||
return idiomaticGet(IV);
|
||||
return get(IV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAuthenticationTag() {
|
||||
return idiomaticGet(TAG);
|
||||
return get(TAG);
|
||||
}
|
||||
|
||||
public byte[] getPbes2Salt() {
|
||||
return idiomaticGet(P2S);
|
||||
return get(P2S);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPbes2Count() {
|
||||
return idiomaticGet(P2C);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeader setPbes2Count(int count) {
|
||||
put(P2C, count);
|
||||
return this;
|
||||
return get(P2C);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
* Copyright (C) 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.
|
||||
|
@ -15,46 +15,33 @@
|
|||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.JweHeaderMutator;
|
||||
import io.jsonwebtoken.security.X509Builder;
|
||||
|
||||
/**
|
||||
* @param <T> return type for method chaining
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class DefaultJweHeaderBuilder extends AbstractProtectedHeaderBuilder<JweHeader, JweHeaderBuilder>
|
||||
implements JweHeaderBuilder {
|
||||
public class DefaultJweHeaderBuilder<T extends JweHeaderMutator<T> & X509Builder<T>>
|
||||
extends DefaultJweHeaderMutator<T> implements X509Builder<T> {
|
||||
|
||||
@Override
|
||||
protected JweHeader newHeader() {
|
||||
return new DefaultJweHeader();
|
||||
protected DefaultJweHeaderBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected DefaultJweHeaderBuilder(DefaultJweHeaderMutator<?> src) {
|
||||
super(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeaderBuilder setAgreementPartyUInfo(byte[] info) {
|
||||
this.header.setAgreementPartyUInfo(info);
|
||||
return this;
|
||||
public T withX509Sha1Thumbprint(boolean enable) {
|
||||
this.x509.withX509Sha1Thumbprint(enable);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeaderBuilder setAgreementPartyUInfo(String info) {
|
||||
this.header.setAgreementPartyUInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeaderBuilder setAgreementPartyVInfo(byte[] info) {
|
||||
this.header.setAgreementPartyVInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeaderBuilder setAgreementPartyVInfo(String info) {
|
||||
this.header.setAgreementPartyVInfo(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JweHeaderBuilder setPbes2Count(int count) {
|
||||
this.header.setPbes2Count(count);
|
||||
return this;
|
||||
public T withX509Sha256Thumbprint(boolean enable) {
|
||||
this.x509.withX509Sha256Thumbprint(enable);
|
||||
return self();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 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.JweHeaderMutator;
|
||||
import io.jsonwebtoken.impl.lang.DelegatingMapMutator;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.security.X509BuilderSupport;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @param <T> return type for method chaining
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class DefaultJweHeaderMutator<T extends JweHeaderMutator<T>>
|
||||
extends DelegatingMapMutator<String, Object, FieldMap, T> implements JweHeaderMutator<T> {
|
||||
|
||||
protected X509BuilderSupport x509;
|
||||
|
||||
public DefaultJweHeaderMutator() {
|
||||
// Any type of header can be created, but JWE fields reflect all potential standard ones, so we use those fields
|
||||
// to catch any value being set, especially through generic 'put' or 'putAll' methods:
|
||||
super(new FieldMap(DefaultJweHeader.FIELDS));
|
||||
clear(); // initialize new X509Builder
|
||||
}
|
||||
|
||||
public DefaultJweHeaderMutator(DefaultJweHeaderMutator<?> src) {
|
||||
super(src.DELEGATE);
|
||||
this.x509 = src.x509;
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// MapMutator methods
|
||||
// =============================================================
|
||||
|
||||
private T put(Field<?> field, Object value) {
|
||||
this.DELEGATE.put(field, value);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
this.x509 = new X509BuilderSupport(this.DELEGATE, IllegalStateException.class);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// JWT Header methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public T setAlgorithm(String alg) {
|
||||
return put(DefaultHeader.ALGORITHM, alg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setContentType(String cty) {
|
||||
return put(DefaultHeader.CONTENT_TYPE, cty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setType(String typ) {
|
||||
return put(DefaultHeader.TYPE, typ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setCompressionAlgorithm(String zip) {
|
||||
return put(DefaultHeader.COMPRESSION_ALGORITHM, zip);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// Protected Header methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public T setJwkSetUrl(URI uri) {
|
||||
return put(DefaultProtectedHeader.JKU, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setJwk(PublicJwk<?> jwk) {
|
||||
return put(DefaultProtectedHeader.JWK, jwk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setKeyId(String kid) {
|
||||
return put(DefaultProtectedHeader.KID, kid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setCritical(Set<String> crit) {
|
||||
return put(DefaultProtectedHeader.CRIT, crit);
|
||||
}
|
||||
|
||||
|
||||
// =============================================================
|
||||
// X.509 methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public T setX509Url(URI uri) {
|
||||
this.x509.setX509Url(uri);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateChain(List<X509Certificate> chain) {
|
||||
this.x509.setX509CertificateChain(chain);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateSha1Thumbprint(byte[] thumbprint) {
|
||||
this.x509.setX509CertificateSha1Thumbprint(thumbprint);
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setX509CertificateSha256Thumbprint(byte[] thumbprint) {
|
||||
this.x509.setX509CertificateSha256Thumbprint(thumbprint);
|
||||
return self();
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// JWE Header methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public T setAgreementPartyUInfo(byte[] info) {
|
||||
return put(DefaultJweHeader.APU, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setAgreementPartyUInfo(String info) {
|
||||
return setAgreementPartyUInfo(Strings.utf8(Strings.clean(info)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setAgreementPartyVInfo(byte[] info) {
|
||||
return put(DefaultJweHeader.APV, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setAgreementPartyVInfo(String info) {
|
||||
return setAgreementPartyVInfo(Strings.utf8(Strings.clean(info)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setPbes2Count(int count) {
|
||||
return put(DefaultJweHeader.P2C, count);
|
||||
}
|
||||
}
|
|
@ -17,14 +17,16 @@ package io.jsonwebtoken.impl;
|
|||
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.lang.Objects;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
|
||||
public class DefaultJws<P> extends DefaultJwt<JwsHeader, P> implements Jws<P> {
|
||||
public class DefaultJws<P> extends DefaultProtectedJwt<JwsHeader, P> implements Jws<P> {
|
||||
|
||||
private static final String DIGEST_NAME = "signature";
|
||||
|
||||
private final String signature;
|
||||
|
||||
public DefaultJws(JwsHeader header, P body, String signature) {
|
||||
super(header, body);
|
||||
super(header, body, Decoders.BASE64URL.decode(signature), DIGEST_NAME);
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
|
@ -33,26 +35,4 @@ public class DefaultJws<P> extends DefaultJwt<JwsHeader, P> implements Jws<P> {
|
|||
return this.signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder toStringBuilder() {
|
||||
return super.toStringBuilder().append(",signature=").append(signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Jws) {
|
||||
Jws<?> jws = (Jws<?>) obj;
|
||||
return super.equals(jws) &&
|
||||
Objects.nullSafeEquals(signature, jws.getSignature());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.nullSafeHashCode(getHeader(), getPayload(), signature);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,17 +17,13 @@ package io.jsonwebtoken.impl;
|
|||
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class DefaultJwsHeader extends AbstractProtectedHeader<JwsHeader> implements JwsHeader {
|
||||
public class DefaultJwsHeader extends DefaultProtectedHeader implements JwsHeader {
|
||||
|
||||
static final Set<Field<?>> FIELDS = AbstractProtectedHeader.FIELDS; //same
|
||||
|
||||
public DefaultJwsHeader() {
|
||||
super(FIELDS);
|
||||
}
|
||||
static final Registry<String, Field<?>> FIELDS = DefaultProtectedHeader.FIELDS; //same
|
||||
|
||||
public DefaultJwsHeader(Map<String, ?> map) {
|
||||
super(FIELDS, map);
|
||||
|
|
|
@ -21,7 +21,7 @@ import io.jsonwebtoken.io.Encoders;
|
|||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Objects;
|
||||
|
||||
public class DefaultJwt<H extends Header<H>, P> implements Jwt<H, P> {
|
||||
public class DefaultJwt<H extends Header, P> implements Jwt<H, P> {
|
||||
|
||||
private final H header;
|
||||
private final P payload;
|
||||
|
|
|
@ -16,10 +16,8 @@
|
|||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.CompressionCodec;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.ClaimsBuilder;
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.JwtBuilder;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.impl.lang.Bytes;
|
||||
|
@ -31,16 +29,15 @@ import io.jsonwebtoken.impl.security.DefaultAeadRequest;
|
|||
import io.jsonwebtoken.impl.security.DefaultKeyRequest;
|
||||
import io.jsonwebtoken.impl.security.DefaultSecureRequest;
|
||||
import io.jsonwebtoken.impl.security.Pbes2HsAkwAlgorithm;
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.io.Encoder;
|
||||
import io.jsonwebtoken.io.Encoders;
|
||||
import io.jsonwebtoken.io.SerializationException;
|
||||
import io.jsonwebtoken.io.Serializer;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Builder;
|
||||
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;
|
||||
|
@ -66,15 +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;
|
||||
|
||||
protected Header<?> header;
|
||||
protected Claims claims;
|
||||
private final DefaultJwtBuilderHeader headerBuilder = new DefaultJwtBuilderHeader(this);
|
||||
|
||||
private final ClaimsBuilder claimsBuilder = new DefaultClaimsBuilder();
|
||||
|
||||
protected byte[] content;
|
||||
|
||||
private SecureDigestAlgorithm<Key, ?> sigAlg = Jwts.SIG.NONE;
|
||||
|
@ -93,7 +90,12 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
protected Function<Map<String, ?>, byte[]> claimsSerializer;
|
||||
|
||||
protected Encoder<byte[], String> base64UrlEncoder = Encoders.BASE64URL;
|
||||
protected CompressionCodec compressionCodec;
|
||||
protected CompressionAlgorithm compressionAlgorithm;
|
||||
|
||||
@Override
|
||||
public JwtBuilder.Header header() {
|
||||
return this.headerBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setProvider(Provider provider) {
|
||||
|
@ -143,50 +145,28 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setHeader(Header<?> header) {
|
||||
return setHeader(Jwts.header().putAll(header));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setHeader(Map<String, ?> header) {
|
||||
return setHeader(Jwts.header().putAll(header));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setHeader(Builder<? extends Header<?>> builder) {
|
||||
Assert.notNull(builder, "Builder cannot be null.");
|
||||
Header<?> header = builder.build();
|
||||
this.header = Assert.notNull(header, "Builder cannot produce a null Header instance.");
|
||||
public JwtBuilder setHeader(Map<String, ?> map) {
|
||||
this.headerBuilder.clear();
|
||||
this.headerBuilder.putAll(map);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setHeaderParams(Map<String, ?> params) {
|
||||
if (!Collections.isEmpty(params)) {
|
||||
Header<?> header = ensureHeader();
|
||||
header.putAll(params);
|
||||
}
|
||||
this.headerBuilder.putAll(params);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Header<?> ensureHeader() {
|
||||
if (this.header == null) {
|
||||
this.header = new DefaultUnprotectedHeader();
|
||||
}
|
||||
return this.header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setHeaderParam(String name, Object value) {
|
||||
ensureHeader().put(name, value);
|
||||
this.headerBuilder.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // TODO: remove for 1.0
|
||||
protected static <K extends Key> SecureDigestAlgorithm<K, ?> forSigningKey(K key) {
|
||||
@SuppressWarnings("deprecation")
|
||||
io.jsonwebtoken.SignatureAlgorithm alg = io.jsonwebtoken.SignatureAlgorithm.forSigningKey(key);
|
||||
return (SecureDigestAlgorithm<K, ?>) Jwts.SIG.get(alg.getValue());
|
||||
@SuppressWarnings("deprecation") io.jsonwebtoken.SignatureAlgorithm alg = io.jsonwebtoken.SignatureAlgorithm.forSigningKey(key);
|
||||
return (SecureDigestAlgorithm<K, ?>) Jwts.SIG.get().forKey(alg.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -239,7 +219,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
public JwtBuilder signWith(Key key, io.jsonwebtoken.SignatureAlgorithm alg) throws InvalidKeyException {
|
||||
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
|
||||
alg.assertValidSigningKey(key); //since 0.10.0 for https://github.com/jwtk/jjwt/issues/334
|
||||
return signWith(key, (SecureDigestAlgorithm<? super Key, ?>) Jwts.SIG.get(alg.getValue()));
|
||||
return signWith(key, (SecureDigestAlgorithm<? super Key, ?>) Jwts.SIG.get().forKey(alg.getValue()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // TODO: remove method for 1.0
|
||||
|
@ -304,9 +284,10 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder compressWith(CompressionCodec compressionCodec) {
|
||||
Assert.notNull(compressionCodec, "compressionCodec cannot be null");
|
||||
this.compressionCodec = compressionCodec;
|
||||
public JwtBuilder compressWith(CompressionAlgorithm alg) {
|
||||
Assert.notNull(alg, "CompressionAlgorithm cannot be null");
|
||||
Assert.hasText(alg.getId(), "CompressionAlgorithm id cannot be null or empty.");
|
||||
this.compressionAlgorithm = alg;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -327,87 +308,75 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
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);
|
||||
ensureHeader().setContentType(cty);
|
||||
this.headerBuilder.setContentType(cty);
|
||||
return setContent(content);
|
||||
}
|
||||
|
||||
protected Claims ensureClaims() {
|
||||
if (this.claims == null) {
|
||||
this.claims = new DefaultClaims();
|
||||
}
|
||||
return this.claims;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setClaims(Claims claims) {
|
||||
this.claims = claims;
|
||||
return this;
|
||||
Assert.notNull(claims, "Claims argument cannot be null.");
|
||||
return setClaims((Map<String, ?>) claims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setClaims(Map<String, ?> claims) {
|
||||
this.claims = new DefaultClaims(claims);
|
||||
Assert.notNull(claims, "Claims map cannot be null.");
|
||||
this.claimsBuilder.empty();
|
||||
this.claimsBuilder.set(claims);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder addClaims(Map<String, ?> claims) {
|
||||
ensureClaims().putAll(claims);
|
||||
this.claimsBuilder.set(claims);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setIssuer(String iss) {
|
||||
return claim(DefaultClaims.ISSUER.getId(), iss);
|
||||
this.claimsBuilder.setIssuer(iss);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setSubject(String sub) {
|
||||
return claim(DefaultClaims.SUBJECT.getId(), sub);
|
||||
this.claimsBuilder.setSubject(sub);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setAudience(String aud) {
|
||||
return claim(DefaultClaims.AUDIENCE.getId(), aud);
|
||||
this.claimsBuilder.setAudience(aud);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setExpiration(Date exp) {
|
||||
return claim(DefaultClaims.EXPIRATION.getId(), exp);
|
||||
this.claimsBuilder.setExpiration(exp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setNotBefore(Date nbf) {
|
||||
return claim(DefaultClaims.NOT_BEFORE.getId(), nbf);
|
||||
this.claimsBuilder.setNotBefore(nbf);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setIssuedAt(Date iat) {
|
||||
return claim(DefaultClaims.ISSUED_AT.getId(), iat);
|
||||
this.claimsBuilder.setIssuedAt(iat);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder setId(String jti) {
|
||||
return claim(DefaultClaims.JTI.getId(), jti);
|
||||
this.claimsBuilder.setId(jti);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder claim(String name, Object value) {
|
||||
Assert.hasText(name, "Claim property name cannot be null or empty.");
|
||||
if (value instanceof String && !Strings.hasText((String) value)) {
|
||||
value = null;
|
||||
}
|
||||
if (this.claims == null) {
|
||||
if (value != null) {
|
||||
ensureClaims().put(name, value);
|
||||
}
|
||||
} else {
|
||||
if (value == null) {
|
||||
this.claims.remove(name);
|
||||
} else {
|
||||
this.claims.put(name, value);
|
||||
}
|
||||
}
|
||||
this.claimsBuilder.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -421,6 +390,8 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
||||
final Claims claims = this.claimsBuilder.build();
|
||||
|
||||
if (Objects.isEmpty(content) && Collections.isEmpty(claims)) {
|
||||
if (jwe) { // JWE payload can never be empty:
|
||||
String msg = "Encrypted JWTs must have either 'claims' or non-empty 'content'.";
|
||||
|
@ -433,8 +404,6 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
throw new IllegalStateException("Both 'content' and 'claims' cannot both be specified. Choose either one.");
|
||||
}
|
||||
|
||||
Header<?> header = ensureHeader();
|
||||
|
||||
if (this.serializer == null) { // try to find one based on the services available
|
||||
//noinspection unchecked
|
||||
serializeToJsonWith(Services.loadFirst(Serializer.class));
|
||||
|
@ -444,28 +413,33 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
if (!Collections.isEmpty(claims)) {
|
||||
payload = claimsSerializer.apply(claims);
|
||||
}
|
||||
if (!Objects.isEmpty(payload) && compressionCodec != null) {
|
||||
payload = compressionCodec.compress(payload);
|
||||
header.setCompressionAlgorithm(compressionCodec.getId());
|
||||
if (!Objects.isEmpty(payload) && compressionAlgorithm != null) {
|
||||
payload = compressionAlgorithm.compress(payload);
|
||||
this.headerBuilder.setCompressionAlgorithm(compressionAlgorithm.getId());
|
||||
}
|
||||
|
||||
if (jwe) {
|
||||
JweHeader jweHeader = header instanceof JweHeader ? (JweHeader) header : new DefaultJweHeader(header);
|
||||
return encrypt(jweHeader, payload);
|
||||
return encrypt(payload);
|
||||
} else {
|
||||
return compact(header, payload);
|
||||
return compact(payload);
|
||||
}
|
||||
}
|
||||
|
||||
private String compact(Header<?> header, byte[] payload) {
|
||||
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);
|
||||
}
|
||||
// if (this.key != null && !(header instanceof JwsHeader)) {
|
||||
// header = new DefaultJwsHeader(header);
|
||||
// }
|
||||
|
||||
header.setAlgorithm(sigAlg.getId());
|
||||
this.headerBuilder.setAlgorithm(sigAlg.getId());
|
||||
|
||||
final io.jsonwebtoken.Header header = buildHeader();
|
||||
|
||||
byte[] headerBytes = headerSerializer.apply(header);
|
||||
String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes);
|
||||
|
@ -490,7 +464,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
return jwt;
|
||||
}
|
||||
|
||||
private String encrypt(JweHeader header, byte[] payload) {
|
||||
private String encrypt(byte[] payload) {
|
||||
|
||||
Assert.stateNotNull(key, "Key is required."); // set by encryptWith*
|
||||
Assert.stateNotNull(enc, "Encryption algorithm is required."); // set by encryptWith*
|
||||
|
@ -499,14 +473,20 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
Assert.stateNotNull(keyAlgFunction, "KeyAlgorithm function cannot be null.");
|
||||
Assert.notEmpty(payload, "JWE payload bytes cannot be empty."); // JWE invariant (JWS can be empty however)
|
||||
|
||||
KeyRequest<Key> keyRequest = new DefaultKeyRequest<>(this.key, this.provider, this.secureRandom, header, enc);
|
||||
//only expose (mutable) JweHeader functionality to KeyAlgorithm instances, not the full headerBuilder
|
||||
// (which exposes this JwtBuilder and shouldn't be referenced by KeyAlgorithms):
|
||||
JweHeader delegate = new DefaultMutableJweHeader(this.headerBuilder);
|
||||
KeyRequest<Key> keyRequest = new DefaultKeyRequest<>(this.key, this.provider, this.secureRandom, delegate, enc);
|
||||
KeyResult keyResult = keyAlgFunction.apply(keyRequest);
|
||||
Assert.stateNotNull(keyResult, "KeyAlgorithm must return a KeyResult.");
|
||||
|
||||
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.");
|
||||
|
||||
header.put(AbstractHeader.ALGORITHM.getId(), keyAlg.getId());
|
||||
header.put(DefaultJweHeader.ENCRYPTION_ALGORITHM.getId(), enc.getId());
|
||||
this.headerBuilder.setAlgorithm(keyAlg.getId());
|
||||
this.headerBuilder.put(DefaultJweHeader.ENCRYPTION_ALGORITHM.getId(), enc.getId());
|
||||
|
||||
final io.jsonwebtoken.Header header = buildHeader();
|
||||
|
||||
byte[] headerBytes = this.headerSerializer.apply(header);
|
||||
final String base64UrlEncodedHeader = base64UrlEncoder.encode(headerBytes);
|
||||
|
@ -524,10 +504,22 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
|||
String base64UrlEncodedCiphertext = base64UrlEncoder.encode(ciphertext);
|
||||
String base64UrlEncodedTag = base64UrlEncoder.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 final JwtBuilder builder;
|
||||
|
||||
public DefaultJwtBuilderHeader(JwtBuilder builder) {
|
||||
super();
|
||||
this.builder = Assert.notNull(builder, "JwtBuilder cannot be null.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtBuilder and() {
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
|
||||
/**
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public class DefaultJwtHeaderBuilder extends DefaultJweHeaderBuilder<Jwts.HeaderBuilder> implements Jwts.HeaderBuilder {
|
||||
|
||||
@SuppressWarnings("unused") // accessed via reflection from the Jwts.header() method implementation
|
||||
public DefaultJwtHeaderBuilder() {
|
||||
}
|
||||
|
||||
public DefaultJwtHeaderBuilder(DefaultJweHeaderMutator<?> src) {
|
||||
super(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Header build() {
|
||||
|
||||
this.x509.apply(); // apply any X.509 values as necessary based on builder state
|
||||
|
||||
//Use a copy constructor to ensure subsequent changes to builder state do not change the constructed header
|
||||
|
||||
// Note: conditional sequence matters here: JWE has more specific requirements than JWS, so check that first:
|
||||
if (DefaultJweHeader.isCandidate(this.DELEGATE)) {
|
||||
return new DefaultJweHeader(this.DELEGATE);
|
||||
} else if (DefaultProtectedHeader.isCandidate(this.DELEGATE)) {
|
||||
return new DefaultJwsHeader(this.DELEGATE);
|
||||
} else {
|
||||
return new DefaultHeader(this.DELEGATE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,12 +16,11 @@
|
|||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ClaimsBuilder;
|
||||
import io.jsonwebtoken.Clock;
|
||||
import io.jsonwebtoken.CompressionCodec;
|
||||
import io.jsonwebtoken.CompressionCodecResolver;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Identifiable;
|
||||
import io.jsonwebtoken.IncorrectClaimException;
|
||||
import io.jsonwebtoken.Jwe;
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
|
@ -38,18 +37,16 @@ import io.jsonwebtoken.MalformedJwtException;
|
|||
import io.jsonwebtoken.MissingClaimException;
|
||||
import io.jsonwebtoken.PrematureJwtException;
|
||||
import io.jsonwebtoken.SigningKeyResolver;
|
||||
import io.jsonwebtoken.UnprotectedHeader;
|
||||
import io.jsonwebtoken.UnsupportedJwtException;
|
||||
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
|
||||
import io.jsonwebtoken.impl.lang.Bytes;
|
||||
import io.jsonwebtoken.impl.lang.Function;
|
||||
import io.jsonwebtoken.impl.lang.IdRegistry;
|
||||
import io.jsonwebtoken.impl.lang.LegacyServices;
|
||||
import io.jsonwebtoken.impl.security.ConstantKeyLocator;
|
||||
import io.jsonwebtoken.impl.security.DefaultAeadResult;
|
||||
import io.jsonwebtoken.impl.security.DefaultDecryptionKeyRequest;
|
||||
import io.jsonwebtoken.impl.security.DefaultVerifySecureDigestRequest;
|
||||
import io.jsonwebtoken.impl.security.LocatingKeyResolver;
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.io.DecodingException;
|
||||
|
@ -78,7 +75,6 @@ import java.security.Key;
|
|||
import java.security.Provider;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -114,12 +110,12 @@ public class DefaultJwtParser implements JwtParser {
|
|||
"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 " +
|
||||
AbstractHeader.ALGORITHM + " header value of '" + Jwts.SIG.NONE.getId() + "') are disallowed by " +
|
||||
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: ";
|
||||
|
||||
private static final String JWE_NONE_MSG = "JWEs do not support key management " + AbstractHeader.ALGORITHM +
|
||||
private static final String JWE_NONE_MSG = "JWEs do not support key management " + DefaultHeader.ALGORITHM +
|
||||
" header value '" + Jwts.SIG.NONE.getId() + "' per " +
|
||||
"https://www.rfc-editor.org/rfc/rfc7518.html#section-4.1";
|
||||
|
||||
|
@ -127,7 +123,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
Jwts.SIG.NONE.getId() + "' yet the compact JWS string contains a signature. This is not permitted " +
|
||||
"per https://tools.ietf.org/html/rfc7518#section-3.6.";
|
||||
private static final String UNPROTECTED_DECOMPRESSION_MSG = "The JWT header references compression algorithm " +
|
||||
"'%s', but payload decompression for Unsecured JWTs (those with an " + AbstractHeader.ALGORITHM +
|
||||
"'%s', but payload decompression for Unsecured JWTs (those with an " + DefaultHeader.ALGORITHM +
|
||||
" header value of '" + Jwts.SIG.NONE.getId() + "') are " + "disallowed by default to protect " +
|
||||
"against [Denial of Service attacks](" +
|
||||
"https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-pellegrino.pdf). If you " +
|
||||
|
@ -135,29 +131,20 @@ public class DefaultJwtParser implements JwtParser {
|
|||
"enableUnsecuredDecompression() method (but please read the security considerations covered in that " +
|
||||
"method's JavaDoc before doing so).";
|
||||
|
||||
private static <I extends Identifiable> IdRegistry<I> newRegistry(String name, Collection<I> defaults, Collection<I> extras) {
|
||||
Collection<I> all = new LinkedHashSet<>(Collections.size(extras) + defaults.size());
|
||||
all.addAll(extras);
|
||||
all.addAll(defaults);
|
||||
return new IdRegistry<>(name, all);
|
||||
}
|
||||
|
||||
private static Function<JwsHeader, SecureDigestAlgorithm<?, ?>> sigFn(Collection<SecureDigestAlgorithm<?, ?>> extras) {
|
||||
String name = "JWS MAC or Signature Algorithm";
|
||||
IdRegistry<SecureDigestAlgorithm<?, ?>> registry = newRegistry(name, Jwts.SIG.values(), extras);
|
||||
return new IdLocator<>(AbstractHeader.ALGORITHM, MISSING_JWS_ALG_MSG, registry);
|
||||
return new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.SIG.get(), extras, MISSING_JWS_ALG_MSG);
|
||||
}
|
||||
|
||||
private static Function<JweHeader, AeadAlgorithm> encFn(Collection<AeadAlgorithm> extras) {
|
||||
String name = "JWE Encryption Algorithm";
|
||||
IdRegistry<AeadAlgorithm> registry = newRegistry(name, Jwts.ENC.values(), extras);
|
||||
return new IdLocator<>(DefaultJweHeader.ENCRYPTION_ALGORITHM, MISSING_ENC_MSG, registry);
|
||||
return new IdLocator<>(DefaultJweHeader.ENCRYPTION_ALGORITHM, Jwts.ENC.get(), extras, MISSING_ENC_MSG);
|
||||
}
|
||||
|
||||
private static Function<JweHeader, KeyAlgorithm<?, ?>> keyFn(Collection<KeyAlgorithm<?, ?>> extras) {
|
||||
String name = "JWE Key Management Algorithm";
|
||||
IdRegistry<KeyAlgorithm<?, ?>> registry = newRegistry(name, Jwts.KEY.values(), extras);
|
||||
return new IdLocator<>(AbstractHeader.ALGORITHM, MISSING_JWE_ALG_MSG, registry);
|
||||
return new IdLocator<>(DefaultHeader.ALGORITHM, Jwts.KEY.get(), extras, MISSING_JWE_ALG_MSG);
|
||||
}
|
||||
|
||||
private static IdLocator<Header, CompressionAlgorithm> zipFn(Collection<CompressionAlgorithm> extras) {
|
||||
return new IdLocator<>(DefaultHeader.COMPRESSION_ALGORITHM, Jwts.ZIP.get(), extras, null);
|
||||
}
|
||||
|
||||
// TODO: make the following fields final for v1.0
|
||||
|
@ -166,8 +153,6 @@ public class DefaultJwtParser implements JwtParser {
|
|||
@SuppressWarnings("deprecation") // will remove for 1.0
|
||||
private SigningKeyResolver signingKeyResolver;
|
||||
|
||||
private Locator<CompressionCodec> compressionCodecLocator;
|
||||
|
||||
private final boolean enableUnsecuredJws;
|
||||
|
||||
private final boolean enableUnsecuredDecompression;
|
||||
|
@ -178,13 +163,15 @@ public class DefaultJwtParser implements JwtParser {
|
|||
|
||||
private final Function<JweHeader, KeyAlgorithm<?, ?>> keyAlgorithmLocator;
|
||||
|
||||
private Function<Header, CompressionAlgorithm> compressionAlgorithmLocator;
|
||||
|
||||
private final Locator<? extends Key> keyLocator;
|
||||
|
||||
private Decoder<String, byte[]> base64UrlDecoder = Decoders.BASE64URL;
|
||||
|
||||
private Deserializer<Map<String, ?>> deserializer;
|
||||
|
||||
private Claims expectedClaims = new DefaultClaims();
|
||||
private ClaimsBuilder expectedClaims = Jwts.claims();
|
||||
|
||||
private Clock clock = DefaultClock.INSTANCE;
|
||||
|
||||
|
@ -202,7 +189,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
this.signatureAlgorithmLocator = sigFn(Collections.<SecureDigestAlgorithm<?, ?>>emptyList());
|
||||
this.keyAlgorithmLocator = keyFn(Collections.<KeyAlgorithm<?, ?>>emptyList());
|
||||
this.encryptionAlgorithmLocator = encFn(Collections.<AeadAlgorithm>emptyList());
|
||||
this.compressionCodecLocator = new DefaultCompressionCodecResolver();
|
||||
this.compressionAlgorithmLocator = zipFn(Collections.<CompressionAlgorithm>emptyList());
|
||||
this.enableUnsecuredJws = false;
|
||||
this.enableUnsecuredDecompression = false;
|
||||
}
|
||||
|
@ -216,10 +203,11 @@ public class DefaultJwtParser implements JwtParser {
|
|||
Locator<? extends Key> keyLocator,
|
||||
Clock clock,
|
||||
long allowedClockSkewMillis,
|
||||
Claims expectedClaims,
|
||||
DefaultClaims expectedClaims,
|
||||
Decoder<String, byte[]> base64UrlDecoder,
|
||||
Deserializer<Map<String, ?>> deserializer,
|
||||
Locator<CompressionCodec> compressionCodecLocator,
|
||||
CompressionCodecResolver compressionCodecResolver,
|
||||
Collection<CompressionAlgorithm> extraZipAlgs,
|
||||
Collection<SecureDigestAlgorithm<?, ?>> extraSigAlgs,
|
||||
Collection<KeyAlgorithm<?, ?>> extraKeyAlgs,
|
||||
Collection<AeadAlgorithm> extraEncAlgs) {
|
||||
|
@ -230,13 +218,18 @@ public class DefaultJwtParser implements JwtParser {
|
|||
this.keyLocator = Assert.notNull(keyLocator, "Key Locator cannot be null.");
|
||||
this.clock = clock;
|
||||
this.allowedClockSkewMillis = allowedClockSkewMillis;
|
||||
this.expectedClaims = expectedClaims;
|
||||
this.expectedClaims = Jwts.claims().set(expectedClaims);
|
||||
this.base64UrlDecoder = base64UrlDecoder;
|
||||
this.deserializer = deserializer;
|
||||
this.signatureAlgorithmLocator = sigFn(extraSigAlgs);
|
||||
this.keyAlgorithmLocator = keyFn(extraKeyAlgs);
|
||||
this.encryptionAlgorithmLocator = encFn(extraEncAlgs);
|
||||
this.compressionCodecLocator = Assert.notNull(compressionCodecLocator, "CompressionCodec locator cannot be null.");
|
||||
|
||||
if (compressionCodecResolver != null) {
|
||||
this.compressionAlgorithmLocator = new CompressionCodecLocator(compressionCodecResolver);
|
||||
} else {
|
||||
this.compressionAlgorithmLocator = zipFn(extraZipAlgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -299,7 +292,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
public JwtParser require(String claimName, Object value) {
|
||||
Assert.hasText(claimName, "claim name cannot be null or empty.");
|
||||
Assert.notNull(value, "The value cannot be null for claim name: " + claimName);
|
||||
expectedClaims.put(claimName, value);
|
||||
expectedClaims.set(claimName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -347,9 +340,9 @@ public class DefaultJwtParser implements JwtParser {
|
|||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public JwtParser setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) {
|
||||
Assert.notNull(compressionCodecResolver, "compressionCodecResolver cannot be null.");
|
||||
this.compressionCodecLocator = new CompressionCodecLocator(compressionCodecResolver);
|
||||
public JwtParser setCompressionCodecResolver(CompressionCodecResolver resolver) {
|
||||
Assert.notNull(resolver, "CompressionCodecResolver cannot be null.");
|
||||
this.compressionAlgorithmLocator = new CompressionCodecLocator(resolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -366,7 +359,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean hasContentType(Header<?> header) {
|
||||
private static boolean hasContentType(Header header) {
|
||||
return header != null && Strings.hasText(header.getContentType());
|
||||
}
|
||||
|
||||
|
@ -522,7 +515,7 @@ public class DefaultJwtParser implements JwtParser {
|
|||
// =============== Header =================
|
||||
final byte[] headerBytes = base64UrlDecode(base64UrlHeader, "protected header");
|
||||
Map<String, ?> m = readValue(headerBytes, "protected header");
|
||||
Header<?> header;
|
||||
Header header;
|
||||
try {
|
||||
header = tokenized.createHeader(m);
|
||||
} catch (Exception e) {
|
||||
|
@ -646,13 +639,13 @@ public class DefaultJwtParser implements JwtParser {
|
|||
verifySignature(tokenized, ((JwsHeader) header), alg, new LocatingKeyResolver(this.keyLocator), null, null);
|
||||
}
|
||||
|
||||
CompressionCodec compressionCodec = compressionCodecLocator.locate(header);
|
||||
if (compressionCodec != null) {
|
||||
CompressionAlgorithm compressionAlgorithm = compressionAlgorithmLocator.apply(header);
|
||||
if (compressionAlgorithm != null) {
|
||||
if (unsecured && !enableUnsecuredDecompression) {
|
||||
String msg = String.format(UNPROTECTED_DECOMPRESSION_MSG, compressionCodec.getId());
|
||||
String msg = String.format(UNPROTECTED_DECOMPRESSION_MSG, compressionAlgorithm.getId());
|
||||
throw new UnsupportedJwtException(msg);
|
||||
}
|
||||
payload = compressionCodec.decompress(payload);
|
||||
payload = compressionAlgorithm.decompress(payload);
|
||||
}
|
||||
|
||||
Claims claims = null;
|
||||
|
@ -757,11 +750,13 @@ public class DefaultJwtParser implements JwtParser {
|
|||
return o;
|
||||
}
|
||||
|
||||
private void validateExpectedClaims(Header<?> header, Claims claims) {
|
||||
private void validateExpectedClaims(Header header, Claims claims) {
|
||||
|
||||
for (String expectedClaimName : expectedClaims.keySet()) {
|
||||
final Claims expected = expectedClaims.build();
|
||||
|
||||
Object expectedClaimValue = normalize(expectedClaims.get(expectedClaimName));
|
||||
for (String expectedClaimName : expected.keySet()) {
|
||||
|
||||
Object expectedClaimValue = normalize(expected.get(expectedClaimName));
|
||||
Object actualClaimValue = normalize(claims.get(expectedClaimName));
|
||||
|
||||
if (expectedClaimValue instanceof Date) {
|
||||
|
@ -813,28 +808,28 @@ public class DefaultJwtParser implements JwtParser {
|
|||
} else {
|
||||
Object body = jwt.getPayload();
|
||||
if (body instanceof Claims) {
|
||||
return handler.onClaimsJwt((Jwt<UnprotectedHeader, Claims>) jwt);
|
||||
return handler.onClaimsJwt((Jwt<Header, Claims>) jwt);
|
||||
} else {
|
||||
return handler.onContentJwt((Jwt<UnprotectedHeader, byte[]>) jwt);
|
||||
return handler.onContentJwt((Jwt<Header, byte[]>) jwt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jwt<UnprotectedHeader, byte[]> parseContentJwt(String compact) {
|
||||
return parse(compact, new JwtHandlerAdapter<Jwt<UnprotectedHeader, byte[]>>() {
|
||||
public Jwt<Header, byte[]> parseContentJwt(String compact) {
|
||||
return parse(compact, new JwtHandlerAdapter<Jwt<Header, byte[]>>() {
|
||||
@Override
|
||||
public Jwt<UnprotectedHeader, byte[]> onContentJwt(Jwt<UnprotectedHeader, byte[]> jwt) {
|
||||
public Jwt<Header, byte[]> onContentJwt(Jwt<Header, byte[]> jwt) {
|
||||
return jwt;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jwt<UnprotectedHeader, Claims> parseClaimsJwt(String compact) {
|
||||
return parse(compact, new JwtHandlerAdapter<Jwt<UnprotectedHeader, Claims>>() {
|
||||
public Jwt<Header, Claims> parseClaimsJwt(String compact) {
|
||||
return parse(compact, new JwtHandlerAdapter<Jwt<Header, Claims>>() {
|
||||
@Override
|
||||
public Jwt<UnprotectedHeader, Claims> onClaimsJwt(Jwt<UnprotectedHeader, Claims> jwt) {
|
||||
public Jwt<Header, Claims> onClaimsJwt(Jwt<Header, Claims> jwt) {
|
||||
return jwt;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -15,17 +15,17 @@
|
|||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ClaimsBuilder;
|
||||
import io.jsonwebtoken.Clock;
|
||||
import io.jsonwebtoken.CompressionCodec;
|
||||
import io.jsonwebtoken.CompressionCodecResolver;
|
||||
import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.JwtParserBuilder;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.Locator;
|
||||
import io.jsonwebtoken.SigningKeyResolver;
|
||||
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
|
||||
import io.jsonwebtoken.impl.lang.Services;
|
||||
import io.jsonwebtoken.impl.security.ConstantKeyLocator;
|
||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.io.Deserializer;
|
||||
|
@ -71,21 +71,22 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
|||
@SuppressWarnings("deprecation") //TODO: remove for 1.0
|
||||
private SigningKeyResolver signingKeyResolver = null;
|
||||
|
||||
private Locator<CompressionCodec> compressionCodecLocator;
|
||||
private final Collection<AeadAlgorithm> extraEncAlgs = new LinkedHashSet<>();
|
||||
|
||||
private final Collection<AeadAlgorithm> extraEncryptionAlgorithms = new LinkedHashSet<>();
|
||||
private final Collection<KeyAlgorithm<?, ?>> extraKeyAlgs = new LinkedHashSet<>();
|
||||
|
||||
private final Collection<KeyAlgorithm<?, ?>> extraKeyAlgorithms = new LinkedHashSet<>();
|
||||
private final Collection<SecureDigestAlgorithm<?, ?>> extraSigAlgs = new LinkedHashSet<>();
|
||||
|
||||
private final Collection<SecureDigestAlgorithm<?, ?>> extraDigestAlgorithms = new LinkedHashSet<>();
|
||||
private final Collection<CompressionAlgorithm> extraZipAlgs = new LinkedHashSet<>();
|
||||
|
||||
private final Collection<CompressionCodec> extraCompressionCodecs = new LinkedHashSet<>();
|
||||
@SuppressWarnings("deprecation")
|
||||
private CompressionCodecResolver compressionCodecResolver;
|
||||
|
||||
private Decoder<String, byte[]> base64UrlDecoder = Decoders.BASE64URL;
|
||||
|
||||
private Deserializer<Map<String, ?>> deserializer;
|
||||
|
||||
private final Claims expectedClaims = new DefaultClaims();
|
||||
private final ClaimsBuilder expectedClaims = Jwts.claims();
|
||||
|
||||
private Clock clock = DefaultClock.INSTANCE;
|
||||
|
||||
|
@ -172,7 +173,7 @@ 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.put(claimName, value);
|
||||
expectedClaims.set(claimName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -221,30 +222,30 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JwtParserBuilder addCompressionCodecs(Collection<? extends CompressionCodec> codecs) {
|
||||
Assert.notEmpty(codecs, "Additional CompressionCodec collection cannot be null or empty.");
|
||||
this.extraCompressionCodecs.addAll(codecs);
|
||||
public JwtParserBuilder addCompressionAlgorithms(Collection<? extends CompressionAlgorithm> algs) {
|
||||
Assert.notEmpty(algs, "Additional CompressionAlgorithm collection cannot be null or empty.");
|
||||
this.extraZipAlgs.addAll(algs);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParserBuilder addEncryptionAlgorithms(Collection<? extends AeadAlgorithm> encAlgs) {
|
||||
Assert.notEmpty(encAlgs, "Additional AeadAlgorithm collection cannot be null or empty.");
|
||||
this.extraEncryptionAlgorithms.addAll(encAlgs);
|
||||
this.extraEncAlgs.addAll(encAlgs);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParserBuilder addSignatureAlgorithms(Collection<? extends SecureDigestAlgorithm<?, ?>> sigAlgs) {
|
||||
Assert.notEmpty(sigAlgs, "Additional SignatureAlgorithm collection cannot be null or empty.");
|
||||
this.extraDigestAlgorithms.addAll(sigAlgs);
|
||||
this.extraSigAlgs.addAll(sigAlgs);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParserBuilder addKeyAlgorithms(Collection<? extends KeyAlgorithm<?, ?>> keyAlgs) {
|
||||
Assert.notEmpty(keyAlgs, "Additional KeyAlgorithm collection cannot be null or empty.");
|
||||
this.extraKeyAlgorithms.addAll(keyAlgs);
|
||||
this.extraKeyAlgs.addAll(keyAlgs);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -262,16 +263,10 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JwtParserBuilder setCompressionCodecLocator(Locator<CompressionCodec> locator) {
|
||||
this.compressionCodecLocator = Assert.notNull(locator, "CompressionCodec locator cannot be null.");
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver resolver) {
|
||||
Assert.notNull(resolver, "compressionCodecResolver cannot be null.");
|
||||
this.compressionCodecLocator = new CompressionCodecLocator(resolver);
|
||||
this.compressionCodecResolver = Assert.notNull(resolver, "CompressionCodecResolver cannot be null.");
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -305,19 +300,17 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
|||
"due to their security implications.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (this.compressionCodecLocator != null && !Collections.isEmpty(extraCompressionCodecs)) {
|
||||
String msg = "Both 'addCompressionCodecs' and 'compressionCodecLocator' " +
|
||||
"(or 'compressionCodecResolver') cannot be specified. Choose either.";
|
||||
if (this.compressionCodecResolver != null && !Collections.isEmpty(extraZipAlgs)) {
|
||||
String msg = "Both 'addCompressionAlgorithms' and 'compressionCodecResolver' " +
|
||||
"cannot be specified. Choose either.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (this.compressionCodecLocator == null) {
|
||||
this.compressionCodecLocator = new DefaultCompressionCodecResolver(extraCompressionCodecs);
|
||||
}
|
||||
|
||||
// Invariants. If these are ever violated, it's an error in this class implementation
|
||||
// (we default to non-null instances, and the setters should never allow null):
|
||||
Assert.stateNotNull(this.keyLocator, "Key locator should never be null.");
|
||||
Assert.stateNotNull(this.compressionCodecLocator, "CompressionCodec Locator should never be null.");
|
||||
|
||||
final DefaultClaims expClaims = (DefaultClaims) this.expectedClaims.build();
|
||||
|
||||
return new ImmutableJwtParser(new DefaultJwtParser(
|
||||
provider,
|
||||
|
@ -327,13 +320,14 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
|||
keyLocator,
|
||||
clock,
|
||||
allowedClockSkewMillis,
|
||||
expectedClaims,
|
||||
expClaims,
|
||||
base64UrlDecoder,
|
||||
new JwtDeserializer<>(deserializer),
|
||||
compressionCodecLocator,
|
||||
extraDigestAlgorithms,
|
||||
extraKeyAlgorithms,
|
||||
extraEncryptionAlgorithms
|
||||
compressionCodecResolver,
|
||||
extraZipAlgs,
|
||||
extraSigAlgs,
|
||||
extraKeyAlgs,
|
||||
extraEncAlgs
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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.JweHeader;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DefaultMutableJweHeader extends DefaultJweHeaderMutator<DefaultMutableJweHeader> implements JweHeader {
|
||||
|
||||
public DefaultMutableJweHeader(DefaultJweHeaderMutator<?> src) {
|
||||
super(src);
|
||||
}
|
||||
|
||||
private <T> T get(Field<T> field) {
|
||||
return this.DELEGATE.get(field);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// JWT Header methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return get(DefaultHeader.ALGORITHM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return get(DefaultHeader.CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return get(DefaultHeader.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCompressionAlgorithm() {
|
||||
return get(DefaultHeader.COMPRESSION_ALGORITHM);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// Protected Header methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public URI getJwkSetUrl() {
|
||||
return get(DefaultProtectedHeader.JKU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicJwk<?> getJwk() {
|
||||
return get(DefaultProtectedHeader.JWK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyId() {
|
||||
return get(DefaultProtectedHeader.KID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getCritical() {
|
||||
return get(DefaultProtectedHeader.CRIT);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// X.509 methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public URI getX509Url() {
|
||||
return get(DefaultProtectedHeader.X5U);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<X509Certificate> getX509CertificateChain() {
|
||||
return get(DefaultProtectedHeader.X5C);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getX509CertificateSha1Thumbprint() {
|
||||
return get(DefaultProtectedHeader.X5T);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getX509CertificateSha256Thumbprint() {
|
||||
return get(DefaultProtectedHeader.X5T_S256);
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// JWE Header methods
|
||||
// =============================================================
|
||||
|
||||
@Override
|
||||
public byte[] getAgreementPartyUInfo() {
|
||||
return get(DefaultJweHeader.APU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAgreementPartyVInfo() {
|
||||
return get(DefaultJweHeader.APV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPbes2Count() {
|
||||
return get(DefaultJweHeader.P2C);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncryptionAlgorithm() {
|
||||
return get(DefaultJweHeader.ENCRYPTION_ALGORITHM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicJwk<?> getEphemeralPublicKey() {
|
||||
return get(DefaultJweHeader.EPK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getInitializationVector() {
|
||||
return get(DefaultJweHeader.IV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAuthenticationTag() {
|
||||
return get(DefaultJweHeader.TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPbes2Salt() {
|
||||
return get(DefaultJweHeader.P2S);
|
||||
}
|
||||
}
|
|
@ -15,13 +15,17 @@
|
|||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.ProtectedHeader;
|
||||
import io.jsonwebtoken.impl.lang.Bytes;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.lang.Fields;
|
||||
import io.jsonwebtoken.impl.security.AbstractAsymmetricJwk;
|
||||
import io.jsonwebtoken.impl.security.AbstractJwk;
|
||||
import io.jsonwebtoken.impl.security.JwkConverter;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
import io.jsonwebtoken.security.PublicJwk;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -34,10 +38,9 @@ import java.util.Set;
|
|||
* Header implementation satisfying shared JWS and JWE header parameter requirements. Header parameters specific to
|
||||
* either JWE or JWS will be defined in respective subclasses.
|
||||
*
|
||||
* @param <T> specific header type to return from mutation/setter methods for method chaining
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public abstract class AbstractProtectedHeader<T extends ProtectedHeader<T>> extends AbstractHeader<T> implements ProtectedHeader<T> {
|
||||
public class DefaultProtectedHeader extends DefaultHeader implements ProtectedHeader {
|
||||
|
||||
static final Field<URI> JKU = Fields.uri("jku", "JWK Set URL");
|
||||
|
||||
|
@ -47,86 +50,73 @@ public abstract class AbstractProtectedHeader<T extends ProtectedHeader<T>> exte
|
|||
.setConverter(JwkConverter.PUBLIC_JWK).build();
|
||||
static final Field<Set<String>> CRIT = Fields.stringSet("crit", "Critical");
|
||||
|
||||
static final Set<Field<?>> FIELDS = Collections.concat(AbstractHeader.FIELDS, CRIT, JKU, JWK, AbstractJwk.KID,
|
||||
AbstractAsymmetricJwk.X5U, AbstractAsymmetricJwk.X5C, AbstractAsymmetricJwk.X5T, AbstractAsymmetricJwk.X5T_S256);
|
||||
static final Field<String> KID = AbstractJwk.KID;
|
||||
|
||||
protected AbstractProtectedHeader(Set<Field<?>> fieldSet) {
|
||||
super(fieldSet);
|
||||
static final Field<URI> X5U = AbstractAsymmetricJwk.X5U;
|
||||
|
||||
static final Field<List<X509Certificate>> X5C = AbstractAsymmetricJwk.X5C;
|
||||
|
||||
static final Field<byte[]> X5T = AbstractAsymmetricJwk.X5T;
|
||||
|
||||
static final Field<byte[]> X5T_S256 = AbstractAsymmetricJwk.X5T_S256;
|
||||
|
||||
static final Registry<String, Field<?>> FIELDS =
|
||||
Fields.registry(DefaultHeader.FIELDS, CRIT, JKU, JWK, KID, X5U, X5C, X5T, X5T_S256);
|
||||
|
||||
static boolean isCandidate(FieldMap fields) {
|
||||
String id = fields.get(DefaultHeader.ALGORITHM);
|
||||
return (Strings.hasText(id) && !Jwts.SIG.NONE.equals(Jwts.SIG.get().get(id))) ||
|
||||
fields.get(JKU) != null ||
|
||||
fields.get(JWK) != null ||
|
||||
!Collections.isEmpty(fields.get(CRIT)) ||
|
||||
Strings.hasText(fields.get(KID)) ||
|
||||
fields.get(X5U) != null ||
|
||||
!Collections.isEmpty(fields.get(X5C)) ||
|
||||
!Bytes.isEmpty(fields.get(X5T)) ||
|
||||
!Bytes.isEmpty(fields.get(X5T_S256));
|
||||
}
|
||||
|
||||
protected AbstractProtectedHeader(Set<Field<?>> fieldSet, Map<String, ?> values) {
|
||||
super(fieldSet, values);
|
||||
protected DefaultProtectedHeader(Registry<String, Field<?>> fields, Map<String, ?> values) {
|
||||
super(fields, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyId() {
|
||||
return idiomaticGet(AbstractJwk.KID);
|
||||
}
|
||||
|
||||
public T setKeyId(String kid) {
|
||||
put(AbstractJwk.KID, kid);
|
||||
return tthis();
|
||||
return get(KID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getJwkSetUrl() {
|
||||
return idiomaticGet(JKU);
|
||||
}
|
||||
|
||||
public T setJwkSetUrl(URI uri) {
|
||||
put(JKU, uri);
|
||||
return tthis();
|
||||
return get(JKU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicJwk<?> getJwk() {
|
||||
return idiomaticGet(JWK);
|
||||
}
|
||||
|
||||
public T setJwk(PublicJwk<?> jwk) {
|
||||
put(JWK, jwk);
|
||||
return tthis();
|
||||
return get(JWK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getX509Url() {
|
||||
return idiomaticGet(AbstractAsymmetricJwk.X5U);
|
||||
}
|
||||
|
||||
public T setX509Url(URI uri) {
|
||||
put(AbstractAsymmetricJwk.X5U, uri);
|
||||
return tthis();
|
||||
return get(AbstractAsymmetricJwk.X5U);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<X509Certificate> getX509CertificateChain() {
|
||||
return idiomaticGet(AbstractAsymmetricJwk.X5C);
|
||||
}
|
||||
|
||||
public T setX509CertificateChain(List<X509Certificate> chain) {
|
||||
put(AbstractAsymmetricJwk.X5C, chain);
|
||||
return tthis();
|
||||
return get(X5C);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getX509CertificateSha1Thumbprint() {
|
||||
return idiomaticGet(AbstractAsymmetricJwk.X5T);
|
||||
}
|
||||
|
||||
public T setX509CertificateSha1Thumbprint(byte[] thumbprint) {
|
||||
put(AbstractAsymmetricJwk.X5T, thumbprint);
|
||||
return tthis();
|
||||
return get(X5T);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getX509CertificateSha256Thumbprint() {
|
||||
return idiomaticGet(AbstractAsymmetricJwk.X5T_S256);
|
||||
}
|
||||
|
||||
public T setX509CertificateSha256Thumbprint(byte[] thumbprint) {
|
||||
put(AbstractAsymmetricJwk.X5T_S256, thumbprint);
|
||||
return tthis();
|
||||
return get(X5T_S256);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getCritical() {
|
||||
return idiomaticGet(CRIT);
|
||||
}
|
||||
|
||||
public T setCritical(Set<String> crit) {
|
||||
put(CRIT, crit);
|
||||
return tthis();
|
||||
return get(CRIT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.ProtectedHeader;
|
||||
import io.jsonwebtoken.ProtectedJwt;
|
||||
import io.jsonwebtoken.io.Encoders;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Objects;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class DefaultProtectedJwt<H extends ProtectedHeader, P> extends DefaultJwt<H, P> implements ProtectedJwt<H, P> {
|
||||
|
||||
protected final byte[] digest;
|
||||
|
||||
private final String digestName;
|
||||
|
||||
public DefaultProtectedJwt(H header, P payload, byte[] digest, String digestName) {
|
||||
super(header, payload);
|
||||
this.digest = Assert.notEmpty(digest, "Digest byte array cannot be null or empty.");
|
||||
this.digestName = Assert.hasText(digestName, "digestName cannot be null or empty.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getDigest() {
|
||||
return this.digest.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder toStringBuilder() {
|
||||
String b64Url = Encoders.BASE64URL.encode(this.digest);
|
||||
return super.toStringBuilder().append(',').append(this.digestName).append('=').append(b64Url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof DefaultProtectedJwt) {
|
||||
DefaultProtectedJwt<?, ?> pjwt = (DefaultProtectedJwt<?, ?>) obj;
|
||||
return super.equals(pjwt) && MessageDigest.isEqual(this.digest, pjwt.digest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.nullSafeHashCode(getHeader(), getPayload(), this.digest);
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ class DefaultTokenizedJwe extends DefaultTokenizedJwt implements TokenizedJwe {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Header<?> createHeader(Map<String, ?> m) {
|
||||
public Header createHeader(Map<String, ?> m) {
|
||||
return new DefaultJweHeader(m);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,10 +49,10 @@ class DefaultTokenizedJwt implements TokenizedJwt {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Header<?> createHeader(Map<String, ?> m) {
|
||||
public Header createHeader(Map<String, ?> m) {
|
||||
if (Strings.hasText(getDigest())) {
|
||||
return new DefaultJwsHeader(m);
|
||||
}
|
||||
return new DefaultUnprotectedHeader(m);
|
||||
return new DefaultHeader(m);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.UnprotectedHeader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class DefaultUnprotectedHeader extends AbstractHeader<UnprotectedHeader> implements UnprotectedHeader {
|
||||
|
||||
public DefaultUnprotectedHeader() {
|
||||
super(AbstractHeader.FIELDS);
|
||||
}
|
||||
|
||||
public DefaultUnprotectedHeader(Map<String, ?> values) {
|
||||
super(AbstractHeader.FIELDS, values);
|
||||
}
|
||||
}
|
|
@ -17,41 +17,70 @@ package io.jsonwebtoken.impl;
|
|||
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.lang.FieldReadable;
|
||||
import io.jsonwebtoken.impl.lang.Fields;
|
||||
import io.jsonwebtoken.impl.lang.Nameable;
|
||||
import io.jsonwebtoken.impl.lang.RedactedSupplier;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Objects;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
||||
public class FieldMap implements Map<String, Object>, FieldReadable, Nameable {
|
||||
|
||||
protected final Map<String, Field<?>> FIELDS;
|
||||
protected final Registry<String, ? extends Field<?>> FIELDS;
|
||||
protected final Map<String, Object> values; // canonical values formatted per RFC requirements
|
||||
protected final Map<String, Object> idiomaticValues; // the values map with any RFC values converted to Java type-safe values where possible
|
||||
|
||||
public JwtMap(Set<Field<?>> fieldSet) {
|
||||
Assert.notEmpty(fieldSet, "Fields cannot be null or empty.");
|
||||
Map<String, Field<?>> fields = new LinkedHashMap<>();
|
||||
for (Field<?> field : fieldSet) {
|
||||
fields.put(field.getId(), field);
|
||||
}
|
||||
this.FIELDS = java.util.Collections.unmodifiableMap(fields);
|
||||
this.values = new LinkedHashMap<>();
|
||||
this.idiomaticValues = new LinkedHashMap<>();
|
||||
private final boolean initialized;
|
||||
|
||||
private final boolean mutable;
|
||||
|
||||
public FieldMap(Set<Field<?>> fields) {
|
||||
this(Fields.registry(fields));
|
||||
}
|
||||
|
||||
public JwtMap(Set<Field<?>> fieldSet, Map<String, ?> values) {
|
||||
this(fieldSet);
|
||||
Assert.notNull(values, "Map argument cannot be null.");
|
||||
public FieldMap(Registry<String, ? extends Field<?>> fields) { // mutable constructor
|
||||
this(fields, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor producing an immutable instance.
|
||||
*
|
||||
* @param fields registry fields
|
||||
* @param values field values
|
||||
*/
|
||||
public FieldMap(Registry<String, ? extends Field<?>> fields, Map<String, ?> values) {
|
||||
this(fields, Assert.notNull(values, "Map argument cannot be null."), false);
|
||||
}
|
||||
|
||||
protected FieldMap(Registry<String, ? extends Field<?>> fields, Map<String, ?> values, boolean mutable) {
|
||||
Assert.notNull(fields, "Field registry cannot be null.");
|
||||
Assert.notEmpty(fields.values(), "Field registry cannot be empty.");
|
||||
this.FIELDS = fields;
|
||||
this.values = new LinkedHashMap<>();
|
||||
this.idiomaticValues = new LinkedHashMap<>();
|
||||
if (!Collections.isEmpty(values)) {
|
||||
putAll(values);
|
||||
}
|
||||
this.mutable = mutable;
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
private void assertMutable() {
|
||||
if (initialized && !mutable) {
|
||||
String msg = getName() + " instance is immutable and may not be modified.";
|
||||
throw new UnsupportedOperationException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -66,15 +95,6 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
(v.getClass().isArray() && Array.getLength(v) == 0);
|
||||
}
|
||||
|
||||
protected Object idiomaticGet(String key) {
|
||||
return this.idiomaticValues.get(key);
|
||||
}
|
||||
|
||||
protected <T> T idiomaticGet(Field<T> field) {
|
||||
Object value = this.idiomaticValues.get(field.getId());
|
||||
return field.cast(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Field<T> field) {
|
||||
Assert.notNull(field, "Field cannot be null.");
|
||||
|
@ -122,6 +142,7 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
|
||||
@Override
|
||||
public Object put(String name, Object value) {
|
||||
assertMutable();
|
||||
name = Assert.notNull(Strings.clean(name), "Member name cannot be null or empty.");
|
||||
if (value instanceof String) {
|
||||
value = Strings.clean((String) value);
|
||||
|
@ -141,7 +162,7 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
}
|
||||
}
|
||||
|
||||
protected Object nullSafePut(String name, Object value) {
|
||||
private Object nullSafePut(String name, Object value) {
|
||||
if (isReducibleToNull(value)) {
|
||||
return remove(name);
|
||||
} else {
|
||||
|
@ -150,7 +171,7 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
}
|
||||
}
|
||||
|
||||
protected <T> Object apply(Field<T> field, Object rawValue) {
|
||||
private <T> Object apply(Field<T> field, Object rawValue) {
|
||||
|
||||
final String id = field.getId();
|
||||
|
||||
|
@ -187,6 +208,7 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
assertMutable();
|
||||
this.idiomaticValues.remove(key);
|
||||
return this.values.remove(key);
|
||||
}
|
||||
|
@ -204,23 +226,24 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
|
||||
@Override
|
||||
public void clear() {
|
||||
assertMutable();
|
||||
this.values.clear();
|
||||
this.idiomaticValues.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return values.keySet();
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return values.values();
|
||||
return new ValueSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
return values.entrySet();
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -238,4 +261,86 @@ public class JwtMap implements Map<String, Object>, FieldReadable, Nameable {
|
|||
public boolean equals(Object obj) {
|
||||
return values.equals(obj);
|
||||
}
|
||||
|
||||
private abstract class FieldMapSet<T> extends AbstractSet<T> {
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return FieldMap.this.size();
|
||||
}
|
||||
}
|
||||
|
||||
private class KeySet extends FieldMapSet<String> {
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return new KeyIterator();
|
||||
}
|
||||
}
|
||||
|
||||
private class ValueSet extends FieldMapSet<Object> {
|
||||
@Override
|
||||
public Iterator<Object> iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
}
|
||||
|
||||
private class EntrySet extends FieldMapSet<Map.Entry<String, Object>> {
|
||||
@Override
|
||||
public Iterator<Entry<String, Object>> iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class FieldMapIterator<T> implements Iterator<T> {
|
||||
|
||||
final Iterator<Map.Entry<String, Object>> i;
|
||||
|
||||
transient Map.Entry<String, Object> current;
|
||||
|
||||
FieldMapIterator() {
|
||||
this.i = FieldMap.this.values.entrySet().iterator();
|
||||
this.current = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
protected Map.Entry<String, Object> nextEntry() {
|
||||
current = i.next();
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (current == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
String key = current.getKey();
|
||||
FieldMap.this.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private class ValueIterator extends FieldMapIterator<Object> {
|
||||
@Override
|
||||
public Object next() {
|
||||
return nextEntry().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyIterator extends FieldMapIterator<String> {
|
||||
@Override
|
||||
public String next() {
|
||||
return nextEntry().getKey();
|
||||
}
|
||||
}
|
||||
|
||||
private class EntryIterator extends FieldMapIterator<Map.Entry<String, Object>> {
|
||||
@Override
|
||||
public Entry<String, Object> next() {
|
||||
return nextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.HeaderMutator;
|
||||
import io.jsonwebtoken.lang.Builder;
|
||||
import io.jsonwebtoken.lang.MapMutator;
|
||||
|
||||
// TODO: move this concept to the API when Java 8 is supported. Do we even need it?
|
||||
public interface HeaderBuilder<H extends Header<H>, T extends HeaderBuilder<H, T>> extends Builder<H>, MapMutator<String, Object, T>, HeaderMutator<T> {
|
||||
}
|
|
@ -16,31 +16,43 @@
|
|||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Identifiable;
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.Locator;
|
||||
import io.jsonwebtoken.MalformedJwtException;
|
||||
import io.jsonwebtoken.UnsupportedJwtException;
|
||||
import io.jsonwebtoken.impl.lang.Field;
|
||||
import io.jsonwebtoken.impl.lang.Function;
|
||||
import io.jsonwebtoken.impl.lang.IdRegistry;
|
||||
import io.jsonwebtoken.lang.Assert;
|
||||
import io.jsonwebtoken.lang.Collections;
|
||||
import io.jsonwebtoken.lang.Registry;
|
||||
import io.jsonwebtoken.lang.Strings;
|
||||
|
||||
public class IdLocator<H extends Header<H>, R> implements Function<H, R> {
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
private final Field<String> headerField;
|
||||
public class IdLocator<H extends Header, R extends Identifiable> implements Locator<R>, Function<H, R> {
|
||||
|
||||
private final Field<String> field;
|
||||
private final String requiredMsg;
|
||||
private final boolean headerValueRequired;
|
||||
private final boolean valueRequired;
|
||||
|
||||
private final Function<String, R> registry;
|
||||
private final Registry<String, R> registry;
|
||||
|
||||
public IdLocator(Field<String> field, String requiredMsg, Function<String, R> registry) {
|
||||
this.headerField = Assert.notNull(field, "Header field cannot be null.");
|
||||
this.registry = Assert.notNull(registry, "Registry cannot be null.");
|
||||
this.headerValueRequired = Strings.hasText(requiredMsg);
|
||||
this.requiredMsg = requiredMsg;
|
||||
public IdLocator(Field<String> field, Registry<String, R> registry, Collection<R> extras, String requiredExceptionMessage) {
|
||||
this.field = Assert.notNull(field, "Header field cannot be null.");
|
||||
this.requiredMsg = Strings.clean(requiredExceptionMessage);
|
||||
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(extras);
|
||||
all.addAll(registry.values());
|
||||
this.registry = new IdRegistry<>(field.getName(), all);
|
||||
}
|
||||
|
||||
private static String type(Header<?> header) {
|
||||
private static String type(Header header) {
|
||||
if (header instanceof JweHeader) {
|
||||
return "JWE";
|
||||
} else if (header instanceof JwsHeader) {
|
||||
|
@ -51,24 +63,29 @@ public class IdLocator<H extends Header<H>, R> implements Function<H, R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public R apply(H header) {
|
||||
|
||||
public R locate(Header header) {
|
||||
Assert.notNull(header, "Header argument cannot be null.");
|
||||
|
||||
Object val = header.get(this.headerField.getId());
|
||||
String id = val != null ? String.valueOf(val) : null;
|
||||
Object val = header.get(this.field.getId());
|
||||
String id = val != null ? val.toString() : null;
|
||||
|
||||
if (this.headerValueRequired && !Strings.hasText(id)) {
|
||||
if (!Strings.hasText(id)) {
|
||||
if (this.valueRequired) {
|
||||
throw new MalformedJwtException(requiredMsg);
|
||||
}
|
||||
|
||||
R instance = registry.apply(id);
|
||||
|
||||
if (this.headerValueRequired && instance == null) {
|
||||
String msg = "Unrecognized " + type(header) + " " + this.headerField + " header value: " + id;
|
||||
throw new UnsupportedJwtException(msg);
|
||||
return null; // otherwise header value not required, so short circuit
|
||||
}
|
||||
|
||||
return instance;
|
||||
try {
|
||||
return registry.forKey(id);
|
||||
} catch (Exception e) {
|
||||
String msg = "Unrecognized " + type(header) + " " + this.field + " header value: " + id;
|
||||
throw new UnsupportedJwtException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R apply(H header) {
|
||||
return locate(header);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import io.jsonwebtoken.Claims;
|
|||
import io.jsonwebtoken.Clock;
|
||||
import io.jsonwebtoken.CompressionCodecResolver;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jwe;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
|
@ -27,7 +28,6 @@ import io.jsonwebtoken.JwtHandler;
|
|||
import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.MalformedJwtException;
|
||||
import io.jsonwebtoken.SigningKeyResolver;
|
||||
import io.jsonwebtoken.UnprotectedHeader;
|
||||
import io.jsonwebtoken.UnsupportedJwtException;
|
||||
import io.jsonwebtoken.io.Decoder;
|
||||
import io.jsonwebtoken.io.Deserializer;
|
||||
|
@ -40,6 +40,7 @@ import java.util.Map;
|
|||
/**
|
||||
* This JwtParser implementation exists as a stop gap until the mutable methods are removed from JwtParser.
|
||||
* TODO: remove this class BEFORE 1.0
|
||||
*
|
||||
* @since 0.11.0
|
||||
*/
|
||||
class ImmutableJwtParser implements JwtParser {
|
||||
|
@ -156,12 +157,12 @@ class ImmutableJwtParser implements JwtParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Jwt<UnprotectedHeader, byte[]> parseContentJwt(String jwt) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
|
||||
public Jwt<Header, byte[]> parseContentJwt(String jwt) throws UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
|
||||
return this.jwtParser.parseContentJwt(jwt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jwt<UnprotectedHeader, Claims> parseClaimsJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
|
||||
public Jwt<Header, Claims> parseClaimsJwt(String jwt) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException {
|
||||
return this.jwtParser.parseClaimsJwt(jwt);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.JweHeader;
|
||||
import io.jsonwebtoken.JweHeaderMutator;
|
||||
|
||||
// TODO: move this concept to the API when Java 8 is supported so we can have JweHeader.builder() --> returns JweHeaderBuilder
|
||||
|
||||
/**
|
||||
* A builder to create {@link JweHeader} instances.
|
||||
*
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface JweHeaderBuilder extends
|
||||
ProtectedHeaderBuilder<JweHeader, JweHeaderBuilder>, JweHeaderMutator<JweHeaderBuilder> {
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
|
||||
// TODO: move this concept to the API when Java 8 is supported so we can have JwsHeader.builder() --> returns JwsHeaderBuilder
|
||||
/**
|
||||
* A builder to create {@link JwsHeader} instances.
|
||||
*
|
||||
* @since JJWT_RELEASE_VERSION
|
||||
*/
|
||||
public interface JwsHeaderBuilder extends ProtectedHeaderBuilder<JwsHeader, JwsHeaderBuilder> {
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 jsonwebtoken.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.jsonwebtoken.impl;
|
||||
|
||||
import io.jsonwebtoken.ProtectedHeader;
|
||||
import io.jsonwebtoken.ProtectedHeaderMutator;
|
||||
import io.jsonwebtoken.security.X509Builder;
|
||||
|
||||
// TODO: move this concept to the API when Java 8 is supported. Do we even need it?
|
||||
public interface ProtectedHeaderBuilder<H extends ProtectedHeader<H>, T extends ProtectedHeaderBuilder<H,T>>
|
||||
extends HeaderBuilder<H,T>, ProtectedHeaderMutator<T>, X509Builder<T> {
|
||||
|
||||
}
|
|
@ -48,5 +48,5 @@ public interface TokenizedJwt {
|
|||
* @param m the header state
|
||||
* @return a new header instance.
|
||||
*/
|
||||
Header<?> createHeader(Map<String, ?> m);
|
||||
Header createHeader(Map<String, ?> m);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue