From 3992fb85bb5cbc33b6a41cff74edd2cb25da3356 Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 10:33:16 -0700 Subject: [PATCH 1/7] Add OpenIdConnect method support in security feature detection --- .../deployment/wrapper/QuarkusJavaClientCodegen.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java index b7daaa74..97170ff9 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java @@ -75,9 +75,10 @@ private void replaceWithQuarkusTemplateFiles() { if (enableSecurityGeneration == null || enableSecurityGeneration) { if (ProcessUtils.hasHttpBasicMethods(this.openAPI) || - ProcessUtils.hasApiKeyMethods(this.openAPI) || - ProcessUtils.hasHttpBearerMethods(this.openAPI) || - ProcessUtils.hasOAuthMethods(this.openAPI)) { + ProcessUtils.hasApiKeyMethods(this.openAPI) || + ProcessUtils.hasHttpBearerMethods(this.openAPI) || + ProcessUtils.hasOAuthMethods(this.openAPI) || + ProcessUtils.hasOpenIdConnectMethods(this.openAPI)) { supportingFiles.add( new SupportingFile(AUTH_PACKAGE + "/compositeAuthenticationProvider.qute", authFileFolder(), From dec81cb646bdb515d92acf6f25b8ea37f84accb9 Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 10:52:48 -0700 Subject: [PATCH 2/7] Add support for token-external-service6 integration with OpenID Connect --- .../main/openapi/token-external-service6.yaml | 20 +++++++++++++++++++ .../src/main/resources/application.properties | 10 ++++++++++ 2 files changed, 30 insertions(+) create mode 100644 client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml diff --git a/client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml b/client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml new file mode 100644 index 00000000..464861e3 --- /dev/null +++ b/client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml @@ -0,0 +1,20 @@ +--- +openapi: 3.0.3 +info: + title: token-external-service6 API + version: 3.0.0-SNAPSHOT +paths: + /token-external-service6/executeQuery6: + post: + operationId: executeQuery6 + responses: + "200": + description: OK + security: + - service6-oidc: [] +components: + securitySchemes: + service6-oidc: + type: openIdConnect + description: Authentication for service6 + openIdConnectUrl: https://example.com/realms/master/.well-known/openid-configuration \ No newline at end of file diff --git a/client/integration-tests/auth-provider/src/main/resources/application.properties b/client/integration-tests/auth-provider/src/main/resources/application.properties index eeed16b8..53658fe8 100644 --- a/client/integration-tests/auth-provider/src/main/resources/application.properties +++ b/client/integration-tests/auth-provider/src/main/resources/application.properties @@ -6,11 +6,13 @@ quarkus.openapi-generator.codegen.spec.token_external_service1_yaml.base-package quarkus.openapi-generator.codegen.spec.token_external_service2_yaml.base-package=org.acme.externalservice2 quarkus.openapi-generator.codegen.spec.token_external_service3_yaml.base-package=org.acme.externalservice3 quarkus.openapi-generator.codegen.spec.token_external_service5_yaml.base-package=org.acme.externalservice5 +quarkus.openapi-generator.codegen.spec.token_external_service6_yaml.base-package=org.acme.externalservice6 quarkus.rest-client.token_external_service1_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_external_service2_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_external_service3_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_external_service5_yaml.url=${propagation-external-service-mock.url} +quarkus.rest-client.token_external_service6_yaml.url=${propagation-external-service-mock.url} # default propagation for token_external_service1 invocation quarkus.openapi-generator.token_external_service1_yaml.auth.service1_http_bearer.token-propagation=true @@ -39,4 +41,12 @@ quarkus.oidc-client.service5_oauth2.grant.type=client quarkus.oidc-client.service5_oauth2.credentials.client-secret.method=basic quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret + +# Oidc client used by the token_external_service6 +quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} +quarkus.oidc-client.service6_oidc.discovery-enabled=true +quarkus.oidc-client.service6_oidc.client-id=kogito-app +quarkus.oidc-client.service6_oidc.credentials.client-secret.value=secret + + quarkus.keycloak.devservices.enabled=false \ No newline at end of file From 97d49d341da94ccdc23498ce55d6ff5e9492341b Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 11:50:49 -0700 Subject: [PATCH 3/7] Add support for token-propagation-external-service6 with OpenID Connect integration --- .../wrapper/QuarkusJavaClientCodegen.java | 8 ++++---- .../it/auth/TokenServerResource.java | 10 ++++++++++ .../src/main/resources/application.properties | 2 ++ .../it/auth/TokenExternalServicesMock.java | 5 +++++ ...TokenWithCustomCredentialProviderTest.java | 2 +- .../it/security/TokenPropagationResource.java | 9 +++++++++ .../token-propagation-external-service6.yaml | 20 +++++++++++++++++++ .../src/main/resources/application.properties | 8 ++++++++ .../TokenPropagationExternalServicesMock.java | 5 +++++ 9 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java index 97170ff9..24808c32 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java @@ -75,10 +75,10 @@ private void replaceWithQuarkusTemplateFiles() { if (enableSecurityGeneration == null || enableSecurityGeneration) { if (ProcessUtils.hasHttpBasicMethods(this.openAPI) || - ProcessUtils.hasApiKeyMethods(this.openAPI) || - ProcessUtils.hasHttpBearerMethods(this.openAPI) || - ProcessUtils.hasOAuthMethods(this.openAPI) || - ProcessUtils.hasOpenIdConnectMethods(this.openAPI)) { + ProcessUtils.hasApiKeyMethods(this.openAPI) || + ProcessUtils.hasHttpBearerMethods(this.openAPI) || + ProcessUtils.hasOAuthMethods(this.openAPI) || + ProcessUtils.hasOpenIdConnectMethods(this.openAPI)) { supportingFiles.add( new SupportingFile(AUTH_PACKAGE + "/compositeAuthenticationProvider.qute", authFileFolder(), diff --git a/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java b/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java index 9c3ae7e5..99d2a4a8 100644 --- a/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java +++ b/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java @@ -20,6 +20,9 @@ public class TokenServerResource { @RestClient org.acme.externalservice5.api.DefaultApi defaultApi5; + @RestClient + org.acme.externalservice6.api.DefaultApi defaultApi6; + @POST @Path("service1") public String service1() { @@ -47,4 +50,11 @@ public String service5() { defaultApi5.executeQuery5(); return "hello"; } + + @POST + @Path("service6") + public String service6() { + defaultApi6.executeQuery6(); + return "hello"; + } } diff --git a/client/integration-tests/auth-provider/src/main/resources/application.properties b/client/integration-tests/auth-provider/src/main/resources/application.properties index 53658fe8..ae9db1b2 100644 --- a/client/integration-tests/auth-provider/src/main/resources/application.properties +++ b/client/integration-tests/auth-provider/src/main/resources/application.properties @@ -46,6 +46,8 @@ quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} quarkus.oidc-client.service6_oidc.discovery-enabled=true quarkus.oidc-client.service6_oidc.client-id=kogito-app +quarkus.oidc-client.service6_oidc.grant.type=client +quarkus.oidc-client.service6_oidc.credentials.client-secret.method=basic quarkus.oidc-client.service6_oidc.credentials.client-secret.value=secret diff --git a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java index 7a454521..48f62372 100644 --- a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java +++ b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java @@ -60,6 +60,11 @@ public Map start() { // configured. The token will be overridden by the custom credential provider stubForExternalService("/token-external-service5/executeQuery5", KEYCLOAK_ACCESS_TOKEN + "_TEST"); + // stub the token-external-service6 invocation with the expected token, no propagation is produced + // in this case but the service must receive the token provided by Keycloak since it has oidc security + // configured. The token will be overridden by the custom credential provider + stubForExternalService("/token-external-service6/executeQuery6", KEYCLOAK_ACCESS_TOKEN + "_TEST"); + return Map.of(TOKEN_EXTERNAL_SERVICE_MOCK_URL, wireMockServer.baseUrl()); } diff --git a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java index 9fd52547..bbd9ebb9 100644 --- a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java +++ b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java @@ -22,7 +22,7 @@ class TokenWithCustomCredentialProviderTest { @ParameterizedTest - @ValueSource(strings = { "service1", "service2", "service3", "service5" }) + @ValueSource(strings = { "service1", "service2", "service3", "service5", "service6" }) void testService(String service) { Map headers = Map.of(HttpHeaders.AUTHORIZATION, AUTHORIZATION_TOKEN); diff --git a/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java b/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java index 4253357f..0a9a1e3a 100644 --- a/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java +++ b/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java @@ -24,6 +24,9 @@ public class TokenPropagationResource { @RestClient org.acme.externalservice5.api.DefaultApi defaultApi5; + @RestClient + org.acme.externalservice6.api.DefaultApi defaultApi6; + @POST @Path("service1") public Response service1() { @@ -53,4 +56,10 @@ public Response service4() { public Response service5() { return defaultApi5.executeQuery5(); } + + @POST + @Path("service6") + public Response service6() { + return defaultApi6.executeQuery6(); + } } diff --git a/client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml b/client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml new file mode 100644 index 00000000..cf2a83c6 --- /dev/null +++ b/client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml @@ -0,0 +1,20 @@ +--- +openapi: 3.0.3 +info: + title: external-service6 API + version: 3.0.0-SNAPSHOT +paths: + /token-propagation-external-service6/executeQuery6: + post: + operationId: executeQuery6 + responses: + "200": + description: OK + security: + - service6-oidc: [] +components: + securitySchemes: + service6-oidc: + type: openIdConnect + description: Authentication for service6 + openIdConnectUrl: https://example.com/realms/master/.well-known/openid-configuration diff --git a/client/integration-tests/security/src/main/resources/application.properties b/client/integration-tests/security/src/main/resources/application.properties index e4bb70b7..6a9ce61b 100644 --- a/client/integration-tests/security/src/main/resources/application.properties +++ b/client/integration-tests/security/src/main/resources/application.properties @@ -78,6 +78,14 @@ quarkus.oidc-client.service5_oauth2.grant.type=client quarkus.oidc-client.service5_oauth2.credentials.client-secret.method=basic quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret +# Oidc client used by the token_propagation_external_service6 +quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} +quarkus.oidc-client.service6_oidc.discovery-enabled=true +quarkus.oidc-client.service6_oidc.client-id=kogito-app +quarkus.oidc-client.service6_oidc.grant.type=client +quarkus.oidc-client.service6_oidc.credentials.client-secret.method=basic +quarkus.oidc-client.service6_oidc.credentials.client-secret.value=secret + quarkus.keycloak.devservices.enabled=false # Slack OpenAPI diff --git a/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java b/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java index 53ecbf2a..62e6863b 100644 --- a/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java +++ b/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java @@ -66,6 +66,11 @@ public Map start() { // configured. stubForExternalService("/token-propagation-external-service5/executeQuery5", KEYCLOAK_ACCESS_TOKEN); + // stub the token-propagation-external-service6 invocation with the expected token, no propagation is produced + // in this case but the service must receive the token provided by Keycloak since it has oidc security + // configured. + stubForExternalService("/token-propagation-external-service6/executeQuery6", KEYCLOAK_ACCESS_TOKEN); + return Map.of(TOKEN_PROPAGATION_EXTERNAL_SERVICE_MOCK_URL, wireMockServer.baseUrl()); } From eaa8a2e91add7e1a7bbeff7145e5031c577c9426 Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 16:36:03 -0700 Subject: [PATCH 4/7] Add OpenIdConnectAuthenticationMarker --- .../deployment/GeneratorProcessor.java | 70 +++++++++++++++++-- .../auth/compositeAuthenticationProvider.qute | 3 + .../src/main/resources/application.properties | 3 +- .../src/main/resources/application.properties | 6 +- .../OpenIdConnectAuthenticationMarker.java | 25 +++++++ 5 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java 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 fa9e3faa..f3cf6576 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 @@ -22,11 +22,7 @@ import io.quarkiverse.openapi.generator.OidcClient; import io.quarkiverse.openapi.generator.OpenApiGeneratorConfig; import io.quarkiverse.openapi.generator.OpenApiSpec; -import io.quarkiverse.openapi.generator.markers.ApiKeyAuthenticationMarker; -import io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker; -import io.quarkiverse.openapi.generator.markers.BearerAuthenticationMarker; -import io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker; -import io.quarkiverse.openapi.generator.markers.OperationMarker; +import io.quarkiverse.openapi.generator.markers.*; import io.quarkiverse.openapi.generator.oidc.ClassicOidcClientRequestFilterDelegate; import io.quarkiverse.openapi.generator.oidc.OidcAuthenticationRecorder; import io.quarkiverse.openapi.generator.oidc.ReactiveOidcClientRequestFilterDelegate; @@ -51,6 +47,8 @@ public class GeneratorProcessor { private static final String FEATURE = "openapi-generator"; private static final DotName OAUTH_AUTHENTICATION_MARKER = DotName.createSimple(OauthAuthenticationMarker.class); + private static final DotName OPEN_ID_CONNECT_AUTHENTICATION_MARKER = DotName + .createSimple(OpenIdConnectAuthenticationMarker.class); private static final DotName BASIC_AUTHENTICATION_MARKER = DotName.createSimple(BasicAuthenticationMarker.class); private static final DotName BEARER_AUTHENTICATION_MARKER = DotName.createSimple(BearerAuthenticationMarker.class); private static final DotName API_KEY_AUTHENTICATION_MARKER = DotName.createSimple(ApiKeyAuthenticationMarker.class); @@ -185,6 +183,68 @@ void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, } } + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void produceOpenIdConnectAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, + BuildProducer authenticationProviders, + BuildProducer beanProducer, + OidcAuthenticationRecorder oidcRecorder) { + + Collection authenticationMarkers = beanArchiveBuildItem.getIndex() + .getAnnotationsWithRepeatable(OPEN_ID_CONNECT_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()) + .stream() + .collect(Collectors.toMap( + AnnotationInstance::equivalenceHashCode, + marker -> marker, + (existing, duplicate) -> existing)) + .values(); + + if (!isClassPresentAtRuntime(ABSTRACT_TOKEN_PRODUCER)) { + if (!authenticationMarkers.isEmpty()) { + throw new IllegalStateException( + "OAuth2 flows detected in spec(s) " + + authenticationMarkers.stream() + .map(m -> m.value("openApiSpecId").asString()) + .distinct() + .collect(Collectors.joining(", ")) + + + " but quarkus-openapi-generator-oidc and quarkus-rest-client-oidc-filter or quarkus-oidc-client-reactive-filter are not on the classpath. " + + + "Please add those dependencies to your project. See https://docs.quarkiverse.io/quarkus-openapi-generator/dev/client.html#_oauth2_authentication"); + } + LOGGER.debug("{} class not found in runtime, skipping OAuth bean generation", ABSTRACT_TOKEN_PRODUCER); + return; + } + LOGGER.debug("{} class found in runtime, producing OAuth bean generation", ABSTRACT_TOKEN_PRODUCER); + + Map> operationsBySpec = getOperationsBySpec(beanArchiveBuildItem); + + for (AnnotationInstance authenticationMarker : authenticationMarkers) { + String name = authenticationMarker.value("name").asString(); + 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() + .addInjectionPoint(ClassType.create(DotName.createSimple(CredentialsProvider.class))) + .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.RUNTIME_INIT) void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, 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 297ce5f3..8712f2d9 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 @@ -4,6 +4,9 @@ package {apiPackage}.auth; {#for auth in openapi:getUniqueOAuthOperations(oauthMethods.orEmpty)} @io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") {/for} +{#for auth in openapi:getUniqueOAuthOperations(openIdConnectMethods.orEmpty)} +@io.quarkiverse.openapi.generator.markers.OpenIdConnectAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") +{/for} {#for auth in httpBasicMethods.orEmpty} @io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") {/for} diff --git a/client/integration-tests/auth-provider/src/main/resources/application.properties b/client/integration-tests/auth-provider/src/main/resources/application.properties index ae9db1b2..42d59467 100644 --- a/client/integration-tests/auth-provider/src/main/resources/application.properties +++ b/client/integration-tests/auth-provider/src/main/resources/application.properties @@ -44,7 +44,8 @@ quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret # Oidc client used by the token_external_service6 quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} -quarkus.oidc-client.service6_oidc.discovery-enabled=true +quarkus.oidc-client.service6_oidc.token-path=${keycloak.mock.service.token-path} +quarkus.oidc-client.service6_oidc.discovery-enabled=false quarkus.oidc-client.service6_oidc.client-id=kogito-app quarkus.oidc-client.service6_oidc.grant.type=client quarkus.oidc-client.service6_oidc.credentials.client-secret.method=basic diff --git a/client/integration-tests/security/src/main/resources/application.properties b/client/integration-tests/security/src/main/resources/application.properties index 6a9ce61b..1e32e3b1 100644 --- a/client/integration-tests/security/src/main/resources/application.properties +++ b/client/integration-tests/security/src/main/resources/application.properties @@ -32,12 +32,15 @@ quarkus.openapi-generator.codegen.spec.token_propagation_external_service2_yaml. quarkus.openapi-generator.codegen.spec.token_propagation_external_service3_yaml.base-package=org.acme.externalservice3 quarkus.openapi-generator.codegen.spec.token_propagation_external_service4_yaml.base-package=org.acme.externalservice4 quarkus.openapi-generator.codegen.spec.token_propagation_external_service5_yaml.base-package=org.acme.externalservice5 +quarkus.openapi-generator.codegen.spec.token_propagation_external_service6_yaml.base-package=org.acme.externalservice6 quarkus.rest-client.token_propagation_external_service1_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service2_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service3_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service4_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service5_yaml.url=${propagation-external-service-mock.url} +quarkus.rest-client.token_propagation_external_service6_yaml.url=${propagation-external-service-mock.url} + # default propagation for token_propagation_external_service1 invocation quarkus.openapi-generator.token_propagation_external_service1_yaml.auth.service1_http_bearer.token-propagation=true @@ -80,7 +83,8 @@ quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret # Oidc client used by the token_propagation_external_service6 quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} -quarkus.oidc-client.service6_oidc.discovery-enabled=true +quarkus.oidc-client.service6_oidc.token-path=${keycloak.mock.service.token-path} +quarkus.oidc-client.service6_oidc.discovery-enabled=false quarkus.oidc-client.service6_oidc.client-id=kogito-app quarkus.oidc-client.service6_oidc.grant.type=client quarkus.oidc-client.service6_oidc.credentials.client-secret.method=basic diff --git a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java new file mode 100644 index 00000000..21666cc1 --- /dev/null +++ b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java @@ -0,0 +1,25 @@ +package io.quarkiverse.openapi.generator.markers; + +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(OpenIdConnectAuthenticationMarker.AuthenticationMarkers.class) +public @interface OpenIdConnectAuthenticationMarker { + + String name(); + + String openApiSpecId(); + + @Target(TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface AuthenticationMarkers { + OpenIdConnectAuthenticationMarker[] value(); + } + +} From bdeb802594403dbb8b21a45868a0a2514ead94fc Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 16:55:34 -0700 Subject: [PATCH 5/7] Remove OpenIdConnectAuthenticationMarker and related logic in favor of existing oauth marker --- .../deployment/GeneratorProcessor.java | 64 ------------------- .../auth/compositeAuthenticationProvider.qute | 2 +- .../OpenIdConnectAuthenticationMarker.java | 25 -------- 3 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java 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 f3cf6576..2b62ed2b 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 @@ -47,8 +47,6 @@ public class GeneratorProcessor { private static final String FEATURE = "openapi-generator"; private static final DotName OAUTH_AUTHENTICATION_MARKER = DotName.createSimple(OauthAuthenticationMarker.class); - private static final DotName OPEN_ID_CONNECT_AUTHENTICATION_MARKER = DotName - .createSimple(OpenIdConnectAuthenticationMarker.class); private static final DotName BASIC_AUTHENTICATION_MARKER = DotName.createSimple(BasicAuthenticationMarker.class); private static final DotName BEARER_AUTHENTICATION_MARKER = DotName.createSimple(BearerAuthenticationMarker.class); private static final DotName API_KEY_AUTHENTICATION_MARKER = DotName.createSimple(ApiKeyAuthenticationMarker.class); @@ -183,68 +181,6 @@ void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, } } - @BuildStep - @Record(ExecutionTime.RUNTIME_INIT) - void produceOpenIdConnectAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, - BuildProducer authenticationProviders, - BuildProducer beanProducer, - OidcAuthenticationRecorder oidcRecorder) { - - Collection authenticationMarkers = beanArchiveBuildItem.getIndex() - .getAnnotationsWithRepeatable(OPEN_ID_CONNECT_AUTHENTICATION_MARKER, beanArchiveBuildItem.getIndex()) - .stream() - .collect(Collectors.toMap( - AnnotationInstance::equivalenceHashCode, - marker -> marker, - (existing, duplicate) -> existing)) - .values(); - - if (!isClassPresentAtRuntime(ABSTRACT_TOKEN_PRODUCER)) { - if (!authenticationMarkers.isEmpty()) { - throw new IllegalStateException( - "OAuth2 flows detected in spec(s) " + - authenticationMarkers.stream() - .map(m -> m.value("openApiSpecId").asString()) - .distinct() - .collect(Collectors.joining(", ")) - + - " but quarkus-openapi-generator-oidc and quarkus-rest-client-oidc-filter or quarkus-oidc-client-reactive-filter are not on the classpath. " - + - "Please add those dependencies to your project. See https://docs.quarkiverse.io/quarkus-openapi-generator/dev/client.html#_oauth2_authentication"); - } - LOGGER.debug("{} class not found in runtime, skipping OAuth bean generation", ABSTRACT_TOKEN_PRODUCER); - return; - } - LOGGER.debug("{} class found in runtime, producing OAuth bean generation", ABSTRACT_TOKEN_PRODUCER); - - Map> operationsBySpec = getOperationsBySpec(beanArchiveBuildItem); - - for (AnnotationInstance authenticationMarker : authenticationMarkers) { - String name = authenticationMarker.value("name").asString(); - 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() - .addInjectionPoint(ClassType.create(DotName.createSimple(CredentialsProvider.class))) - .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.RUNTIME_INIT) void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem, 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 8712f2d9..29b73b8c 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 @@ -5,7 +5,7 @@ package {apiPackage}.auth; @io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") {/for} {#for auth in openapi:getUniqueOAuthOperations(openIdConnectMethods.orEmpty)} -@io.quarkiverse.openapi.generator.markers.OpenIdConnectAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") +@io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") {/for} {#for auth in httpBasicMethods.orEmpty} @io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") diff --git a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java b/client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java deleted file mode 100644 index 21666cc1..00000000 --- a/client/runtime/src/main/java/io/quarkiverse/openapi/generator/markers/OpenIdConnectAuthenticationMarker.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.quarkiverse.openapi.generator.markers; - -import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(OpenIdConnectAuthenticationMarker.AuthenticationMarkers.class) -public @interface OpenIdConnectAuthenticationMarker { - - String name(); - - String openApiSpecId(); - - @Target(TYPE) - @Retention(RetentionPolicy.RUNTIME) - @interface AuthenticationMarkers { - OpenIdConnectAuthenticationMarker[] value(); - } - -} From e6b59bc2a6d3d40e8ffe267dacd9a31bb1b9390d Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 16:57:59 -0700 Subject: [PATCH 6/7] Expand individual imports for authentication markers in GeneratorProcessor to improve clarity --- .../openapi/generator/deployment/GeneratorProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 2b62ed2b..fa9e3faa 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 @@ -22,7 +22,11 @@ import io.quarkiverse.openapi.generator.OidcClient; import io.quarkiverse.openapi.generator.OpenApiGeneratorConfig; import io.quarkiverse.openapi.generator.OpenApiSpec; -import io.quarkiverse.openapi.generator.markers.*; +import io.quarkiverse.openapi.generator.markers.ApiKeyAuthenticationMarker; +import io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker; +import io.quarkiverse.openapi.generator.markers.BearerAuthenticationMarker; +import io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker; +import io.quarkiverse.openapi.generator.markers.OperationMarker; import io.quarkiverse.openapi.generator.oidc.ClassicOidcClientRequestFilterDelegate; import io.quarkiverse.openapi.generator.oidc.OidcAuthenticationRecorder; import io.quarkiverse.openapi.generator.oidc.ReactiveOidcClientRequestFilterDelegate; From b6be4aa557eb641464a7557cd110827f7944e0e1 Mon Sep 17 00:00:00 2001 From: Alexander Haslam Date: Thu, 21 Aug 2025 10:33:16 -0700 Subject: [PATCH 7/7] Add Support for SecurityScheme type of openIdConnect and add integration tests to verify this feature --- .../wrapper/QuarkusJavaClientCodegen.java | 3 ++- .../auth/compositeAuthenticationProvider.qute | 3 +++ .../it/auth/TokenServerResource.java | 10 ++++++++++ .../main/openapi/token-external-service6.yaml | 20 +++++++++++++++++++ .../src/main/resources/application.properties | 13 ++++++++++++ .../it/auth/TokenExternalServicesMock.java | 5 +++++ ...TokenWithCustomCredentialProviderTest.java | 2 +- .../it/security/TokenPropagationResource.java | 9 +++++++++ .../token-propagation-external-service6.yaml | 20 +++++++++++++++++++ .../src/main/resources/application.properties | 12 +++++++++++ .../TokenPropagationExternalServicesMock.java | 5 +++++ 11 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml create mode 100644 client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java index b7daaa74..24808c32 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/QuarkusJavaClientCodegen.java @@ -77,7 +77,8 @@ private void replaceWithQuarkusTemplateFiles() { if (ProcessUtils.hasHttpBasicMethods(this.openAPI) || ProcessUtils.hasApiKeyMethods(this.openAPI) || ProcessUtils.hasHttpBearerMethods(this.openAPI) || - ProcessUtils.hasOAuthMethods(this.openAPI)) { + ProcessUtils.hasOAuthMethods(this.openAPI) || + ProcessUtils.hasOpenIdConnectMethods(this.openAPI)) { supportingFiles.add( new SupportingFile(AUTH_PACKAGE + "/compositeAuthenticationProvider.qute", authFileFolder(), 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 297ce5f3..29b73b8c 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 @@ -4,6 +4,9 @@ package {apiPackage}.auth; {#for auth in openapi:getUniqueOAuthOperations(oauthMethods.orEmpty)} @io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") {/for} +{#for auth in openapi:getUniqueOAuthOperations(openIdConnectMethods.orEmpty)} +@io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") +{/for} {#for auth in httpBasicMethods.orEmpty} @io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}") {/for} diff --git a/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java b/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java index 9c3ae7e5..99d2a4a8 100644 --- a/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java +++ b/client/integration-tests/auth-provider/src/main/java/io/quarkiverse/openapi/generator/it/auth/TokenServerResource.java @@ -20,6 +20,9 @@ public class TokenServerResource { @RestClient org.acme.externalservice5.api.DefaultApi defaultApi5; + @RestClient + org.acme.externalservice6.api.DefaultApi defaultApi6; + @POST @Path("service1") public String service1() { @@ -47,4 +50,11 @@ public String service5() { defaultApi5.executeQuery5(); return "hello"; } + + @POST + @Path("service6") + public String service6() { + defaultApi6.executeQuery6(); + return "hello"; + } } diff --git a/client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml b/client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml new file mode 100644 index 00000000..464861e3 --- /dev/null +++ b/client/integration-tests/auth-provider/src/main/openapi/token-external-service6.yaml @@ -0,0 +1,20 @@ +--- +openapi: 3.0.3 +info: + title: token-external-service6 API + version: 3.0.0-SNAPSHOT +paths: + /token-external-service6/executeQuery6: + post: + operationId: executeQuery6 + responses: + "200": + description: OK + security: + - service6-oidc: [] +components: + securitySchemes: + service6-oidc: + type: openIdConnect + description: Authentication for service6 + openIdConnectUrl: https://example.com/realms/master/.well-known/openid-configuration \ No newline at end of file diff --git a/client/integration-tests/auth-provider/src/main/resources/application.properties b/client/integration-tests/auth-provider/src/main/resources/application.properties index eeed16b8..42d59467 100644 --- a/client/integration-tests/auth-provider/src/main/resources/application.properties +++ b/client/integration-tests/auth-provider/src/main/resources/application.properties @@ -6,11 +6,13 @@ quarkus.openapi-generator.codegen.spec.token_external_service1_yaml.base-package quarkus.openapi-generator.codegen.spec.token_external_service2_yaml.base-package=org.acme.externalservice2 quarkus.openapi-generator.codegen.spec.token_external_service3_yaml.base-package=org.acme.externalservice3 quarkus.openapi-generator.codegen.spec.token_external_service5_yaml.base-package=org.acme.externalservice5 +quarkus.openapi-generator.codegen.spec.token_external_service6_yaml.base-package=org.acme.externalservice6 quarkus.rest-client.token_external_service1_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_external_service2_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_external_service3_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_external_service5_yaml.url=${propagation-external-service-mock.url} +quarkus.rest-client.token_external_service6_yaml.url=${propagation-external-service-mock.url} # default propagation for token_external_service1 invocation quarkus.openapi-generator.token_external_service1_yaml.auth.service1_http_bearer.token-propagation=true @@ -39,4 +41,15 @@ quarkus.oidc-client.service5_oauth2.grant.type=client quarkus.oidc-client.service5_oauth2.credentials.client-secret.method=basic quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret + +# Oidc client used by the token_external_service6 +quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} +quarkus.oidc-client.service6_oidc.token-path=${keycloak.mock.service.token-path} +quarkus.oidc-client.service6_oidc.discovery-enabled=false +quarkus.oidc-client.service6_oidc.client-id=kogito-app +quarkus.oidc-client.service6_oidc.grant.type=client +quarkus.oidc-client.service6_oidc.credentials.client-secret.method=basic +quarkus.oidc-client.service6_oidc.credentials.client-secret.value=secret + + quarkus.keycloak.devservices.enabled=false \ No newline at end of file diff --git a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java index 7a454521..48f62372 100644 --- a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java +++ b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenExternalServicesMock.java @@ -60,6 +60,11 @@ public Map start() { // configured. The token will be overridden by the custom credential provider stubForExternalService("/token-external-service5/executeQuery5", KEYCLOAK_ACCESS_TOKEN + "_TEST"); + // stub the token-external-service6 invocation with the expected token, no propagation is produced + // in this case but the service must receive the token provided by Keycloak since it has oidc security + // configured. The token will be overridden by the custom credential provider + stubForExternalService("/token-external-service6/executeQuery6", KEYCLOAK_ACCESS_TOKEN + "_TEST"); + return Map.of(TOKEN_EXTERNAL_SERVICE_MOCK_URL, wireMockServer.baseUrl()); } diff --git a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java index 9fd52547..bbd9ebb9 100644 --- a/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java +++ b/client/integration-tests/auth-provider/src/test/java/io/quarkiverse/openapi/generator/it/auth/TokenWithCustomCredentialProviderTest.java @@ -22,7 +22,7 @@ class TokenWithCustomCredentialProviderTest { @ParameterizedTest - @ValueSource(strings = { "service1", "service2", "service3", "service5" }) + @ValueSource(strings = { "service1", "service2", "service3", "service5", "service6" }) void testService(String service) { Map headers = Map.of(HttpHeaders.AUTHORIZATION, AUTHORIZATION_TOKEN); diff --git a/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java b/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java index 4253357f..0a9a1e3a 100644 --- a/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java +++ b/client/integration-tests/security/src/main/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationResource.java @@ -24,6 +24,9 @@ public class TokenPropagationResource { @RestClient org.acme.externalservice5.api.DefaultApi defaultApi5; + @RestClient + org.acme.externalservice6.api.DefaultApi defaultApi6; + @POST @Path("service1") public Response service1() { @@ -53,4 +56,10 @@ public Response service4() { public Response service5() { return defaultApi5.executeQuery5(); } + + @POST + @Path("service6") + public Response service6() { + return defaultApi6.executeQuery6(); + } } diff --git a/client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml b/client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml new file mode 100644 index 00000000..cf2a83c6 --- /dev/null +++ b/client/integration-tests/security/src/main/openapi/token-propagation-external-service6.yaml @@ -0,0 +1,20 @@ +--- +openapi: 3.0.3 +info: + title: external-service6 API + version: 3.0.0-SNAPSHOT +paths: + /token-propagation-external-service6/executeQuery6: + post: + operationId: executeQuery6 + responses: + "200": + description: OK + security: + - service6-oidc: [] +components: + securitySchemes: + service6-oidc: + type: openIdConnect + description: Authentication for service6 + openIdConnectUrl: https://example.com/realms/master/.well-known/openid-configuration diff --git a/client/integration-tests/security/src/main/resources/application.properties b/client/integration-tests/security/src/main/resources/application.properties index e4bb70b7..1e32e3b1 100644 --- a/client/integration-tests/security/src/main/resources/application.properties +++ b/client/integration-tests/security/src/main/resources/application.properties @@ -32,12 +32,15 @@ quarkus.openapi-generator.codegen.spec.token_propagation_external_service2_yaml. quarkus.openapi-generator.codegen.spec.token_propagation_external_service3_yaml.base-package=org.acme.externalservice3 quarkus.openapi-generator.codegen.spec.token_propagation_external_service4_yaml.base-package=org.acme.externalservice4 quarkus.openapi-generator.codegen.spec.token_propagation_external_service5_yaml.base-package=org.acme.externalservice5 +quarkus.openapi-generator.codegen.spec.token_propagation_external_service6_yaml.base-package=org.acme.externalservice6 quarkus.rest-client.token_propagation_external_service1_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service2_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service3_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service4_yaml.url=${propagation-external-service-mock.url} quarkus.rest-client.token_propagation_external_service5_yaml.url=${propagation-external-service-mock.url} +quarkus.rest-client.token_propagation_external_service6_yaml.url=${propagation-external-service-mock.url} + # default propagation for token_propagation_external_service1 invocation quarkus.openapi-generator.token_propagation_external_service1_yaml.auth.service1_http_bearer.token-propagation=true @@ -78,6 +81,15 @@ quarkus.oidc-client.service5_oauth2.grant.type=client quarkus.oidc-client.service5_oauth2.credentials.client-secret.method=basic quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret +# Oidc client used by the token_propagation_external_service6 +quarkus.oidc-client.service6_oidc.auth-server-url=${keycloak.mock.service.url} +quarkus.oidc-client.service6_oidc.token-path=${keycloak.mock.service.token-path} +quarkus.oidc-client.service6_oidc.discovery-enabled=false +quarkus.oidc-client.service6_oidc.client-id=kogito-app +quarkus.oidc-client.service6_oidc.grant.type=client +quarkus.oidc-client.service6_oidc.credentials.client-secret.method=basic +quarkus.oidc-client.service6_oidc.credentials.client-secret.value=secret + quarkus.keycloak.devservices.enabled=false # Slack OpenAPI diff --git a/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java b/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java index 53ecbf2a..62e6863b 100644 --- a/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java +++ b/client/integration-tests/security/src/test/java/io/quarkiverse/openapi/generator/it/security/TokenPropagationExternalServicesMock.java @@ -66,6 +66,11 @@ public Map start() { // configured. stubForExternalService("/token-propagation-external-service5/executeQuery5", KEYCLOAK_ACCESS_TOKEN); + // stub the token-propagation-external-service6 invocation with the expected token, no propagation is produced + // in this case but the service must receive the token provided by Keycloak since it has oidc security + // configured. + stubForExternalService("/token-propagation-external-service6/executeQuery6", KEYCLOAK_ACCESS_TOKEN); + return Map.of(TOKEN_PROPAGATION_EXTERNAL_SERVICE_MOCK_URL, wireMockServer.baseUrl()); }