From 99d6002a7666a39880b1ae0a41498ae217967627 Mon Sep 17 00:00:00 2001 From: Kevin Wise Date: Wed, 13 Nov 2024 03:25:44 -0700 Subject: [PATCH] fix: Make JwtTokenValidator not a bean (#1848) * fix: Make JwtTokenValidator not a bean - remove `@Inject` so JwtTokenValidator will no longer be a bean candidate - allow disabling NimbusReactiveJsonWebTokenValidator in case of custom implementation * add configuration properties for validator * javadoc: remove unused imports --------- Co-authored-by: Sergio del Amo --- .../nimbus/NimbusJsonWebTokenValidator.java | 3 + ...busJsonWebTokenValidatorConfiguration.java | 35 +++++++++ ...TokenValidatorConfigurationProperties.java | 74 +++++++++++++++++++ .../NimbusReactiveJsonWebTokenValidator.java | 3 + .../jwt/validator/JwtTokenValidator.java | 2 - .../token/validator/TokenValidatorSpec.groovy | 52 +++++++++++++ 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfiguration.java create mode 100644 security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfigurationProperties.java create mode 100644 security-jwt/src/test/groovy/io/micronaut/security/token/validator/TokenValidatorSpec.groovy diff --git a/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidator.java b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidator.java index 97593c1624..a77f6ad68d 100644 --- a/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidator.java +++ b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidator.java @@ -18,8 +18,10 @@ import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.PlainJWT; import com.nimbusds.jwt.SignedJWT; +import io.micronaut.context.annotation.Requires; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.util.StringUtils; import io.micronaut.security.token.jwt.signature.ReactiveSignatureConfiguration; import io.micronaut.security.token.jwt.signature.SignatureConfiguration; import io.micronaut.security.token.jwt.validator.GenericJwtClaimsValidator; @@ -38,6 +40,7 @@ * @param Request */ @Singleton +@Requires(property = NimbusJsonWebTokenValidatorConfigurationProperties.PREFIX + ".validator", value = StringUtils.TRUE, defaultValue = StringUtils.TRUE) class NimbusJsonWebTokenValidator extends AbstractJsonWebTokenValidator implements JsonWebTokenValidator { private final JsonWebTokenParser jsonWebTokenParser; private final JsonWebTokenSignatureValidator signatureValidator; diff --git a/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfiguration.java b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfiguration.java new file mode 100644 index 0000000000..e02027971a --- /dev/null +++ b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfiguration.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017-2024 original authors + * + * 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 + * + * https://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.micronaut.security.token.jwt.nimbus; + +/** + * Nimbus Json Web Token Validators Configuration. + * @author Sergio del Amo + * @since 4.11.1 + */ +public interface NimbusJsonWebTokenValidatorConfiguration { + /** + * + * @return Whether the bean {@link NimbusReactiveJsonWebTokenValidator} is enabled. + */ + boolean isReactiveValidator(); + + /** + * + * @return Whether the bean {@link NimbusJsonWebTokenValidator} is enabled. + */ + boolean isValidator(); +} diff --git a/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfigurationProperties.java b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfigurationProperties.java new file mode 100644 index 0000000000..1f8a76bee3 --- /dev/null +++ b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusJsonWebTokenValidatorConfigurationProperties.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017-2024 original authors + * + * 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 + * + * https://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.micronaut.security.token.jwt.nimbus; + +import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.security.token.jwt.config.JwtConfigurationProperties; + +/** + * {@link ConfigurationProperties} implementation of {@link NimbusJsonWebTokenValidatorConfiguration}. + * @author Sergio del Amo + * @since 4.11.1 + */ +@ConfigurationProperties(NimbusJsonWebTokenValidatorConfigurationProperties.PREFIX) +public class NimbusJsonWebTokenValidatorConfigurationProperties implements NimbusJsonWebTokenValidatorConfiguration { + /** + * The default reactive validator value. + */ + @SuppressWarnings("WeakerAccess") + public static final String PREFIX = JwtConfigurationProperties.PREFIX + ".nimbus"; + + /** + * The default reactive validator value. + */ + @SuppressWarnings("WeakerAccess") + public static final boolean DEFAULT_REACTIVE_VALIDATOR = true; + + /** + * The default enable value. + */ + @SuppressWarnings("WeakerAccess") + public static final boolean DEFAULT_VALIDATOR = true; + + private boolean reactiveValidator = DEFAULT_REACTIVE_VALIDATOR; + private boolean validator = DEFAULT_VALIDATOR; + + @Override + public boolean isReactiveValidator() { + return reactiveValidator; + } + + @Override + public boolean isValidator() { + return validator; + } + + /** + * Whether the bean {@link NimbusReactiveJsonWebTokenValidator} is enabled. Default value {@value #DEFAULT_REACTIVE_VALIDATOR}. + * @param reactiveValidator Whether the bean {@link NimbusReactiveJsonWebTokenValidator} is enabled. + */ + public void setReactiveValidator(boolean reactiveValidator) { + this.reactiveValidator = reactiveValidator; + } + + /** + * Whether the bean {@link NimbusJsonWebTokenValidator} is enabled. Default value {@value #DEFAULT_VALIDATOR}. + * @param validator Whether the bean {@link NimbusJsonWebTokenValidator} is enabled. + */ + public void setValidator(boolean validator) { + this.validator = validator; + } +} diff --git a/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusReactiveJsonWebTokenValidator.java b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusReactiveJsonWebTokenValidator.java index 46dc4d3973..e400094537 100644 --- a/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusReactiveJsonWebTokenValidator.java +++ b/security-jwt/src/main/java/io/micronaut/security/token/jwt/nimbus/NimbusReactiveJsonWebTokenValidator.java @@ -18,9 +18,11 @@ import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.PlainJWT; import com.nimbusds.jwt.SignedJWT; +import io.micronaut.context.annotation.Requires; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.core.async.annotation.SingleResult; +import io.micronaut.core.util.StringUtils; import io.micronaut.security.authentication.Authentication; import io.micronaut.security.token.jwt.signature.ReactiveSignatureConfiguration; import io.micronaut.security.token.jwt.signature.SignatureConfiguration; @@ -43,6 +45,7 @@ * @param The request type */ @Singleton +@Requires(property = NimbusJsonWebTokenValidatorConfigurationProperties.PREFIX + ".reactive-validator", value = StringUtils.TRUE, defaultValue = StringUtils.TRUE) class NimbusReactiveJsonWebTokenValidator extends AbstractJsonWebTokenValidator implements ReactiveJsonWebTokenValidator { private final JwtAuthenticationFactory jwtAuthenticationFactory; private final JsonWebTokenParser jsonWebTokenParser; diff --git a/security-jwt/src/main/java/io/micronaut/security/token/jwt/validator/JwtTokenValidator.java b/security-jwt/src/main/java/io/micronaut/security/token/jwt/validator/JwtTokenValidator.java index e32c8dc41f..a1dc002274 100644 --- a/security-jwt/src/main/java/io/micronaut/security/token/jwt/validator/JwtTokenValidator.java +++ b/security-jwt/src/main/java/io/micronaut/security/token/jwt/validator/JwtTokenValidator.java @@ -21,7 +21,6 @@ import io.micronaut.security.token.jwt.encryption.EncryptionConfiguration; import io.micronaut.security.token.jwt.signature.SignatureConfiguration; import io.micronaut.security.token.validator.TokenValidator; -import jakarta.inject.Inject; import jakarta.inject.Named; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -55,7 +54,6 @@ public class JwtTokenValidator implements TokenValidator { * @param jwtAuthenticationFactory Utility to generate an Authentication given a JWT. * @param executorService Executor Service */ - @Inject public JwtTokenValidator(Collection signatureConfigurations, Collection encryptionConfigurations, Collection genericJwtClaimsValidators, diff --git a/security-jwt/src/test/groovy/io/micronaut/security/token/validator/TokenValidatorSpec.groovy b/security-jwt/src/test/groovy/io/micronaut/security/token/validator/TokenValidatorSpec.groovy new file mode 100644 index 0000000000..7429cb859e --- /dev/null +++ b/security-jwt/src/test/groovy/io/micronaut/security/token/validator/TokenValidatorSpec.groovy @@ -0,0 +1,52 @@ +package io.micronaut.security.token.validator + +import io.micronaut.context.BeanContext +import io.micronaut.context.annotation.Property +import io.micronaut.core.util.StringUtils +import io.micronaut.security.token.jwt.nimbus.NimbusJsonWebTokenValidator +import io.micronaut.security.token.jwt.nimbus.NimbusReactiveJsonWebTokenValidator +import io.micronaut.security.token.jwt.validator.JsonWebTokenValidator +import io.micronaut.security.token.jwt.validator.JwtTokenValidator +import io.micronaut.security.token.jwt.validator.ReactiveJsonWebTokenValidator +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + + +@MicronautTest(startApplication = false, rebuildContext = true) +class TokenValidatorSpec extends Specification { + + @Inject + Collection tokenValidators + + @Inject + BeanContext beanContext + + void "JwtTokenValidator should not be considered a bean by default"() { + expect: + tokenValidators.stream().noneMatch {it instanceof JwtTokenValidator} + } + + void "NimbusReactiveJsonWebTokenValidator should be considered a bean by default"() { + expect: + tokenValidators.size() == 1 + tokenValidators.stream().anyMatch {it.getClass().getSimpleName() == "NimbusReactiveJsonWebTokenValidator"} + } + + @Property(name = "micronaut.security.token.jwt.nimbus.reactive-validator", value = StringUtils.FALSE) + void "NimbusReactiveJsonWebTokenValidator can be disabled via config"() { + expect: + tokenValidators.stream().noneMatch {it.getClass().getSimpleName() == "NimbusReactiveJsonWebTokenValidator"} + !beanContext.containsBean(ReactiveJsonWebTokenValidator) + !beanContext.containsBean(NimbusReactiveJsonWebTokenValidator) + beanContext.containsBean(JsonWebTokenValidator) + } + + @Property(name = "micronaut.security.token.jwt.nimbus.validator", value = StringUtils.FALSE) + void "NimbusJsonWebTokenValidator can be disabled via config"() { + expect: + !beanContext.containsBean(JsonWebTokenValidator) + !beanContext.containsBean(NimbusJsonWebTokenValidator) + beanContext.containsBean(ReactiveJsonWebTokenValidator) + } +}