mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 17:22:13 +00:00
Add Post-Processor for JWTProcessor Configuration
Extends all existing builders in NimbusJwtDecoder and NimbusReactiveJwtDecoder with a post-processor hook to apply changes on the JWTProcessor used for token verification. Test cases added show how this is used to configure the JWTProcessor to allow additional JWT typ headers. Closes gh-8730
This commit is contained in:
parent
3c2a97ed29
commit
d31fff11b3
@ -219,10 +219,12 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
private Set<SignatureAlgorithm> signatureAlgorithms = new HashSet<>();
|
||||
private RestOperations restOperations = new RestTemplate();
|
||||
private Cache cache;
|
||||
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private JwkSetUriJwtDecoderBuilder(String jwkSetUri) {
|
||||
Assert.hasText(jwkSetUri, "jwkSetUri cannot be empty");
|
||||
this.jwkSetUri = jwkSetUri;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,6 +284,20 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public JwkSetUriJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
JWSKeySelector<SecurityContext> jwsKeySelector(JWKSource<SecurityContext> jwkSource) {
|
||||
if (this.signatureAlgorithms.isEmpty()) {
|
||||
return new JWSVerificationKeySelector<>(JWSAlgorithm.RS256, jwkSource);
|
||||
@ -312,6 +328,8 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
// Spring Security validates the claim set independent from Nimbus
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { });
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
return jwtProcessor;
|
||||
}
|
||||
|
||||
@ -414,11 +432,13 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
public static final class PublicKeyJwtDecoderBuilder {
|
||||
private JWSAlgorithm jwsAlgorithm;
|
||||
private RSAPublicKey key;
|
||||
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private PublicKeyJwtDecoderBuilder(RSAPublicKey key) {
|
||||
Assert.notNull(key, "key cannot be null");
|
||||
this.jwsAlgorithm = JWSAlgorithm.RS256;
|
||||
this.key = key;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -437,6 +457,20 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link PublicKeyJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public PublicKeyJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
JWTProcessor<SecurityContext> processor() {
|
||||
if (!JWSAlgorithm.Family.RSA.contains(this.jwsAlgorithm)) {
|
||||
throw new IllegalStateException("The provided key is of type RSA; " +
|
||||
@ -452,6 +486,8 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
// Spring Security validates the claim set independent from Nimbus
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { });
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
return jwtProcessor;
|
||||
}
|
||||
|
||||
@ -471,10 +507,12 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
public static final class SecretKeyJwtDecoderBuilder {
|
||||
private final SecretKey secretKey;
|
||||
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256;
|
||||
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private SecretKeyJwtDecoderBuilder(SecretKey secretKey) {
|
||||
Assert.notNull(secretKey, "secretKey cannot be null");
|
||||
this.secretKey = secretKey;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -494,6 +532,20 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link SecretKeyJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public SecretKeyJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the configured {@link NimbusJwtDecoder}.
|
||||
*
|
||||
@ -512,6 +564,8 @@ public final class NimbusJwtDecoder implements JwtDecoder {
|
||||
// Spring Security validates the claim set independent from Nimbus
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { });
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
return jwtProcessor;
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
|
||||
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
|
||||
import com.nimbusds.jwt.proc.JWTProcessor;
|
||||
import reactor.core.publisher.Flux;
|
||||
@ -245,10 +246,12 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
private final String jwkSetUri;
|
||||
private Set<SignatureAlgorithm> signatureAlgorithms = new HashSet<>();
|
||||
private WebClient webClient = WebClient.create();
|
||||
private Consumer<ConfigurableJWTProcessor<JWKSecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private JwkSetUriReactiveJwtDecoderBuilder(String jwkSetUri) {
|
||||
Assert.hasText(jwkSetUri, "jwkSetUri cannot be empty");
|
||||
this.jwkSetUri = jwkSetUri;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,6 +297,20 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link JwkSetUriReactiveJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public JwkSetUriReactiveJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<JWKSecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the configured {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
@ -323,6 +340,8 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
jwtProcessor.setJWSKeySelector(jwsKeySelector);
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {});
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
ReactiveRemoteJWKSource source = new ReactiveRemoteJWKSource(this.jwkSetUri);
|
||||
source.setWebClient(this.webClient);
|
||||
|
||||
@ -360,11 +379,13 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
public static final class PublicKeyReactiveJwtDecoderBuilder {
|
||||
private final RSAPublicKey key;
|
||||
private JWSAlgorithm jwsAlgorithm;
|
||||
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private PublicKeyReactiveJwtDecoderBuilder(RSAPublicKey key) {
|
||||
Assert.notNull(key, "key cannot be null");
|
||||
this.key = key;
|
||||
this.jwsAlgorithm = JWSAlgorithm.RS256;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -382,6 +403,20 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link PublicKeyReactiveJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public PublicKeyReactiveJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the configured {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
@ -406,6 +441,8 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
// Spring Security validates the claim set independent from Nimbus
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { });
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
return jwt -> Mono.just(createClaimsSet(jwtProcessor, jwt, null));
|
||||
}
|
||||
}
|
||||
@ -418,10 +455,12 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
public static final class SecretKeyReactiveJwtDecoderBuilder {
|
||||
private final SecretKey secretKey;
|
||||
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256;
|
||||
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private SecretKeyReactiveJwtDecoderBuilder(SecretKey secretKey) {
|
||||
Assert.notNull(secretKey, "secretKey cannot be null");
|
||||
this.secretKey = secretKey;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -441,6 +480,20 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link SecretKeyReactiveJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public SecretKeyReactiveJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the configured {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
@ -459,6 +512,8 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
// Spring Security validates the claim set independent from Nimbus
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { });
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
return jwt -> Mono.just(createClaimsSet(jwtProcessor, jwt, null));
|
||||
}
|
||||
}
|
||||
@ -471,10 +526,12 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
public static final class JwkSourceReactiveJwtDecoderBuilder {
|
||||
private final Function<SignedJWT, Flux<JWK>> jwkSource;
|
||||
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.RS256;
|
||||
private Consumer<ConfigurableJWTProcessor<JWKSecurityContext>> jwtProcessorCustomizer;
|
||||
|
||||
private JwkSourceReactiveJwtDecoderBuilder(Function<SignedJWT, Flux<JWK>> jwkSource) {
|
||||
Assert.notNull(jwkSource, "jwkSource cannot be null");
|
||||
this.jwkSource = jwkSource;
|
||||
this.jwtProcessorCustomizer = (processor) -> {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -490,6 +547,20 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Consumer} to customize the {@link JWTProcessor ConfigurableJWTProcessor} before
|
||||
* passing it to the build {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
* @param jwtProcessorCustomizer the callback used to alter the processor
|
||||
* @return a {@link JwkSourceReactiveJwtDecoderBuilder} for further configurations
|
||||
* @since 5.4
|
||||
*/
|
||||
public JwkSourceReactiveJwtDecoderBuilder jwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<JWKSecurityContext>> jwtProcessorCustomizer) {
|
||||
Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null");
|
||||
this.jwtProcessorCustomizer = jwtProcessorCustomizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the configured {@link NimbusReactiveJwtDecoder}.
|
||||
*
|
||||
@ -507,6 +578,8 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder {
|
||||
jwtProcessor.setJWSKeySelector(jwsKeySelector);
|
||||
jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> {});
|
||||
|
||||
this.jwtProcessorCustomizer.accept(jwtProcessor);
|
||||
|
||||
return jwt -> {
|
||||
if (jwt instanceof SignedJWT) {
|
||||
return this.jwkSource.apply((SignedJWT) jwt)
|
||||
|
@ -35,6 +35,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import com.nimbusds.jose.JOSEObjectType;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.JWSSigner;
|
||||
@ -42,6 +43,7 @@ import com.nimbusds.jose.crypto.MACSigner;
|
||||
import com.nimbusds.jose.crypto.RSASSASigner;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.BadJOSEException;
|
||||
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
|
||||
import com.nimbusds.jose.proc.JWSKeySelector;
|
||||
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
@ -346,6 +348,30 @@ public class NimbusJwtDecoderTests {
|
||||
.isInstanceOf(BadJwtException.class);
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withPublicKeyWhenUsingCustomTypeHeaderThenSuccessfullyDecodes() throws Exception {
|
||||
RSAPublicKey publicKey = TestKeys.DEFAULT_PUBLIC_KEY;
|
||||
RSAPrivateKey privateKey = TestKeys.DEFAULT_PRIVATE_KEY;
|
||||
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).type(new JOSEObjectType("JWS")).build();
|
||||
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
|
||||
.expirationTime(Date.from(Instant.now().plusSeconds(60)))
|
||||
.build();
|
||||
SignedJWT signedJwt = signedJwt(privateKey, header, claimsSet);
|
||||
NimbusJwtDecoder decoder = withPublicKey(publicKey)
|
||||
.signatureAlgorithm(SignatureAlgorithm.RS256)
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
assertThat(decoder.decode(signedJwt.serialize()).containsClaim(JwtClaimNames.EXP)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withPublicKeyWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> withPublicKey(key()).jwtProcessorCustomizer(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSecretKeyWhenNullThenThrowsIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> withSecretKey(null))
|
||||
@ -407,6 +433,30 @@ public class NimbusJwtDecoderTests {
|
||||
.isEqualTo("test-subject");
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withSecretKeyWhenUsingCustomTypeHeaderThenSuccessfullyDecodes() throws Exception {
|
||||
SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY;
|
||||
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256).type(new JOSEObjectType("JWS")).build();
|
||||
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
|
||||
.expirationTime(Date.from(Instant.now().plusSeconds(60)))
|
||||
.build();
|
||||
SignedJWT signedJwt = signedJwt(secretKey, header, claimsSet);
|
||||
NimbusJwtDecoder decoder = withSecretKey(secretKey)
|
||||
.macAlgorithm(MacAlgorithm.HS256)
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
assertThat(decoder.decode(signedJwt.serialize()).containsClaim(JwtClaimNames.EXP)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSecretKeyWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY;
|
||||
assertThatThrownBy(() -> withSecretKey(secretKey).jwtProcessorCustomizer(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jwsKeySelectorWhenNoAlgorithmThenReturnsRS256Selector() {
|
||||
JWKSource<SecurityContext> jwkSource = mock(JWKSource.class);
|
||||
@ -524,6 +574,28 @@ public class NimbusJwtDecoderTests {
|
||||
.hasMessageContaining("An error occurred while attempting to decode the Jwt");
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withJwkSetUriWhenUsingCustomTypeHeaderThenRefuseOmittedType() throws Exception {
|
||||
RestOperations restOperations = mock(RestOperations.class);
|
||||
when(restOperations.exchange(any(RequestEntity.class), eq(String.class)))
|
||||
.thenReturn(new ResponseEntity<>(JWK_SET, HttpStatus.OK));
|
||||
NimbusJwtDecoder jwtDecoder = withJwkSetUri(JWK_SET_URI)
|
||||
.restOperations(restOperations)
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
assertThatCode(() -> jwtDecoder.decode(SIGNED_JWT))
|
||||
.isInstanceOf(BadJwtException.class)
|
||||
.hasMessageContaining("An error occurred while attempting to decode the Jwt: Required JOSE header \"typ\" (type) parameter is missing");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withJwkSetUriWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> withJwkSetUri(JWK_SET_URI).jwtProcessorCustomizer(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
private RSAPublicKey key() throws InvalidKeySpecException {
|
||||
byte[] decoded = Base64.getDecoder().decode(VERIFY_KEY.getBytes());
|
||||
EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
|
||||
|
@ -31,12 +31,14 @@ import java.util.Date;
|
||||
import java.util.Map;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import com.nimbusds.jose.JOSEObjectType;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.JWSSigner;
|
||||
import com.nimbusds.jose.crypto.MACSigner;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
|
||||
import com.nimbusds.jose.proc.JWKSecurityContext;
|
||||
import com.nimbusds.jose.proc.JWSKeySelector;
|
||||
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
|
||||
@ -44,6 +46,7 @@ import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.assertj.core.api.AssertionsForClassTypes;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
@ -269,6 +272,13 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
assertThatCode(() -> builder.jwsAlgorithm(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withJwkSetUriWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
assertThatCode(() -> withJwkSetUri(jwkSetUri).jwtProcessorCustomizer(null).build())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restOperationsWhenNullThenThrowsException() {
|
||||
NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder builder = withJwkSetUri(this.jwkSetUri);
|
||||
@ -286,6 +296,19 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
verify(webClient).get();
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withJwkSetUriWhenUsingCustomTypeHeaderThenRefuseOmittedType() {
|
||||
WebClient webClient = mockJwkSetResponse(this.jwkSet);
|
||||
NimbusReactiveJwtDecoder decoder = withJwkSetUri(this.jwkSetUri)
|
||||
.webClient(webClient)
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
assertThatCode(() -> decoder.decode(messageReadToken).block())
|
||||
.isInstanceOf(BadJwtException.class)
|
||||
.hasRootCauseMessage("Required JOSE header \"typ\" (type) parameter is missing");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withPublicKeyWhenNullThenThrowsException() {
|
||||
assertThatThrownBy(() -> withPublicKey(null))
|
||||
@ -300,6 +323,13 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
assertThatCode(() -> withPublicKey(key()).jwtProcessorCustomizer(null).build())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeWhenUsingPublicKeyThenSuccessfullyDecodes() throws Exception {
|
||||
NimbusReactiveJwtDecoder decoder = withPublicKey(key()).build();
|
||||
@ -325,12 +355,31 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
.isInstanceOf(BadJwtException.class);
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withPublicKeyWhenUsingCustomTypeHeaderThenRefuseOmittedType() throws Exception {
|
||||
NimbusReactiveJwtDecoder decoder = withPublicKey(key())
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
|
||||
AssertionsForClassTypes.assertThatCode(() -> decoder.decode(this.rsa256).block())
|
||||
.isInstanceOf(BadJwtException.class)
|
||||
.hasRootCauseMessage("Required JOSE header \"typ\" (type) parameter is missing");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withJwkSourceWhenNullThenThrowsException() {
|
||||
assertThatCode(() -> withJwkSource(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withJwkSourceWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
assertThatCode(() -> withJwkSource(jwt -> Flux.empty()).jwtProcessorCustomizer(null).build())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeWhenCustomJwkSourceResolutionThenDecodes() {
|
||||
NimbusReactiveJwtDecoder decoder =
|
||||
@ -342,6 +391,18 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withJwkSourceWhenUsingCustomTypeHeaderThenRefuseOmittedType() {
|
||||
NimbusReactiveJwtDecoder decoder = withJwkSource(jwt -> Flux.empty())
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
|
||||
assertThatCode(() -> decoder.decode(this.messageReadToken).block())
|
||||
.isInstanceOf(BadJwtException.class)
|
||||
.hasRootCauseMessage("Required JOSE header \"typ\" (type) parameter is missing");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSecretKeyWhenSecretKeyNullThenThrowsIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> withSecretKey(null))
|
||||
@ -349,6 +410,14 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
.hasMessage("secretKey cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSecretKeyWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() {
|
||||
SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY;
|
||||
assertThatThrownBy(() -> withSecretKey(secretKey).jwtProcessorCustomizer(null).build())
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("jwtProcessorCustomizer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSecretKeyWhenMacAlgorithmNullThenThrowsIllegalArgumentException() {
|
||||
SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY;
|
||||
@ -372,6 +441,18 @@ public class NimbusReactiveJwtDecoderTests {
|
||||
assertThat(jwt.getSubject()).isEqualTo("test-subject");
|
||||
}
|
||||
|
||||
// gh-8730
|
||||
@Test
|
||||
public void withSecretKeyWhenUsingCustomTypeHeaderThenRefuseOmittedType() {
|
||||
SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY;
|
||||
NimbusReactiveJwtDecoder decoder = withSecretKey(secretKey)
|
||||
.jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))))
|
||||
.build();
|
||||
assertThatCode(() -> decoder.decode(messageReadToken).block())
|
||||
.isInstanceOf(BadJwtException.class)
|
||||
.hasRootCauseMessage("Required JOSE header \"typ\" (type) parameter is missing");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeWhenSecretKeyAndAlgorithmMismatchThenThrowsJwtException() throws Exception {
|
||||
SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY;
|
||||
|
Loading…
x
Reference in New Issue
Block a user