|
@@ -33,6 +33,7 @@ import java.util.function.Function;
|
|
import javax.crypto.SecretKey;
|
|
import javax.crypto.SecretKey;
|
|
|
|
|
|
import com.nimbusds.jose.JOSEException;
|
|
import com.nimbusds.jose.JOSEException;
|
|
|
|
+import com.nimbusds.jose.JOSEObjectType;
|
|
import com.nimbusds.jose.JWSAlgorithm;
|
|
import com.nimbusds.jose.JWSAlgorithm;
|
|
import com.nimbusds.jose.KeySourceException;
|
|
import com.nimbusds.jose.KeySourceException;
|
|
import com.nimbusds.jose.RemoteKeySourceException;
|
|
import com.nimbusds.jose.RemoteKeySourceException;
|
|
@@ -41,6 +42,8 @@ import com.nimbusds.jose.jwk.source.JWKSetCacheRefreshEvaluator;
|
|
import com.nimbusds.jose.jwk.source.JWKSetSource;
|
|
import com.nimbusds.jose.jwk.source.JWKSetSource;
|
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
|
import com.nimbusds.jose.jwk.source.JWKSourceBuilder;
|
|
import com.nimbusds.jose.jwk.source.JWKSourceBuilder;
|
|
|
|
+import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
|
|
|
|
+import com.nimbusds.jose.proc.JOSEObjectTypeVerifier;
|
|
import com.nimbusds.jose.proc.JWSKeySelector;
|
|
import com.nimbusds.jose.proc.JWSKeySelector;
|
|
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
|
|
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
|
|
import com.nimbusds.jose.proc.SecurityContext;
|
|
import com.nimbusds.jose.proc.SecurityContext;
|
|
@@ -265,11 +268,20 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
*/
|
|
*/
|
|
public static final class JwkSetUriJwtDecoderBuilder {
|
|
public static final class JwkSetUriJwtDecoderBuilder {
|
|
|
|
|
|
|
|
+ private static final JOSEObjectTypeVerifier<SecurityContext> JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier<>(
|
|
|
|
+ JOSEObjectType.JWT, null);
|
|
|
|
+
|
|
|
|
+ private static final JOSEObjectTypeVerifier<SecurityContext> NO_TYPE_VERIFIER = (header, context) -> {
|
|
|
|
+ };
|
|
|
|
+
|
|
private Function<RestOperations, String> jwkSetUri;
|
|
private Function<RestOperations, String> jwkSetUri;
|
|
|
|
|
|
private Function<JWKSource<SecurityContext>, Set<JWSAlgorithm>> defaultAlgorithms = (source) -> Set
|
|
private Function<JWKSource<SecurityContext>, Set<JWSAlgorithm>> defaultAlgorithms = (source) -> Set
|
|
.of(JWSAlgorithm.RS256);
|
|
.of(JWSAlgorithm.RS256);
|
|
|
|
|
|
|
|
+ private JOSEObjectTypeVerifier<SecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(
|
|
|
|
+ JOSEObjectType.JWT, null);
|
|
|
|
+
|
|
private Set<SignatureAlgorithm> signatureAlgorithms = new HashSet<>();
|
|
private Set<SignatureAlgorithm> signatureAlgorithms = new HashSet<>();
|
|
|
|
|
|
private RestOperations restOperations = new RestTemplate();
|
|
private RestOperations restOperations = new RestTemplate();
|
|
@@ -295,6 +307,54 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Whether to use Nimbus's typ header verification. This is {@code true} by
|
|
|
|
+ * default, however it may change to {@code false} in a future major release.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
|
|
|
|
+ * check the {@code typ} header themselves in order to determine what kind of
|
|
|
|
+ * validation is needed
|
|
|
|
+ * </p>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * This is done for you when you use {@link JwtValidators} to construct a
|
|
|
|
+ * validator.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * That means that this: <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
|
|
|
|
+ * </code>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * Is equivalent to this: <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
|
|
|
|
+ * .validateType(false)
|
|
|
|
+ * .build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
|
|
|
|
+ * </code>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * The difference is that by setting this to {@code false}, it allows you to
|
|
|
|
+ * provide validation by type, like for {@code at+jwt}:
|
|
|
|
+ *
|
|
|
|
+ * <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
|
|
|
|
+ * .validateType(false)
|
|
|
|
+ * .build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
|
|
|
|
+ * </code>
|
|
|
|
+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
|
|
|
|
+ * not
|
|
|
|
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
|
|
|
|
+ * @since 6.5
|
|
|
|
+ */
|
|
|
|
+ public JwkSetUriJwtDecoderBuilder validateType(boolean shouldValidateTypHeader) {
|
|
|
|
+ this.typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER;
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Append the given signing
|
|
* Append the given signing
|
|
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
|
|
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
|
|
@@ -389,6 +449,7 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
JWTProcessor<SecurityContext> processor() {
|
|
JWTProcessor<SecurityContext> processor() {
|
|
JWKSource<SecurityContext> jwkSource = jwkSource();
|
|
JWKSource<SecurityContext> jwkSource = jwkSource();
|
|
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
|
|
ConfigurableJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
|
|
|
|
+ jwtProcessor.setJWSTypeVerifier(this.typeVerifier);
|
|
jwtProcessor.setJWSKeySelector(jwsKeySelector(jwkSource));
|
|
jwtProcessor.setJWSKeySelector(jwsKeySelector(jwkSource));
|
|
// Spring Security validates the claim set independent from Nimbus
|
|
// Spring Security validates the claim set independent from Nimbus
|
|
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
|
|
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
|
|
@@ -481,8 +542,17 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
*/
|
|
*/
|
|
public static final class PublicKeyJwtDecoderBuilder {
|
|
public static final class PublicKeyJwtDecoderBuilder {
|
|
|
|
|
|
|
|
+ private static final JOSEObjectTypeVerifier<SecurityContext> JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier<>(
|
|
|
|
+ JOSEObjectType.JWT, null);
|
|
|
|
+
|
|
|
|
+ private static final JOSEObjectTypeVerifier<SecurityContext> NO_TYPE_VERIFIER = (header, context) -> {
|
|
|
|
+ };
|
|
|
|
+
|
|
private JWSAlgorithm jwsAlgorithm;
|
|
private JWSAlgorithm jwsAlgorithm;
|
|
|
|
|
|
|
|
+ private JOSEObjectTypeVerifier<SecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(
|
|
|
|
+ JOSEObjectType.JWT, null);
|
|
|
|
+
|
|
private RSAPublicKey key;
|
|
private RSAPublicKey key;
|
|
|
|
|
|
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
|
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
|
@@ -495,6 +565,54 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Whether to use Nimbus's typ header verification. This is {@code true} by
|
|
|
|
+ * default, however it may change to {@code false} in a future major release.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
|
|
|
|
+ * check the {@code typ} header themselves in order to determine what kind of
|
|
|
|
+ * validation is needed
|
|
|
|
+ * </p>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * This is done for you when you use {@link JwtValidators} to construct a
|
|
|
|
+ * validator.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * That means that this: <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
|
|
|
|
+ * </code>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * Is equivalent to this: <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
|
|
|
|
+ * .validateType(false)
|
|
|
|
+ * .build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
|
|
|
|
+ * </code>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * The difference is that by setting this to {@code false}, it allows you to
|
|
|
|
+ * provide validation by type, like for {@code at+jwt}:
|
|
|
|
+ *
|
|
|
|
+ * <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
|
|
|
|
+ * .validateType(false)
|
|
|
|
+ * .build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
|
|
|
|
+ * </code>
|
|
|
|
+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
|
|
|
|
+ * not
|
|
|
|
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
|
|
|
|
+ * @since 6.5
|
|
|
|
+ */
|
|
|
|
+ public PublicKeyJwtDecoderBuilder validateType(boolean shouldValidateTypHeader) {
|
|
|
|
+ this.typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER;
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Use the given signing
|
|
* Use the given signing
|
|
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
|
|
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
|
|
@@ -533,6 +651,7 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
+ this.jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512.");
|
|
+ this.jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512.");
|
|
JWSKeySelector<SecurityContext> jwsKeySelector = new SingleKeyJWSKeySelector<>(this.jwsAlgorithm, this.key);
|
|
JWSKeySelector<SecurityContext> jwsKeySelector = new SingleKeyJWSKeySelector<>(this.jwsAlgorithm, this.key);
|
|
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
|
|
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
|
|
|
|
+ jwtProcessor.setJWSTypeVerifier(this.typeVerifier);
|
|
jwtProcessor.setJWSKeySelector(jwsKeySelector);
|
|
jwtProcessor.setJWSKeySelector(jwsKeySelector);
|
|
// Spring Security validates the claim set independent from Nimbus
|
|
// Spring Security validates the claim set independent from Nimbus
|
|
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
|
|
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
|
|
@@ -557,10 +676,19 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
*/
|
|
*/
|
|
public static final class SecretKeyJwtDecoderBuilder {
|
|
public static final class SecretKeyJwtDecoderBuilder {
|
|
|
|
|
|
|
|
+ private static final JOSEObjectTypeVerifier<SecurityContext> JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier<>(
|
|
|
|
+ JOSEObjectType.JWT, null);
|
|
|
|
+
|
|
|
|
+ private static final JOSEObjectTypeVerifier<SecurityContext> NO_TYPE_VERIFIER = (header, context) -> {
|
|
|
|
+ };
|
|
|
|
+
|
|
private final SecretKey secretKey;
|
|
private final SecretKey secretKey;
|
|
|
|
|
|
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256;
|
|
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256;
|
|
|
|
|
|
|
|
+ private JOSEObjectTypeVerifier<SecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(
|
|
|
|
+ JOSEObjectType.JWT, null);
|
|
|
|
+
|
|
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
|
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
|
|
|
|
|
private SecretKeyJwtDecoderBuilder(SecretKey secretKey) {
|
|
private SecretKeyJwtDecoderBuilder(SecretKey secretKey) {
|
|
@@ -570,6 +698,54 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Whether to use Nimbus's typ header verification. This is {@code true} by
|
|
|
|
+ * default, however it may change to {@code false} in a future major release.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
|
|
|
|
+ * check the {@code typ} header themselves in order to determine what kind of
|
|
|
|
+ * validation is needed
|
|
|
|
+ * </p>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * This is done for you when you use {@link JwtValidators} to construct a
|
|
|
|
+ * validator.
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * That means that this: <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
|
|
|
|
+ * </code>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * Is equivalent to this: <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
|
|
|
|
+ * .validateType(false)
|
|
|
|
+ * .build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
|
|
|
|
+ * </code>
|
|
|
|
+ *
|
|
|
|
+ * <p>
|
|
|
|
+ * The difference is that by setting this to {@code false}, it allows you to
|
|
|
|
+ * provide validation by type, like for {@code at+jwt}:
|
|
|
|
+ *
|
|
|
|
+ * <code>
|
|
|
|
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
|
|
|
|
+ * .validateType(false)
|
|
|
|
+ * .build();
|
|
|
|
+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
|
|
|
|
+ * </code>
|
|
|
|
+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
|
|
|
|
+ * not
|
|
|
|
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
|
|
|
|
+ * @since 6.5
|
|
|
|
+ */
|
|
|
|
+ public SecretKeyJwtDecoderBuilder validateType(boolean shouldValidateTypHeader) {
|
|
|
|
+ this.typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER;
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Use the given
|
|
* Use the given
|
|
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
|
|
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
|
|
@@ -615,6 +791,7 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
|
this.secretKey);
|
|
this.secretKey);
|
|
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
|
|
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
|
|
jwtProcessor.setJWSKeySelector(jwsKeySelector);
|
|
jwtProcessor.setJWSKeySelector(jwsKeySelector);
|
|
|
|
+ jwtProcessor.setJWSTypeVerifier(this.typeVerifier);
|
|
// Spring Security validates the claim set independent from Nimbus
|
|
// Spring Security validates the claim set independent from Nimbus
|
|
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
|
|
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {
|
|
});
|
|
});
|