From 6c85744565bc43ae3ebab64a8662d147f3149ea9 Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Thu, 13 Mar 2025 12:23:47 -0400 Subject: [PATCH] Fix #1038 - Do not register duplicated AuthProviders SyntheticBeans Signed-off-by: Ricardo Zanini --- .../deployment/GeneratorProcessor.java | 118 +++++++++++++----- .../auth/compositeAuthenticationProvider.qute | 2 +- .../microprofile/auth/headersFactory.qute | 2 +- .../OpenApiSpecProviderTest.java | 10 +- .../authentication/OperationTest.java | 6 +- .../generator/AuthenticationRecorder.java | 6 +- ...thenticationPropagationHeadersFactory.java | 4 +- ... BaseCompositeAuthenticationProvider.java} | 4 +- 8 files changed, 106 insertions(+), 46 deletions(-) rename client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/{CompositeAuthenticationProvider.java => BaseCompositeAuthenticationProvider.java} (94%) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratorProcessor.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratorProcessor.java index d719673e3..1f6978c36 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratorProcessor.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratorProcessor.java @@ -33,7 +33,7 @@ import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider; import io.quarkiverse.openapi.generator.providers.ApiKeyIn; import io.quarkiverse.openapi.generator.providers.AuthProvider; -import io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider; +import io.quarkiverse.openapi.generator.providers.BaseCompositeAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.OperationAuthInfo; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; @@ -110,12 +110,17 @@ void produceCompositeProviders(AuthenticationRecorder recorder, List> providersBySpec = authProviders.stream() .collect(Collectors.groupingBy(AuthProviderBuildItem::getOpenApiSpecId)); providersBySpec.forEach((openApiSpecId, providers) -> { - beanProducer.produce(SyntheticBeanBuildItem.configure(CompositeAuthenticationProvider.class).scope(Dependent.class) - .addQualifier().annotation(OpenApiSpec.class).addValue("openApiSpecId", openApiSpecId).done() - .addInjectionPoint(ParameterizedType.create(Instance.class, ClassType.create(AuthProvider.class)), + beanProducer.produce(SyntheticBeanBuildItem.configure(BaseCompositeAuthenticationProvider.class) + .scope(Dependent.class) + .addQualifier() + .annotation(OpenApiSpec.class) + .addValue("openApiSpecId", openApiSpecId) + .done() + .addInjectionPoint( + ParameterizedType.create(Instance.class, ClassType.create(AuthProvider.class)), AnnotationInstance.builder(OpenApiSpec.class).add("openApiSpecId", openApiSpecId).build()) - .createWith(recorder.recordCompositeProvider(openApiSpecId)).done()); - + .createWith(recorder.recordCompositeProvider(openApiSpecId)) + .done()); }); } @@ -131,7 +136,13 @@ void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, } LOGGER.debug("{} class found in runtime, producing OAuth bean generation", ABSTRACT_TOKEN_PRODUCER); Collection authenticationMarkers = beanArchiveBuildItem.getIndex() - .getAnnotationsWithRepeatable(OAUTH_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()); + .getAnnotationsWithRepeatable(OAUTH_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()) + .stream() + .collect(Collectors.toMap( + AnnotationInstance::equivalenceHashCode, + marker -> marker, + (existing, duplicate) -> existing)) + .values(); Map> operationsBySpec = getOperationsBySpec(beanArchiveBuildItem); @@ -140,13 +151,21 @@ void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, String openApiSpecId = authenticationMarker.value("openApiSpecId").asString(); List operations = getOperations(operationsBySpec, openApiSpecId, name); authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, name)); - beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class).scope(Dependent.class).addQualifier() - .annotation(AuthName.class).addValue("name", name).done().addQualifier().annotation(OpenApiSpec.class) - .addValue("openApiSpecId", openApiSpecId).done() + beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class) + .scope(Dependent.class) + .addQualifier() + .annotation(AuthName.class) + .addValue("name", name) + .done() + .addQualifier() + .annotation(OpenApiSpec.class) + .addValue("openApiSpecId", openApiSpecId) + .done() .addInjectionPoint(ClassType.create(OAuth2AuthenticationProvider.OidcClientRequestFilterDelegate.class), AnnotationInstance.builder(OidcClient.class).add("name", sanitizeAuthName(name)).build()) .createWith(oidcRecorder.recordOauthAuthProvider(sanitizeAuthName(name), openApiSpecId, operations)) - .unremovable().done()); + .unremovable() + .done()); } } @@ -157,7 +176,13 @@ void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, AuthenticationRecorder recorder) { Collection authenticationMarkers = beanArchiveBuildItem.getIndex() - .getAnnotationsWithRepeatable(BASIC_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()); + .getAnnotationsWithRepeatable(BASIC_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()) + .stream() + .collect(Collectors.toMap( + AnnotationInstance::equivalenceHashCode, + marker -> marker, + (existing, duplicate) -> existing)) + .values(); Map> operationsBySpec = getOperationsBySpec(beanArchiveBuildItem); for (AnnotationInstance authenticationMarker : authenticationMarkers) { @@ -167,12 +192,18 @@ void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, List operations = getOperations(operationsBySpec, openApiSpecId, name); authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, name)); - - beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class).scope(Dependent.class).addQualifier() - .annotation(AuthName.class).addValue("name", name).done().addQualifier().annotation(OpenApiSpec.class) - .addValue("openApiSpecId", openApiSpecId).done() + beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class) + .scope(Dependent.class) + .addQualifier() + .annotation(AuthName.class) + .addValue("name", name).done() + .addQualifier() + .annotation(OpenApiSpec.class) + .addValue("openApiSpecId", openApiSpecId) + .done() .createWith(recorder.recordBasicAuthProvider(sanitizeAuthName(name), openApiSpecId, operations)) - .unremovable().done()); + .unremovable() + .done()); } } @@ -183,7 +214,13 @@ void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, AuthenticationRecorder recorder) { Collection authenticationMarkers = beanArchiveBuildItem.getIndex() - .getAnnotationsWithRepeatable(BEARER_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()); + .getAnnotationsWithRepeatable(BEARER_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()) + .stream() + .collect(Collectors.toMap( + AnnotationInstance::equivalenceHashCode, + marker -> marker, + (existing, duplicate) -> existing)) + .values(); Map> operationsBySpec = getOperationsBySpec(beanArchiveBuildItem); for (AnnotationInstance authenticationMarker : authenticationMarkers) { @@ -193,11 +230,19 @@ void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, List operations = getOperations(operationsBySpec, openApiSpecId, name); authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, name)); - beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class).scope(Dependent.class).addQualifier() - .annotation(AuthName.class).addValue("name", name).done().addQualifier().annotation(OpenApiSpec.class) - .addValue("openApiSpecId", openApiSpecId).done() + beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class) + .scope(Dependent.class) + .addQualifier() + .annotation(AuthName.class) + .addValue("name", name) + .done() + .addQualifier() + .annotation(OpenApiSpec.class) + .addValue("openApiSpecId", openApiSpecId) + .done() .createWith(recorder.recordBearerAuthProvider(sanitizeAuthName(name), scheme, openApiSpecId, operations)) - .unremovable().done()); + .unremovable() + .done()); } } @@ -209,7 +254,14 @@ void produceApiKeyAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, AuthenticationRecorder recorder) { Collection authenticationMarkers = beanArchiveBuildItem.getIndex() - .getAnnotationsWithRepeatable(API_KEY_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()); + .getAnnotationsWithRepeatable(API_KEY_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()) + .stream() + .collect(Collectors.toMap( + AnnotationInstance::equivalenceHashCode, + marker -> marker, + (existing, duplicate) -> existing)) + .values(); + Map> operationsBySpec = getOperationsBySpec(beanArchiveBuildItem); for (AnnotationInstance authenticationMarker : authenticationMarkers) { String name = authenticationMarker.value("name").asString(); @@ -220,12 +272,20 @@ void produceApiKeyAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, List operations = getOperations(operationsBySpec, openApiSpecId, name); authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, name)); - - beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class).scope(Dependent.class).addQualifier() - .annotation(AuthName.class).addValue("name", name).done().addQualifier().annotation(OpenApiSpec.class) - .addValue("openApiSpecId", openApiSpecId).done().createWith(recorder - .recordApiKeyAuthProvider(sanitizeAuthName(name), openApiSpecId, apiKeyIn, apiKeyName, operations)) - .unremovable().done()); + beanProducer.produce(SyntheticBeanBuildItem.configure(AuthProvider.class) + .scope(Dependent.class) + .addQualifier() + .annotation(AuthName.class) + .addValue("name", name) + .done() + .addQualifier() + .annotation(OpenApiSpec.class) + .addValue("openApiSpecId", openApiSpecId) + .done() + .createWith(recorder.recordApiKeyAuthProvider(sanitizeAuthName(name), openApiSpecId, apiKeyIn, apiKeyName, + operations)) + .unremovable() + .done()); } } diff --git a/client/deployment/src/main/resources/templates/libraries/microprofile/auth/compositeAuthenticationProvider.qute b/client/deployment/src/main/resources/templates/libraries/microprofile/auth/compositeAuthenticationProvider.qute index ca6085c27..297ce5f34 100644 --- a/client/deployment/src/main/resources/templates/libraries/microprofile/auth/compositeAuthenticationProvider.qute +++ b/client/deployment/src/main/resources/templates/libraries/microprofile/auth/compositeAuthenticationProvider.qute @@ -23,7 +23,7 @@ public class CompositeAuthenticationProvider implements jakarta.ws.rs.client.Cli @jakarta.inject.Inject @io.quarkiverse.openapi.generator.OpenApiSpec(openApiSpecId="{quarkus-generator.openApiSpecId}") - io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider compositeProvider; + io.quarkiverse.openapi.generator.providers.BaseCompositeAuthenticationProvider compositeProvider; @java.lang.Override public void filter(jakarta.ws.rs.client.ClientRequestContext context) throws java.io.IOException { diff --git a/client/deployment/src/main/resources/templates/libraries/microprofile/auth/headersFactory.qute b/client/deployment/src/main/resources/templates/libraries/microprofile/auth/headersFactory.qute index adb47b393..ddebaffec 100644 --- a/client/deployment/src/main/resources/templates/libraries/microprofile/auth/headersFactory.qute +++ b/client/deployment/src/main/resources/templates/libraries/microprofile/auth/headersFactory.qute @@ -3,7 +3,7 @@ package {apiPackage}.auth; public class AuthenticationPropagationHeadersFactory extends io.quarkiverse.openapi.generator.providers.AbstractAuthenticationPropagationHeadersFactory { @jakarta.inject.Inject - public AuthenticationPropagationHeadersFactory(@io.quarkiverse.openapi.generator.OpenApiSpec(openApiSpecId="{quarkus-generator.openApiSpecId}") io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider compositeProvider, io.quarkiverse.openapi.generator.OpenApiGeneratorConfig generatorConfig, io.quarkiverse.openapi.generator.providers.HeadersProvider headersProvider) { + public AuthenticationPropagationHeadersFactory(@io.quarkiverse.openapi.generator.OpenApiSpec(openApiSpecId="{quarkus-generator.openApiSpecId}") io.quarkiverse.openapi.generator.providers.BaseCompositeAuthenticationProvider compositeProvider, io.quarkiverse.openapi.generator.OpenApiGeneratorConfig generatorConfig, io.quarkiverse.openapi.generator.providers.HeadersProvider headersProvider) { super(compositeProvider, generatorConfig, headersProvider); } diff --git a/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OpenApiSpecProviderTest.java b/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OpenApiSpecProviderTest.java index 5a0f652c7..579b2a32c 100644 --- a/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OpenApiSpecProviderTest.java +++ b/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OpenApiSpecProviderTest.java @@ -20,8 +20,8 @@ import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider; import io.quarkiverse.openapi.generator.providers.ApiKeyAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.AuthProvider; +import io.quarkiverse.openapi.generator.providers.BaseCompositeAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.BasicAuthenticationProvider; -import io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider; import io.quarkus.test.QuarkusUnitTest; public class OpenApiSpecProviderTest { @@ -41,19 +41,19 @@ public class OpenApiSpecProviderTest { @Inject @OpenApiSpec(openApiSpecId = "spec_1") - CompositeAuthenticationProvider spec1CompositeProvider; + BaseCompositeAuthenticationProvider spec1CompositeProvider; @Inject @OpenApiSpec(openApiSpecId = "spec_2") - CompositeAuthenticationProvider spec2CompositeProvider; + BaseCompositeAuthenticationProvider spec2CompositeProvider; @Inject @OpenApiSpec(openApiSpecId = "spec_3") - CompositeAuthenticationProvider spec3CompositeProvider; + BaseCompositeAuthenticationProvider spec3CompositeProvider; @Inject @OpenApiSpec(openApiSpecId = "spec_multi") - CompositeAuthenticationProvider multiCompositeProvider; + BaseCompositeAuthenticationProvider multiCompositeProvider; @Test public void checkCompositeProvider() { diff --git a/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OperationTest.java b/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OperationTest.java index f9a330c1f..05abba0a3 100644 --- a/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OperationTest.java +++ b/client/deployment/src/test/java/io/quarkiverse/openapi/generator/deployment/authentication/OperationTest.java @@ -20,7 +20,7 @@ import io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker; import io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker; import io.quarkiverse.openapi.generator.markers.OperationMarker; -import io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider; +import io.quarkiverse.openapi.generator.providers.BaseCompositeAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.OperationAuthInfo; import io.quarkus.test.QuarkusUnitTest; @@ -40,10 +40,10 @@ public class OperationTest { @Inject @OpenApiSpec(openApiSpecId = "petstore_json") - CompositeAuthenticationProvider compositeProvider; + BaseCompositeAuthenticationProvider compositeProvider; @Inject @OpenApiSpec(openApiSpecId = "other_spec_json") - CompositeAuthenticationProvider otherProvider; + BaseCompositeAuthenticationProvider otherProvider; @Test public void test() { diff --git a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/AuthenticationRecorder.java b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/AuthenticationRecorder.java index a5f599297..8672be8e8 100644 --- a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/AuthenticationRecorder.java +++ b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/AuthenticationRecorder.java @@ -10,9 +10,9 @@ import io.quarkiverse.openapi.generator.providers.ApiKeyAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.ApiKeyIn; import io.quarkiverse.openapi.generator.providers.AuthProvider; +import io.quarkiverse.openapi.generator.providers.BaseCompositeAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.BasicAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.BearerAuthenticationProvider; -import io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider; import io.quarkiverse.openapi.generator.providers.OperationAuthInfo; import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.runtime.annotations.Recorder; @@ -20,12 +20,12 @@ @Recorder public class AuthenticationRecorder { - public Function, CompositeAuthenticationProvider> recordCompositeProvider( + public Function, BaseCompositeAuthenticationProvider> recordCompositeProvider( String openApiSpec) { return ctx -> { List providers = ctx.getInjectedReference(new TypeLiteral>() { }, new Literal(openApiSpec)).stream().toList(); - return new CompositeAuthenticationProvider(providers); + return new BaseCompositeAuthenticationProvider(providers); }; } diff --git a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/AbstractAuthenticationPropagationHeadersFactory.java b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/AbstractAuthenticationPropagationHeadersFactory.java index 586e14c72..2f9c1a04e 100644 --- a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/AbstractAuthenticationPropagationHeadersFactory.java +++ b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/AbstractAuthenticationPropagationHeadersFactory.java @@ -19,11 +19,11 @@ public abstract class AbstractAuthenticationPropagationHeadersFactory implements private static final String HEADER_NAME_PREFIX_FOR_TOKEN_PROPAGATION = "QCG_%s"; private static final String HEADER_NAME_FOR_TOKEN_PROPAGATION = "QCG_%s_%s_%s"; - protected CompositeAuthenticationProvider compositeProvider; + protected BaseCompositeAuthenticationProvider compositeProvider; protected OpenApiGeneratorConfig generatorConfig; protected HeadersProvider headersProvider; - protected AbstractAuthenticationPropagationHeadersFactory(CompositeAuthenticationProvider compositeProvider, + protected AbstractAuthenticationPropagationHeadersFactory(BaseCompositeAuthenticationProvider compositeProvider, OpenApiGeneratorConfig generatorConfig, HeadersProvider headersProvider) { this.compositeProvider = compositeProvider; diff --git a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/CompositeAuthenticationProvider.java b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/BaseCompositeAuthenticationProvider.java similarity index 94% rename from client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/CompositeAuthenticationProvider.java rename to client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/BaseCompositeAuthenticationProvider.java index 3df16cb19..a6d705f49 100644 --- a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/CompositeAuthenticationProvider.java +++ b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/providers/BaseCompositeAuthenticationProvider.java @@ -16,11 +16,11 @@ * Composition of supported {@link ClientRequestFilter} defined by a given OpenAPI interface. * This class is used as the base class of generated code. */ -public class CompositeAuthenticationProvider implements ClientRequestFilter { +public class BaseCompositeAuthenticationProvider implements ClientRequestFilter { private final List authProviders; - public CompositeAuthenticationProvider(List authProviders) { + public BaseCompositeAuthenticationProvider(List authProviders) { this.authProviders = List.copyOf(authProviders); }