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 1d48b9849..6538f9ce4 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 @@ -84,8 +84,7 @@ FeatureBuildItem feature() { } @BuildStep - void additionalBean(Capabilities capabilities, BuildProducer producer) { - + void registerOidcClientBean(Capabilities capabilities, BuildProducer producer) { if (!isClassPresentAtRuntime(ABSTRACT_TOKEN_PRODUCER)) { LOGGER.debug("{} class not found in runtime, skipping OidcClientRequestFilterDelegate bean generation", ABSTRACT_TOKEN_PRODUCER); @@ -101,7 +100,6 @@ void additionalBean(Capabilities capabilities, BuildProducer authenticationProviders, BuildProducer beanProducer, @@ -178,14 +176,16 @@ void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, .done() .addInjectionPoint(ClassType.create(OAuth2AuthenticationProvider.OidcClientRequestFilterDelegate.class), AnnotationInstance.builder(OidcClient.class).add("name", sanitizeAuthName(name)).build()) + .addInjectionPoint(ClassType.create(DotName.createSimple(CredentialsProvider.class))) .createWith(oidcRecorder.recordOauthAuthProvider(sanitizeAuthName(name), openApiSpecId, operations)) + .setRuntimeInit() .unremovable() .done()); } } @BuildStep - @Record(ExecutionTime.STATIC_INIT) + @Record(ExecutionTime.RUNTIME_INIT) void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, BuildProducer authenticationProviders, BuildProducer beanProducer, AuthenticationRecorder recorder) { @@ -218,13 +218,14 @@ void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, .done() .addInjectionPoint(ClassType.create(DotName.createSimple(CredentialsProvider.class))) .createWith(recorder.recordBasicAuthProvider(sanitizeAuthName(name), openApiSpecId, operations)) + .setRuntimeInit() .unremovable() .done()); } } @BuildStep - @Record(ExecutionTime.STATIC_INIT) + @Record(ExecutionTime.RUNTIME_INIT) void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, BuildProducer authenticationProviders, BuildProducer beanProducer, AuthenticationRecorder recorder) { @@ -258,6 +259,7 @@ void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, .done() .addInjectionPoint(ClassType.create(DotName.createSimple(CredentialsProvider.class))) .createWith(recorder.recordBearerAuthProvider(sanitizeAuthName(name), scheme, openApiSpecId, operations)) + .setRuntimeInit() .unremovable() .done()); @@ -265,7 +267,7 @@ void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, } @BuildStep - @Record(ExecutionTime.STATIC_INIT) + @Record(ExecutionTime.RUNTIME_INIT) void produceApiKeyAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, BuildProducer authenticationProviders, BuildProducer beanProducer, AuthenticationRecorder recorder) { @@ -302,6 +304,7 @@ void produceApiKeyAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, .addInjectionPoint(ClassType.create(DotName.createSimple(CredentialsProvider.class))) .createWith(recorder.recordApiKeyAuthProvider(sanitizeAuthName(name), openApiSpecId, apiKeyIn, apiKeyName, operations)) + .setRuntimeInit() .unremovable() .done()); } diff --git a/client/integration-tests/override-credential-provider/pom.xml b/client/integration-tests/override-credential-provider/pom.xml new file mode 100644 index 000000000..4902d46b0 --- /dev/null +++ b/client/integration-tests/override-credential-provider/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + quarkus-openapi-generator-integration-tests + io.quarkiverse.openapi.generator + 3.0.0-SNAPSHOT + + + quarkus-openapi-generatir-it-override-credential-provider + Quarkus - OpenAPI Generator - Integration Tests - Client - Override Credentials Provider + Integration Test to verify https://github.com/quarkiverse/quarkus-openapi-generator/issues/1156 + + + + io.quarkiverse.openapi.generator + quarkus-openapi-generator + + + org.assertj + assertj-core + test + + + io.quarkus + quarkus-junit5 + test + + + org.wiremock + wiremock + test + + + + + + + io.quarkus + quarkus-maven-plugin + true + + + + build + generate-code + generate-code-tests + + + + + + + \ No newline at end of file diff --git a/client/integration-tests/override-credential-provider/src/main/java/io/quarkiverse/openapi/generator/it/creds/CustomCredentialsProvider.java b/client/integration-tests/override-credential-provider/src/main/java/io/quarkiverse/openapi/generator/it/creds/CustomCredentialsProvider.java new file mode 100644 index 000000000..0ac9e2282 --- /dev/null +++ b/client/integration-tests/override-credential-provider/src/main/java/io/quarkiverse/openapi/generator/it/creds/CustomCredentialsProvider.java @@ -0,0 +1,26 @@ +package io.quarkiverse.openapi.generator.it.creds; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Alternative; +import jakarta.ws.rs.client.ClientRequestContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.quarkiverse.openapi.generator.providers.ConfigCredentialsProvider; + +@Dependent +@Alternative +@Priority(200) +public class CustomCredentialsProvider extends ConfigCredentialsProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(CustomCredentialsProvider.class); + + public static String TOKEN = "FIXED_TEST_TOKEN"; + + @Override + public String getBearerToken(ClientRequestContext requestContext, String openApiSpecId, String authName) { + LOGGER.info("========> getBearerToken from CustomCredentialsProvider"); + return TOKEN; + } +} \ No newline at end of file diff --git a/client/integration-tests/override-credential-provider/src/main/openapi/simple-server.yaml b/client/integration-tests/override-credential-provider/src/main/openapi/simple-server.yaml new file mode 100644 index 000000000..72e0c5ecc --- /dev/null +++ b/client/integration-tests/override-credential-provider/src/main/openapi/simple-server.yaml @@ -0,0 +1,27 @@ +openapi: 3.0.3 +info: + title: Simple server API + description: |- + Simple server API + version: 1.0.0 +tags: + - name: Simple server API + description: Simple server API +servers: + - url: / +paths: + /simple: + get: + summary: Send requests to simple server with simple JWT security scheme + description: Send requests to simple server to check the auth header + operationId: getWithSimpleBearerTokenSecurityScheme + responses: + "200": + description: Successful operation + security: + - SimpleBearerToken: [] +components: + securitySchemes: + SimpleBearerToken: + type: http + scheme: bearer \ No newline at end of file diff --git a/client/integration-tests/override-credential-provider/src/main/resources/application.properties b/client/integration-tests/override-credential-provider/src/main/resources/application.properties new file mode 100644 index 000000000..ec6ba13cf --- /dev/null +++ b/client/integration-tests/override-credential-provider/src/main/resources/application.properties @@ -0,0 +1,3 @@ +quarkus.openapi-generator.simple_server_yaml.auth.SimpleBearerToken.header-name=X-Authorization-Simple +# We have a custom CredentialsProvider that will ignore this token set in the config and will return a hard-coded one. +quarkus.openapi-generator.simple_server_yaml.auth.SimpleBearerToken.bearer-token=WILL_BE_OVERRIDED \ No newline at end of file diff --git a/client/integration-tests/override-credential-provider/src/test/java/io/quarkiverse/openapi/generator/it/creds/CustomCredentialsProviderTest.java b/client/integration-tests/override-credential-provider/src/test/java/io/quarkiverse/openapi/generator/it/creds/CustomCredentialsProviderTest.java new file mode 100644 index 000000000..368964e29 --- /dev/null +++ b/client/integration-tests/override-credential-provider/src/test/java/io/quarkiverse/openapi/generator/it/creds/CustomCredentialsProviderTest.java @@ -0,0 +1,41 @@ +package io.quarkiverse.openapi.generator.it.creds; + +import jakarta.inject.Inject; + +import org.assertj.core.api.Assertions; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.junit.jupiter.api.Test; +import org.openapi.quarkus.simple_server_yaml.api.DefaultApi; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import io.quarkus.test.common.WithTestResource; +import io.quarkus.test.junit.QuarkusTest; + +@WithTestResource(SimpleServerMockResource.class) +@QuarkusTest +public class CustomCredentialsProviderTest { + + /** + * @see SimpleServerMockResource#inject(QuarkusTestResourceLifecycleManager.TestInjector) + */ + WireMockServer simpleServer; + + @RestClient + @Inject + DefaultApi defaultApi; + + /** + * This test validates whether the custom CredentialsProvider is overriden. + */ + @Test + public void testGetHardCodedToken() { + Assertions.assertThat(defaultApi.getWithSimpleBearerTokenSecurityScheme().getStatus()).isEqualTo(200); + + simpleServer.verify(WireMock.getRequestedFor(WireMock.urlEqualTo("/simple")).withHeader("Authorization", + WireMock.equalTo("Bearer " + CustomCredentialsProvider.TOKEN))); + } + +} \ No newline at end of file diff --git a/client/integration-tests/override-credential-provider/src/test/java/io/quarkiverse/openapi/generator/it/creds/SimpleServerMockResource.java b/client/integration-tests/override-credential-provider/src/test/java/io/quarkiverse/openapi/generator/it/creds/SimpleServerMockResource.java new file mode 100644 index 000000000..1d2d93e23 --- /dev/null +++ b/client/integration-tests/override-credential-provider/src/test/java/io/quarkiverse/openapi/generator/it/creds/SimpleServerMockResource.java @@ -0,0 +1,42 @@ +package io.quarkiverse.openapi.generator.it.creds; + +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; + +import java.util.Collections; +import java.util.Map; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; + +public class SimpleServerMockResource implements QuarkusTestResourceLifecycleManager { + + private WireMockServer wireMockServer; + + @Override + public Map start() { + wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort()); + wireMockServer.start(); + + wireMockServer.stubFor(get(urlMatching("/simple")) + .willReturn(ok())); + + return Collections.singletonMap("quarkus.rest-client.simple_server_yaml.url", + wireMockServer.baseUrl()); + } + + @Override + public void inject(TestInjector testInjector) { + testInjector.injectIntoFields(wireMockServer, f -> f.getName().equals("simpleServer")); + } + + @Override + public void stop() { + if (null != wireMockServer) { + wireMockServer.stop(); + } + } +} \ No newline at end of file diff --git a/client/integration-tests/pom.xml b/client/integration-tests/pom.xml index b2a36db4a..fa71bf7f8 100644 --- a/client/integration-tests/pom.xml +++ b/client/integration-tests/pom.xml @@ -47,6 +47,7 @@ without-oidc serializable-model equals-hashcode + override-credential-provider diff --git a/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/OidcAuthenticationRecorder.java b/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/OidcAuthenticationRecorder.java index 2ed758540..3710ff219 100644 --- a/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/OidcAuthenticationRecorder.java +++ b/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/OidcAuthenticationRecorder.java @@ -6,6 +6,7 @@ import io.quarkiverse.openapi.generator.OidcClient; import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider; import io.quarkiverse.openapi.generator.providers.AuthProvider; +import io.quarkiverse.openapi.generator.providers.CredentialsProvider; import io.quarkiverse.openapi.generator.providers.OperationAuthInfo; import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.runtime.annotations.Recorder; @@ -20,6 +21,7 @@ public Function, AuthProvider> recordOa return context -> new OAuth2AuthenticationProvider(name, openApiSpecId, context.getInjectedReference(OAuth2AuthenticationProvider.OidcClientRequestFilterDelegate.class, new OidcClient.Literal(name)), - operations); + operations, + context.getInjectedReference(CredentialsProvider.class)); } } diff --git a/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/providers/OAuth2AuthenticationProvider.java b/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/providers/OAuth2AuthenticationProvider.java index f4f7009ed..c2dda5c80 100644 --- a/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/providers/OAuth2AuthenticationProvider.java +++ b/client/oidc/src/main/java/io/quarkiverse/openapi/generator/oidc/providers/OAuth2AuthenticationProvider.java @@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory; import io.quarkiverse.openapi.generator.providers.AbstractAuthProvider; -import io.quarkiverse.openapi.generator.providers.ConfigCredentialsProvider; +import io.quarkiverse.openapi.generator.providers.CredentialsProvider; import io.quarkiverse.openapi.generator.providers.OperationAuthInfo; import io.quarkus.oidc.common.runtime.OidcConstants; @@ -23,8 +23,9 @@ public class OAuth2AuthenticationProvider extends AbstractAuthProvider { private final OidcClientRequestFilterDelegate delegate; public OAuth2AuthenticationProvider(String name, - String openApiSpecId, OidcClientRequestFilterDelegate delegate, List operations) { - super(name, openApiSpecId, operations, new ConfigCredentialsProvider()); + String openApiSpecId, OidcClientRequestFilterDelegate delegate, List operations, + CredentialsProvider credentialsProvider) { + super(name, openApiSpecId, operations, credentialsProvider); this.delegate = delegate; validateConfig(); }