From 9261f8b0d8f8602840accf658b02544c941daa93 Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Mon, 14 Oct 2024 10:03:34 +0200 Subject: [PATCH 1/8] SmallRye GraphQL 2.11 --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 6d0d5cf2a0855..31e2fc4558d78 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -57,7 +57,7 @@ 4.1.0 4.0.0 3.13.0 - 2.10.0 + 2.11.0 6.5.0 4.6.0 2.1.2 From 4d02b1b78b593a9f2d129225cfd0f738e5e9b985 Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Mon, 23 Sep 2024 01:32:56 +0300 Subject: [PATCH 2/8] changes for namespaces --- .../deployment/SmallRyeGraphQLProcessor.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java index 792edd0eba119..df0fe33f6cadf 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java @@ -82,6 +82,7 @@ import io.smallrye.graphql.api.Deprecated; import io.smallrye.graphql.api.Entry; import io.smallrye.graphql.api.ErrorExtensionProvider; +import io.smallrye.graphql.api.Namespace; import io.smallrye.graphql.api.OneOf; import io.smallrye.graphql.api.federation.Authenticated; import io.smallrye.graphql.api.federation.ComposeDirective; @@ -114,7 +115,6 @@ import io.smallrye.graphql.schema.model.Argument; import io.smallrye.graphql.schema.model.DirectiveType; import io.smallrye.graphql.schema.model.Field; -import io.smallrye.graphql.schema.model.Group; import io.smallrye.graphql.schema.model.InputType; import io.smallrye.graphql.schema.model.Operation; import io.smallrye.graphql.schema.model.Reference; @@ -320,6 +320,7 @@ void buildFinalIndex( indexer.indexClass(RequiresScopes.class); indexer.indexClass(ScopeGroup.class); indexer.indexClass(ScopeItem.class); + indexer.indexClass(Namespace.class); } catch (IOException ex) { LOG.warn("Failure while creating index", ex); } @@ -507,11 +508,7 @@ private boolean getBooleanConfigValue(String smallryeKey, boolean defaultValue) private String[] getSchemaJavaClasses(Schema schema) { // Unique list of classes we need to do reflection on Set classes = new HashSet<>(); - - classes.addAll(getOperationClassNames(schema.getQueries())); - classes.addAll(getOperationClassNames(schema.getGroupedQueries())); - classes.addAll(getOperationClassNames(schema.getMutations())); - classes.addAll(getOperationClassNames(schema.getGroupedMutations())); + classes.addAll(getOperationClassNames(schema.getAllOperations())); classes.addAll(getTypeClassNames(schema.getTypes().values())); classes.addAll(getInputClassNames(schema.getInputs().values())); classes.addAll(getInterfaceClassNames(schema.getInterfaces().values())); @@ -557,15 +554,6 @@ private Set getOperationClassNames(Set operations) { return classes; } - private Set getOperationClassNames(Map> groupedOperations) { - Set classes = new HashSet<>(); - Collection> operations = groupedOperations.values(); - for (Set operationSet : operations) { - classes.addAll(getOperationClassNames(operationSet)); - } - return classes; - } - private Set getTypeClassNames(Collection complexGraphQLTypes) { Set classes = new HashSet<>(); for (Type complexGraphQLType : complexGraphQLTypes) { From 51b455249736d835a66899bbabc5909f367d57a1 Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Fri, 27 Sep 2024 14:12:30 +0300 Subject: [PATCH 3/8] Add federation Resolver annotation to index --- .../smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java index df0fe33f6cadf..1ff5438078a37 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java @@ -94,6 +94,7 @@ import io.smallrye.graphql.api.federation.Key; import io.smallrye.graphql.api.federation.Provides; import io.smallrye.graphql.api.federation.Requires; +import io.smallrye.graphql.api.federation.Resolver; import io.smallrye.graphql.api.federation.Shareable; import io.smallrye.graphql.api.federation.Tag; import io.smallrye.graphql.api.federation.link.Import; @@ -321,6 +322,7 @@ void buildFinalIndex( indexer.indexClass(ScopeGroup.class); indexer.indexClass(ScopeItem.class); indexer.indexClass(Namespace.class); + indexer.indexClass(Resolver.class); } catch (IOException ex) { LOG.warn("Failure while creating index", ex); } From 922a4f5aad4421c5168b5387a98d13637120ef9f Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Fri, 27 Sep 2024 15:30:24 +0300 Subject: [PATCH 4/8] Add tests for resolvers --- .../federation/resolver/ExtendedApi.java | 25 ++++++ .../federation/resolver/ExtendedType.java | 65 ++++++++++++++++ .../resolver/FederationResolverTest.java | 77 +++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedApi.java create mode 100644 extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedType.java create mode 100644 extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/FederationResolverTest.java diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedApi.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedApi.java new file mode 100644 index 0000000000000..e33ecb3b5b1c7 --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedApi.java @@ -0,0 +1,25 @@ +package io.quarkus.smallrye.graphql.deployment.federation.resolver; + +import org.eclipse.microprofile.graphql.GraphQLApi; + +import io.smallrye.graphql.api.federation.Resolver; + +@GraphQLApi +public class ExtendedApi { + @Resolver + public ExtendedType extendedTypeById(String id) { + ExtendedType extendedType = new ExtendedType(); + extendedType.setId(id); + extendedType.setDescription("extendedTypeById"); + return extendedType; + } + + @Resolver + public ExtendedType extendedTypeByIdNameKey(String id, String name, String key) { + ExtendedType extendedType = new ExtendedType(); + extendedType.setId(id); + extendedType.setValue(id + name + key); + extendedType.setDescription("extendedTypeByIdNameKey"); + return extendedType; + } +} diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedType.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedType.java new file mode 100644 index 0000000000000..2245792651af5 --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/ExtendedType.java @@ -0,0 +1,65 @@ +package io.quarkus.smallrye.graphql.deployment.federation.resolver; + +import io.smallrye.graphql.api.federation.Extends; +import io.smallrye.graphql.api.federation.External; +import io.smallrye.graphql.api.federation.FieldSet; +import io.smallrye.graphql.api.federation.Key; +import io.smallrye.graphql.api.federation.Requires; + +@Extends +@Key(fields = @FieldSet("id")) +public class ExtendedType { + @External + private String id; + + @External + private String name; + + @External + private String key; + + @Requires(fields = @FieldSet("name key")) + private String value; + + private String description; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/FederationResolverTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/FederationResolverTest.java new file mode 100644 index 0000000000000..748aecf66c352 --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/resolver/FederationResolverTest.java @@ -0,0 +1,77 @@ +package io.quarkus.smallrye.graphql.deployment.federation.resolver; + +import org.hamcrest.CoreMatchers; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.smallrye.graphql.deployment.AbstractGraphQLTest; +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class FederationResolverTest extends AbstractGraphQLTest { + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(ExtendedApi.class, ExtendedType.class) + .addAsResource(new StringAsset("quarkus.smallrye-graphql.schema-include-directives=true"), + "application.properties") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @Test + public void resolverById() { + String request = getPayload(TEST_ID_QUERY); + RestAssured.given().when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(request) + .post("/graphql") + .then() + .assertThat() + .statusCode(200) + .and() + .body(CoreMatchers.is( + "{\"data\":{\"_entities\":[{\"id\":\"id\",\"description\":\"extendedTypeById\"}]}}")); + } + + @Test + public void resolverByIdNameKey() { + String request = getPayload(TEST_ID_NAME_KEY_QUERY); + RestAssured.given().when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(request) + .post("/graphql") + .then() + .assertThat() + .statusCode(200) + .and() + .body(CoreMatchers.is( + "{\"data\":{\"_entities\":[{\"id\":\"id\",\"value\":\"idnamekey\",\"description\":\"extendedTypeByIdNameKey\"}]}}")); + } + + private static final String TEST_ID_QUERY = "query {\n" + + "_entities(\n" + + " representations: { id: \"id\", __typename: \"ExtendedType\" }\n" + + ") {\n" + + " ... on ExtendedType {\n" + + " id\n" + + " description\n" + + " }\n" + + " }\n" + + "}"; + + private static final String TEST_ID_NAME_KEY_QUERY = "query {\n" + + "_entities(\n" + + " representations: { id: \"id\", name: \"name\", key: \"key\", __typename: \"ExtendedType\" }\n" + + ") {\n" + + " ... on ExtendedType {\n" + + " id\n" + + " value\n" + + " description\n" + + " }\n" + + " }\n" + + "}"; +} From b3dbcb38f5bc904bea3014a0b0cf0700ac906c22 Mon Sep 17 00:00:00 2001 From: Marek Skacelik Date: Fri, 13 Sep 2024 10:22:04 +0200 Subject: [PATCH 5/8] Added implementation of TLS-registry for GraphQL Client --- .../main/asciidoc/tls-registry-reference.adoc | 12 +- .../deployment/pom.xml | 14 ++ .../SmallRyeGraphQLClientProcessor.java | 19 ++- .../deployment/ssl/SSLTestingTools.java | 59 +++++++ ...ntClientAuthenticationBadKeystoreTest.java | 90 +++++++++++ ...ientAuthenticationCorrectKeystoreTest.java | 72 +++++++++ ...raphQLClientReloadKeystoreDefaultTest.java | 142 +++++++++++++++++ ...pesafeGraphQLClientReloadKeystoreTest.java | 145 ++++++++++++++++++ ...ientServerAndClientAuthenticationTest.java | 73 +++++++++ ...AuthenticationBadKeystoreOnServerTest.java | 88 +++++++++++ ...erAuthenticationCorrectTruststoreTest.java | 71 +++++++++ .../smallrye-graphql-client/runtime/pom.xml | 4 + ...LClientCertificateUpdateEventListener.java | 52 +++++++ .../client/runtime/GraphQLClientConfig.java | 37 +++++ .../SmallRyeGraphQLClientRecorder.java | 38 ++++- 15 files changed, 904 insertions(+), 12 deletions(-) create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationBadKeystoreTest.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationCorrectKeystoreTest.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAndClientAuthenticationTest.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationBadKeystoreOnServerTest.java create mode 100644 extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationCorrectTruststoreTest.java create mode 100644 extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java diff --git a/docs/src/main/asciidoc/tls-registry-reference.adoc b/docs/src/main/asciidoc/tls-registry-reference.adoc index 297cfa50f1356..b566976b92ced 100644 --- a/docs/src/main/asciidoc/tls-registry-reference.adoc +++ b/docs/src/main/asciidoc/tls-registry-reference.adoc @@ -21,11 +21,12 @@ The TLS Registry consolidates settings and supports multiple named configuration Therefore, you can tailor TLS settings for different application parts. This flexibility is particularly useful when different components require distinct security configurations. -The TLS Registry extension is automatically included in your project when you use compatible extensions, such as Quarkus REST, gRPC +The TLS Registry extension is automatically included in your project when you use compatible extensions, such as Quarkus REST, gRPC, SmallRye GraphQL Client ifndef::no-reactive-routes[] , or Reactive Routes endif::no-reactive-routes[] . +The TLS Registry extension is automatically included in your project when you use compatible extensions, such as Quarkus REST, gRPC, SmallRye GraphQL Client, or Reactive Routes. As a result, applications that use the TLS Registry can be ready to handle secure communications out of the box. TLS Registry also provides features like automatic certificate reloading, Let's Encrypt (ACME) integration, Kubernetes Cert-Manager support, and compatibility with various keystore formats, such as PKCS12, PEM, and JKS. @@ -149,6 +150,15 @@ quarkus.http.tls-configuration-name=MY_TLS_CONFIGURATION quarkus.grpc.clients.hello.tls-configuration-name=MY_TLS_CONFIGURATION ---- +.Example configuration for a SmallRye GraphQL client: +[source,properties] +---- +quarkus.smallrye-graphql-client.my-client.tls-configuration-name=MY_TLS_CONFIGURATION +---- +> [NOTE] +> When using the Typesafe GraphQL client with a certificate reloading mechanism (see <>), it is essential to override the bean's scope to `RequestScoped` (or another similar scope). By default, the Typesafe client is an application-scoped bean. +> This guarantees that each new instance of the bean created after a certificate reload will be configured with the latest certificate. + == Configuring TLS TLS configuration primarily involves managing keystores and truststores. diff --git a/extensions/smallrye-graphql-client/deployment/pom.xml b/extensions/smallrye-graphql-client/deployment/pom.xml index 39802c416ed48..0ff02d5c2a3a5 100644 --- a/extensions/smallrye-graphql-client/deployment/pom.xml +++ b/extensions/smallrye-graphql-client/deployment/pom.xml @@ -41,6 +41,10 @@ io.smallrye smallrye-graphql-client-model-builder + + io.quarkus + quarkus-tls-registry-deployment + io.smallrye smallrye-graphql-client-model @@ -81,6 +85,16 @@ quarkus-elytron-security-properties-file-deployment test + + org.assertj + assertj-core + test + + + io.smallrye.certs + smallrye-certificate-generator-junit5 + test + diff --git a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java index ccbe1690d2004..b7cd32fa124a6 100644 --- a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java +++ b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Map; -import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Singleton; import org.eclipse.microprofile.graphql.Input; @@ -26,9 +25,12 @@ import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem; import io.quarkus.arc.deployment.BeanContainerBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.deployment.SyntheticBeansRuntimeInitBuildItem; +import io.quarkus.arc.processor.BuiltinScope; import io.quarkus.deployment.Feature; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.Consume; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.AdditionalIndexedClassesBuildItem; import io.quarkus.deployment.builditem.CombinedIndexBuildItem; @@ -40,6 +42,7 @@ import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.runtime.RuntimeValue; import io.quarkus.smallrye.graphql.client.runtime.GraphQLClientBuildConfig; +import io.quarkus.smallrye.graphql.client.runtime.GraphQLClientCertificateUpdateEventListener; import io.quarkus.smallrye.graphql.client.runtime.GraphQLClientSupport; import io.quarkus.smallrye.graphql.client.runtime.GraphQLClientsConfig; import io.quarkus.smallrye.graphql.client.runtime.SmallRyeGraphQLClientRecorder; @@ -52,6 +55,7 @@ public class SmallRyeGraphQLClientProcessor { private static final DotName GRAPHQL_CLIENT_API = DotName .createSimple("io.smallrye.graphql.client.typesafe.api.GraphQLClientApi"); private static final DotName GRAPHQL_CLIENT = DotName.createSimple("io.smallrye.graphql.client.GraphQLClient"); + private static final String CERTIFICATE_UPDATE_EVENT_LISTENER = GraphQLClientCertificateUpdateEventListener.class.getName(); private static final String NAMED_DYNAMIC_CLIENTS = "io.smallrye.graphql.client.impl.dynamic.cdi.NamedDynamicClients"; @BuildStep @@ -124,10 +128,11 @@ void initializeTypesafeClient(BeanArchiveIndexBuildItem index, } } + BuiltinScope scope = BuiltinScope.from(index.getIndex().getClassByName(apiClass)); // an equivalent of io.smallrye.graphql.client.typesafe.impl.cdi.GraphQlClientBean that produces typesafe client instances SyntheticBeanBuildItem bean = SyntheticBeanBuildItem.configure(apiClassInfo.name()) .addType(apiClassInfo.name()) - .scope(ApplicationScoped.class) + .scope(scope == null ? BuiltinScope.APPLICATION.getInfo() : scope.getInfo()) .addInjectionPoint(ClassType.create(DotName.createSimple(ClientModels.class))) .createWith(recorder.typesafeClientSupplier(apiClass)) .unremovable() @@ -165,13 +170,12 @@ void setTypesafeApiClasses(BeanArchiveIndexBuildItem index, */ @BuildStep @Record(RUNTIME_INIT) - GraphQLClientConfigInitializedBuildItem mergeClientConfigurations(BuildProducer syntheticBeans, - SmallRyeGraphQLClientRecorder recorder, + @Consume(SyntheticBeansRuntimeInitBuildItem.class) + GraphQLClientConfigInitializedBuildItem mergeClientConfigurations(SmallRyeGraphQLClientRecorder recorder, GraphQLClientsConfig quarkusConfig, BeanArchiveIndexBuildItem index) { // to store config keys of all clients found in the application code List knownConfigKeys = new ArrayList<>(); - Map shortNamesToQualifiedNames = new HashMap<>(); for (AnnotationInstance annotation : index.getIndex().getAnnotations(GRAPHQL_CLIENT_API)) { ClassInfo clazz = annotation.target().asClass(); @@ -241,4 +245,9 @@ void setAdditionalClassesToIndex(BuildProducer additionalBeans) { + additionalBeans.produce(new AdditionalBeanBuildItem(CERTIFICATE_UPDATE_EVENT_LISTENER)); + } + } diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java new file mode 100644 index 0000000000000..99dac5dfeeb36 --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java @@ -0,0 +1,59 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import java.security.KeyStore; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import io.smallrye.graphql.client.vertx.ssl.SSLTools; +import io.vertx.core.Vertx; +import io.vertx.core.http.ClientAuth; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.net.JksOptions; +import io.vertx.core.net.PfxOptions; + +public class SSLTestingTools { + private Vertx vertx; + + public HttpServer runServer(String keystorePath, String keystorePassword, + String truststorePath, String truststorePassword) + throws InterruptedException, ExecutionException, TimeoutException { + vertx = Vertx.vertx(); + HttpServerOptions options = new HttpServerOptions(); + options.setSsl(true); + options.setHost("localhost"); + + if (keystorePath != null) { + PfxOptions keystoreOptions = new PfxOptions(); + KeyStore keyStore = SSLTools.createKeyStore(keystorePath, "PKCS12", keystorePassword); + keystoreOptions.setValue(SSLTools.asBuffer(keyStore, keystorePassword.toCharArray())); + keystoreOptions.setPassword(keystorePassword); + options.setKeyCertOptions(keystoreOptions); + } + + if (truststorePath != null) { + options.setClientAuth(ClientAuth.REQUIRED); + PfxOptions truststoreOptions = new PfxOptions(); + KeyStore trustStore = SSLTools.createKeyStore(truststorePath, "PKCS12", truststorePassword); + truststoreOptions.setValue(SSLTools.asBuffer(trustStore, truststorePassword.toCharArray())); + truststoreOptions.setPassword(truststorePassword); + options.setTrustOptions(truststoreOptions); + } + + HttpServer server = vertx.createHttpServer(options); + server.requestHandler(request -> { + request.response().send("{\n" + + " \"data\": {\n" + + " \"result\": \"HelloWorld\"\n" + + " }\n" + + "}"); + }); + + return server.listen(63805).toCompletionStage().toCompletableFuture().get(10, TimeUnit.SECONDS); + } + + public void close() { + vertx.close(); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationBadKeystoreTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationBadKeystoreTest.java new file mode 100644 index 0000000000000..89c4a0c36976d --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationBadKeystoreTest.java @@ -0,0 +1,90 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import jakarta.inject.Inject; + +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "graphql", password = "password", formats = { Format.PKCS12 }, client = true), + @Certificate(name = "wrong-graphql", password = "wrong-password", formats = { Format.PKCS12 }, client = true) +}) +public class TypesafeGraphQLClientClientAuthenticationBadKeystoreTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static HttpServer server; + + private static final String CONFIGURATION = """ + quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client + quarkus.tls.my-tls-client.key-store.p12.path=target/certs/wrong-graphql-client-keystore.p12 + quarkus.tls.my-tls-client.key-store.p12.password=wrong-password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + quarkus.tls.my-tls-client.trust-all=true + """.formatted(PORT); + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(MyApi.class, SSLTestingTools.class) + .addAsResource(new StringAsset(CONFIGURATION), + "application.properties") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @GraphQLClientApi(configKey = "my-client") + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/graphql-keystore.p12", + "password", "target/certs/graphql-server-truststore.p12", "password"); + } + + @Test + void clientAuthentication_badKeystore() { + try { + myApi.getResult(); + Assertions.fail("Should not be able to connect"); + } catch (Exception e) { + // verify that the server rejected the client's certificate + assertHasCauseContainingMessage(e, "Received fatal alert: certificate_unknown"); + } + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } + + private void assertHasCauseContainingMessage(Throwable t, String message) { + Throwable throwable = t; + while (throwable.getCause() != null) { + throwable = throwable.getCause(); + if (throwable.getMessage().contains(message)) { + t.printStackTrace(); + return; + } + } + throw new RuntimeException("Unexpected exception", t); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationCorrectKeystoreTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationCorrectKeystoreTest.java new file mode 100644 index 0000000000000..b3f0fbbe1b087 --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientClientAuthenticationCorrectKeystoreTest.java @@ -0,0 +1,72 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import jakarta.inject.Inject; + +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; + +@Certificates(baseDir = "target/certs", certificates = @Certificate(name = "graphql", password = "password", formats = { + Format.PKCS12 }, client = true)) +public class TypesafeGraphQLClientClientAuthenticationCorrectKeystoreTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static final String EXPECTED_RESPONSE = "HelloWorld"; + private static HttpServer server; + + private static final String CONFIGURATION = """ + quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client + quarkus.tls.my-tls-client.key-store.p12.path=target/certs/graphql-client-keystore.p12 + quarkus.tls.my-tls-client.key-store.p12.password=password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + quarkus.tls.my-tls-client.trust-all=true + """.formatted(PORT); + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(MyApi.class, SSLTestingTools.class) + .addAsResource(new StringAsset(CONFIGURATION), + "application.properties") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @GraphQLClientApi(configKey = "my-client") + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/graphql-keystore.p12", + "password", "target/certs/graphql-server-truststore.p12", "password"); + } + + @Test + void clientAuthentication_correctKeystore() { + assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java new file mode 100644 index 0000000000000..e92806f8a3d8a --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java @@ -0,0 +1,142 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import io.quarkus.arc.Arc; +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.tls.CertificateUpdatedEvent; +import io.quarkus.tls.TlsConfiguration; +import io.quarkus.tls.TlsConfigurationRegistry; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; +import io.vertx.core.net.KeyCertOptions; +import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.event.Event; +import jakarta.inject.Inject; +import org.assertj.core.api.Assertions; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "wrong-test-reload", password = "password", formats = Format.PKCS12, client = true), + @Certificate(name = "test-reload", password = "password", formats = Format.PKCS12, client = true) +}) +public class TypesafeGraphQLClientReloadKeystoreDefaultTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static final String EXPECTED_RESPONSE = "HelloWorld"; + private static HttpServer server; + + private static final File temp = new File("target/test-certificates-" + UUID.randomUUID()); + + private static final String CONFIGURATION = """ + quarkus.tls.key-store.p12.path=%s + quarkus.tls.key-store.p12.password=password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + quarkus.tls.trust-all=true + """.formatted(temp.getAbsolutePath() + "/tls.p12", PORT); + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(CONFIGURATION), "application.properties") + .addClasses(MyApi.class, SSLTestingTools.class)) + .overrideRuntimeConfigKey("loc", temp.getAbsolutePath()) + .setBeforeAllCustomizer(() -> { + try { + temp.mkdirs(); + Files.copy(new File("target/certs/wrong-test-reload-client-keystore.p12").toPath(), + new File(temp, "/tls.p12").toPath()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + @GraphQLClientApi(configKey = "my-client") + @RequestScoped + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @Inject + TlsConfigurationRegistry registry; + + @ConfigProperty(name = "loc") + File certs; + + @Inject + Event event; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/test-reload-keystore.p12", + "password", "target/certs/test-reload-server-truststore.p12", + "password"); + } + + @Test + void testReloading() throws IOException { + TlsConfiguration def = registry.getDefault().orElseThrow(); + KeyCertOptions keystoreOptionsBefore = (KeyCertOptions) GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions(); + Arc.container().requestContext().activate(); + try { + myApi.getResult(); + Assertions.fail(); // should fail + } catch (Exception ex) { + assertHasCauseContainingMessage(ex, "Received fatal alert: certificate_unknown"); + } finally { + Arc.container().requestContext().terminate(); + } + Files.copy(new File("target/certs/test-reload-client-keystore.p12").toPath(), + new File(certs, "/tls.p12").toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + + assertThat(def.reload()).isTrue(); + event.fire(new CertificateUpdatedEvent("", def)); + Arc.container().requestContext().activate(); + try { + assertThat(GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions()).isNotEqualTo(keystoreOptionsBefore); + assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); + } finally { + Arc.container().requestContext().terminate(); + } + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } + + private void assertHasCauseContainingMessage(Throwable t, String message) { + Throwable throwable = t; + while (throwable.getCause() != null) { + throwable = throwable.getCause(); + if (throwable.getMessage().contains(message)) { + return; + } + } + throw new RuntimeException("Unexpected exception", t); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java new file mode 100644 index 0000000000000..b64b69fac0a40 --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java @@ -0,0 +1,145 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.UUID; + +import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; +import io.vertx.core.net.KeyCertOptions; +import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.event.Event; +import jakarta.inject.Inject; + +import org.assertj.core.api.Assertions; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.tls.CertificateUpdatedEvent; +import io.quarkus.tls.TlsConfiguration; +import io.quarkus.tls.TlsConfigurationRegistry; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "wrong-test-reload", password = "password", formats = Format.PKCS12, client = true), + @Certificate(name = "test-reload", password = "password", formats = Format.PKCS12, client = true) +}) +public class TypesafeGraphQLClientReloadKeystoreTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static final String EXPECTED_RESPONSE = "HelloWorld"; + private static HttpServer server; + + private static final File temp = new File("target/test-certificates-" + UUID.randomUUID()); + + private static final String CONFIGURATION = """ + quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client + quarkus.tls.my-tls-client.key-store.p12.path=%s + quarkus.tls.my-tls-client.key-store.p12.password=password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + quarkus.tls.my-tls-client.trust-all=true + """.formatted(temp.getAbsolutePath() + "/tls.p12", PORT); + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(CONFIGURATION), "application.properties") + .addClasses(MyApi.class, SSLTestingTools.class)) + .overrideRuntimeConfigKey("loc", temp.getAbsolutePath()) + .setBeforeAllCustomizer(() -> { + try { + temp.mkdirs(); + Files.copy(new File("target/certs/wrong-test-reload-client-keystore.p12").toPath(), + new File(temp, "/tls.p12").toPath()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + @GraphQLClientApi(configKey = "my-client") + @RequestScoped + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @Inject + TlsConfigurationRegistry registry; + + @ConfigProperty(name = "loc") + File certs; + + @Inject + Event event; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/test-reload-keystore.p12", + "password", "target/certs/test-reload-server-truststore.p12", + "password"); + } + + @Test + void testReloading() throws IOException { + TlsConfiguration tlsClient = registry.get("my-tls-client").orElseThrow(); + KeyCertOptions keystoreOptionsBefore = (KeyCertOptions) GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions(); + Arc.container().requestContext().activate(); + try { + myApi.getResult(); + Assertions.fail(); // should fail + } catch (Exception ex) { + assertHasCauseContainingMessage(ex, "Received fatal alert: certificate_unknown"); + } finally { + Arc.container().requestContext().terminate(); + } + Files.copy(new File("target/certs/test-reload-client-keystore.p12").toPath(), + new File(certs, "/tls.p12").toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + + assertThat(tlsClient.reload()).isTrue(); + event.fire(new CertificateUpdatedEvent("my-tls-client", tlsClient)); + Arc.container().requestContext().activate(); + try { + assertThat(GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions()).isNotEqualTo(keystoreOptionsBefore); + assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); + } finally { + Arc.container().requestContext().terminate(); + } + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } + + private void assertHasCauseContainingMessage(Throwable t, String message) { + Throwable throwable = t; + while (throwable.getCause() != null) { + throwable = throwable.getCause(); + if (throwable.getMessage().contains(message)) { + return; + } + } + throw new RuntimeException("Unexpected exception", t); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAndClientAuthenticationTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAndClientAuthenticationTest.java new file mode 100644 index 0000000000000..f7329518fe1ec --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAndClientAuthenticationTest.java @@ -0,0 +1,73 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import jakarta.inject.Inject; + +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; + +@Certificates(baseDir = "target/certs", certificates = @Certificate(name = "graphql", password = "password", formats = { + Format.PKCS12 }, client = true)) +public class TypesafeGraphQLClientServerAndClientAuthenticationTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static final String EXPECTED_RESPONSE = "HelloWorld"; + private static HttpServer server; + + private static final String CONFIGURATION = """ + quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client + quarkus.tls.my-tls-client.key-store.p12.path=target/certs/graphql-client-keystore.p12 + quarkus.tls.my-tls-client.key-store.p12.password=password + quarkus.tls.my-tls-client.trust-store.p12.path=target/certs/graphql-client-truststore.p12 + quarkus.tls.my-tls-client.trust-store.p12.password=password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + """.formatted(PORT); + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(MyApi.class, SSLTestingTools.class) + .addAsResource(new StringAsset(CONFIGURATION), + "application.properties") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @GraphQLClientApi(configKey = "my-client") + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/graphql-keystore.p12", + "password", "target/certs/graphql-server-truststore.p12", "password"); + } + + @Test + void clientAuthentication_correctKeystore() { + assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationBadKeystoreOnServerTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationBadKeystoreOnServerTest.java new file mode 100644 index 0000000000000..ffb3b53951d1f --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationBadKeystoreOnServerTest.java @@ -0,0 +1,88 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import jakarta.inject.Inject; + +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "graphql", password = "password", formats = { Format.PKCS12 }, client = true), + @Certificate(name = "wrong-graphql", password = "wrong-password", formats = { Format.PKCS12 }) +}) +public class TypesafeGraphQLClientServerAuthenticationBadKeystoreOnServerTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static HttpServer server; + + private static final String CONFIGURATION = """ + quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client + quarkus.tls.my-tls-client.trust-store.p12.path=target/certs/graphql-client-truststore.p12 + quarkus.tls.my-tls-client.trust-store.p12.password=password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + """.formatted(PORT); + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(MyApi.class, SSLTestingTools.class) + .addAsResource(new StringAsset(CONFIGURATION), + "application.properties") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @GraphQLClientApi(configKey = "my-client") + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/wrong-graphql-keystore.p12", + "wrong-password", null, null); + } + + @Test + void serverAuthentication_badKeystoreOnServer() { + try { + myApi.getResult(); + Assertions.fail("Should not be able to connect"); + } catch (Exception ex) { + assertHasCauseContainingMessage(ex, "Path does not chain with any of the trust anchors"); + } + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } + + private void assertHasCauseContainingMessage(Throwable t, String message) { + Throwable throwable = t; + while (throwable.getCause() != null) { + throwable = throwable.getCause(); + if (throwable.getMessage().contains(message)) { + t.printStackTrace(); + return; + } + } + throw new RuntimeException("Unexpected exception", t); + } +} diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationCorrectTruststoreTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationCorrectTruststoreTest.java new file mode 100644 index 0000000000000..52ffec083bb32 --- /dev/null +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientServerAuthenticationCorrectTruststoreTest.java @@ -0,0 +1,71 @@ +package io.quarkus.smallrye.graphql.client.deployment.ssl; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import jakarta.inject.Inject; + +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; + +@Certificates(baseDir = "target/certs", certificates = @Certificate(name = "graphql", password = "password", formats = { + Format.PKCS12 }, client = true)) +public class TypesafeGraphQLClientServerAuthenticationCorrectTruststoreTest { + + private static final int PORT = 63805; + private static final SSLTestingTools TOOLS = new SSLTestingTools(); + private static final String EXPECTED_RESPONSE = "HelloWorld"; + private static HttpServer server; + + private static final String CONFIGURATION = """ + quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client + quarkus.tls.my-tls-client.trust-store.p12.path=target/certs/graphql-client-truststore.p12 + quarkus.tls.my-tls-client.trust-store.p12.password=password + quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ + """.formatted(PORT); + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(MyApi.class, SSLTestingTools.class) + .addAsResource(new StringAsset(CONFIGURATION), + "application.properties") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @GraphQLClientApi(configKey = "my-client") + private interface MyApi { + @Query + String getResult(); + } + + @Inject + MyApi myApi; + + @BeforeAll + static void setupServer() throws Exception { + server = TOOLS.runServer("target/certs/graphql-keystore.p12", + "password", null, null); + } + + @Test + void serverAuthentication_correctTruststore() { + assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); + } + + @AfterAll + static void closeServer() { + server.close(); + TOOLS.close(); + } +} diff --git a/extensions/smallrye-graphql-client/runtime/pom.xml b/extensions/smallrye-graphql-client/runtime/pom.xml index f0e29e2ed24c5..e79eb164f31e9 100644 --- a/extensions/smallrye-graphql-client/runtime/pom.xml +++ b/extensions/smallrye-graphql-client/runtime/pom.xml @@ -38,6 +38,10 @@ io.smallrye smallrye-graphql-client-model + + io.quarkus + quarkus-tls-registry + io.smallrye smallrye-graphql-client-implementation-vertx diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java new file mode 100644 index 0000000000000..201d56054af22 --- /dev/null +++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java @@ -0,0 +1,52 @@ +package io.quarkus.smallrye.graphql.client.runtime; + +import io.smallrye.graphql.client.impl.GraphQLClientConfiguration; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.jboss.logging.Logger; + +import io.quarkus.tls.CertificateUpdatedEvent; +import io.quarkus.tls.TlsConfiguration; +import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; + +import static io.quarkus.tls.runtime.config.TlsConfig.DEFAULT_NAME; + +@Singleton +public class GraphQLClientCertificateUpdateEventListener { + + private final static Logger LOG = Logger.getLogger(GraphQLClientCertificateUpdateEventListener.class); + + @Inject + GraphQLClientsConfig graphQLClientsConfig; + + public void onCertificateUpdate(@Observes CertificateUpdatedEvent event) { + String updatedTlsConfigurationName = event.name(); + TlsConfiguration updatedTlsConfiguration = event.tlsConfiguration(); + graphQLClientsConfig.clients + .forEach((configKey, clientConfig) -> { + GraphQLClientConfiguration graphQLClientConfiguration = GraphQLClientsConfiguration.getInstance().getClient(configKey); + clientConfig.tlsConfigurationName.ifPresentOrElse(tlsConfigurationName -> { + if (tlsConfigurationName.equals(updatedTlsConfigurationName)) { + updateConfiguration(updatedTlsConfigurationName, updatedTlsConfiguration, graphQLClientConfiguration, configKey); + } + }, () -> { + if (DEFAULT_NAME.equals(updatedTlsConfigurationName)) { + updateConfiguration("default", updatedTlsConfiguration, graphQLClientConfiguration, configKey); + } + }); + }); + } + + private void updateConfiguration(String tlsBucketName, TlsConfiguration updatedTlsConfiguration, GraphQLClientConfiguration graphQLClientConfiguration, String configKey) { + LOG.infof("Certificate reloaded for the client '%s' using the TLS configuration (bucket) name '%s'", configKey, + tlsBucketName); + graphQLClientConfiguration + .setTlsKeyStoreOptions(updatedTlsConfiguration.getKeyStoreOptions()); + graphQLClientConfiguration + .setTlsTrustStoreOptions(updatedTlsConfiguration.getTrustStoreOptions()); + graphQLClientConfiguration + .setSslOptions(updatedTlsConfiguration.getSSLOptions()); // CLR + } +} diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java index dcbe959117b0a..b5286242cee6b 100644 --- a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java +++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java @@ -52,38 +52,69 @@ public class GraphQLClientConfig { /** * The trust store location. Can point to either a classpath resource or a file. + * + * @deprecated This configuration property is deprecated. Consider using the Quarkus TLS registry. + * Set the desired TLS bucket name using the following configuration property: + * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem + @Deprecated public Optional trustStore; /** * The trust store password. + * + * @deprecated This configuration property is deprecated. Consider using the Quarkus TLS registry. + * Set the desired TLS bucket name using the following configuration property: + * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem + @Deprecated public Optional trustStorePassword; /** * The type of the trust store. Defaults to "JKS". + * + * @deprecated This configuration property is deprecated. Consider using the Quarkus TLS registry. + * Set the desired TLS bucket name using the following configuration property: + * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem + @Deprecated public Optional trustStoreType; /** * The key store location. Can point to either a classpath resource or a file. + * + * @deprecated This configuration property is deprecated. Consider using the Quarkus TLS registry. + * Set the desired TLS bucket name using the following configuration property: + * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem + @Deprecated public Optional keyStore; /** * The key store password. + * + * @deprecated This configuration property is deprecated. Consider using the Quarkus TLS registry. + * Set the desired TLS bucket name using the following configuration property: + * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem + @Deprecated public Optional keyStorePassword; /** * The type of the key store. Defaults to "JKS". + * + * @deprecated This configuration property is deprecated. Consider using the Quarkus TLS registry. + * Set the desired TLS bucket name using the following configuration property: + * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. + * */ @ConfigItem + @Deprecated public Optional keyStoreType; /** @@ -130,4 +161,10 @@ public class GraphQLClientConfig { */ @ConfigItem public Optional allowUnexpectedResponseFields; + + /** + * The name of the TLS configuration (bucket) used for client authentication in the TLS registry. + */ + @ConfigItem + public Optional tlsConfigurationName; } diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java index 27ff5b5af7262..f4c1294f7fba1 100644 --- a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java +++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java @@ -13,10 +13,13 @@ import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.logging.Logger; +import io.quarkus.arc.Arc; import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; +import io.quarkus.tls.TlsConfiguration; +import io.quarkus.tls.TlsConfigurationRegistry; import io.smallrye.graphql.client.impl.GraphQLClientConfiguration; import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; import io.smallrye.graphql.client.model.ClientModels; @@ -119,12 +122,22 @@ private GraphQLClientConfiguration toSmallRyeNativeConfiguration(GraphQLClientCo .map(m -> new HashMap(m)).orElse(null)); quarkusConfig.url.ifPresent(transformed::setUrl); transformed.setWebsocketSubprotocols(quarkusConfig.subprotocols.orElse(new ArrayList<>())); - quarkusConfig.keyStore.ifPresent(transformed::setKeyStore); - quarkusConfig.keyStoreType.ifPresent(transformed::setKeyStoreType); - quarkusConfig.keyStorePassword.ifPresent(transformed::setKeyStorePassword); - quarkusConfig.trustStore.ifPresent(transformed::setTrustStore); - quarkusConfig.trustStoreType.ifPresent(transformed::setTrustStoreType); - quarkusConfig.trustStorePassword.ifPresent(transformed::setTrustStorePassword); + resolveTlsConfigurationForRegistry(quarkusConfig) + .ifPresentOrElse(tlsConfiguration -> { + transformed.setTlsKeyStoreOptions(tlsConfiguration.getKeyStoreOptions()); + transformed.setTlsTrustStoreOptions(tlsConfiguration.getTrustStoreOptions()); + transformed.setSslOptions(tlsConfiguration.getSSLOptions()); + tlsConfiguration.getHostnameVerificationAlgorithm().ifPresent(transformed::setHostnameVerificationAlgorithm); + transformed.setUsesSni(Boolean.valueOf(tlsConfiguration.usesSni())); + }, () -> { + // DEPRECATED + quarkusConfig.keyStore.ifPresent(transformed::setKeyStore); + quarkusConfig.keyStoreType.ifPresent(transformed::setKeyStoreType); + quarkusConfig.keyStorePassword.ifPresent(transformed::setKeyStorePassword); + quarkusConfig.trustStore.ifPresent(transformed::setTrustStore); + quarkusConfig.trustStoreType.ifPresent(transformed::setTrustStoreType); + quarkusConfig.trustStorePassword.ifPresent(transformed::setTrustStorePassword); + }); quarkusConfig.proxyHost.ifPresent(transformed::setProxyHost); quarkusConfig.proxyPort.ifPresent(transformed::setProxyPort); quarkusConfig.proxyUsername.ifPresent(transformed::setProxyUsername); @@ -149,4 +162,17 @@ public RuntimeValue getRuntimeClientModel(ClientModels clientModel return new RuntimeValue<>(clientModel); } + private Optional resolveTlsConfigurationForRegistry(GraphQLClientConfig quarkusConfig) { + if (Arc.container() != null) { + TlsConfigurationRegistry tlsConfigurationRegistry = Arc.container().select(TlsConfigurationRegistry.class).orNull(); + if (tlsConfigurationRegistry != null) { + if (tlsConfigurationRegistry.getDefault().isPresent() && (tlsConfigurationRegistry.getDefault().get().getTrustStoreOptions() != null + || tlsConfigurationRegistry.getDefault().get().isTrustAll())) { + return tlsConfigurationRegistry.getDefault(); + } + return TlsConfiguration.from(tlsConfigurationRegistry, quarkusConfig.tlsConfigurationName); + } + } + return Optional.empty(); + } } From 6025d287489689fee17d7cec7a2233ee496e8e4c Mon Sep 17 00:00:00 2001 From: Dimitris Polissiou Date: Tue, 1 Oct 2024 15:07:09 +0300 Subject: [PATCH 6/8] Change GraphQL bean validation test assertions Remove field arguments from expected field error path, add separate assertions for the violation property path --- .../deployment/GraphQLBeanValidationTest.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLBeanValidationTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLBeanValidationTest.java index 8ef79e03df346..d57b8ad2bff0e 100644 --- a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLBeanValidationTest.java +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLBeanValidationTest.java @@ -65,7 +65,8 @@ public void testNonBlocking() { .assertThat() .statusCode(200) .body("errors[0].message", containsString("Message too long")) - .body("errors[0].path", hasItems("nonBlocking", "input")) + .body("errors[0].path", hasItems("nonBlocking")) + .body("errors[0].extensions.violations[0].propertyPath", hasItems("nonBlocking", "input")) .body("data.nonBlocking", nullValue()); } @@ -81,7 +82,8 @@ public void testBlocking() { .assertThat() .statusCode(200) .body("errors[0].message", containsString("Message too long")) - .body("errors[0].path", hasItems("blocking", "input")) + .body("errors[0].path", hasItems("blocking")) + .body("errors[0].extensions.violations[0].propertyPath", hasItems("blocking", "input")) .body("data.blocking", nullValue()); } @@ -97,7 +99,8 @@ public void testUniNonBlocking() { .assertThat() .statusCode(200) .body("errors[0].message", containsString("Message too long")) - .body("errors[0].path", hasItems("uniNonBlocking", "input")) + .body("errors[0].path", hasItems("uniNonBlocking")) + .body("errors[0].extensions.violations[0].propertyPath", hasItems("uniNonBlocking", "input")) .body("data.uniNonBlocking", nullValue()); } @@ -113,7 +116,8 @@ public void testUniBlocking() { .assertThat() .statusCode(200) .body("errors[0].message", containsString("Message too long")) - .body("errors[0].path", hasItems("uniBlocking", "input")) + .body("errors[0].path", hasItems("uniBlocking")) + .body("errors[0].extensions.violations[0].propertyPath", hasItems("uniBlocking", "input")) .body("data.uniBlocking", nullValue()); } From 1578da47452216b046b89a46900e876821876edd Mon Sep 17 00:00:00 2001 From: Marek Skacelik Date: Wed, 2 Oct 2024 10:05:02 +0200 Subject: [PATCH 7/8] Added factory services for dynamic client (GraphQL) --- .../SmallRyeGraphQLClientProcessor.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java index b7cd32fa124a6..012944bdad91f 100644 --- a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java +++ b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java @@ -74,23 +74,23 @@ void setupServiceProviders(BuildProducer services) { .allProvidersFromClassPath("io.smallrye.graphql.client.typesafe.api.TypesafeGraphQLClientBuilder")); services.produce(ServiceProviderBuildItem .allProvidersFromClassPath("io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClientBuilder")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Argument")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Directive")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.ArgumentFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DirectiveFactory")); services.produce( - ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.DirectiveArgument")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Document")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Enum")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Field")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Fragment")); + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DirectiveArgumentFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DocumentFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.EnumFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FieldFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FragmentFactory")); services.produce( - ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.FragmentReference")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.InlineFragment")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.InputObject")); + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FragmentReferenceFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InlineFragmentFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InputObjectFactory")); services.produce( - ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.InputObjectField")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Operation")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.Variable")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.VariableType")); + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InputObjectFieldFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.OperationFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.VariableFactory")); + services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.VariableTypeFactory")); } @BuildStep From 3375bb219d337088dbaaab1297d687cdbd11bdbe Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Mon, 14 Oct 2024 11:16:30 +0200 Subject: [PATCH 8/8] Docs and formatting fixes, deprecate old properties --- .../main/asciidoc/tls-registry-reference.adoc | 17 ++++-- .../SmallRyeGraphQLClientProcessor.java | 42 +++++++++----- .../deployment/ssl/SSLTestingTools.java | 3 +- ...raphQLClientReloadKeystoreDefaultTest.java | 55 ++++++++++--------- ...pesafeGraphQLClientReloadKeystoreTest.java | 23 ++++---- ...LClientCertificateUpdateEventListener.java | 15 +++-- .../client/runtime/GraphQLClientConfig.java | 12 ++-- .../SmallRyeGraphQLClientRecorder.java | 8 ++- 8 files changed, 105 insertions(+), 70 deletions(-) diff --git a/docs/src/main/asciidoc/tls-registry-reference.adoc b/docs/src/main/asciidoc/tls-registry-reference.adoc index b566976b92ced..4024783fe2e8a 100644 --- a/docs/src/main/asciidoc/tls-registry-reference.adoc +++ b/docs/src/main/asciidoc/tls-registry-reference.adoc @@ -26,7 +26,7 @@ ifndef::no-reactive-routes[] , or Reactive Routes endif::no-reactive-routes[] . -The TLS Registry extension is automatically included in your project when you use compatible extensions, such as Quarkus REST, gRPC, SmallRye GraphQL Client, or Reactive Routes. + As a result, applications that use the TLS Registry can be ready to handle secure communications out of the box. TLS Registry also provides features like automatic certificate reloading, Let's Encrypt (ACME) integration, Kubernetes Cert-Manager support, and compatibility with various keystore formats, such as PKCS12, PEM, and JKS. @@ -155,9 +155,18 @@ quarkus.grpc.clients.hello.tls-configuration-name=MY_TLS_CONFIGURATION ---- quarkus.smallrye-graphql-client.my-client.tls-configuration-name=MY_TLS_CONFIGURATION ---- -> [NOTE] -> When using the Typesafe GraphQL client with a certificate reloading mechanism (see <>), it is essential to override the bean's scope to `RequestScoped` (or another similar scope). By default, the Typesafe client is an application-scoped bean. -> This guarantees that each new instance of the bean created after a certificate reload will be configured with the latest certificate. + +[NOTE] +==== +When using the Typesafe GraphQL client with a certificate +reloading mechanism (see <>), it is essential to +override the bean's scope to `RequestScoped` (or another similar scope +shorter than application). This is because by default, the Typesafe client is an +application-scoped bean, so shortening the scope guarantees that new instances of the bean +created after a certificate reload will be configured with the latest +certificate. Dynamic clients are `@Dependent` scoped, so you should +inject them into components with an appropriate scope. +==== == Configuring TLS diff --git a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java index 012944bdad91f..59f6cc99488eb 100644 --- a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java +++ b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java @@ -74,23 +74,37 @@ void setupServiceProviders(BuildProducer services) { .allProvidersFromClassPath("io.smallrye.graphql.client.typesafe.api.TypesafeGraphQLClientBuilder")); services.produce(ServiceProviderBuildItem .allProvidersFromClassPath("io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClientBuilder")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.ArgumentFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DirectiveFactory")); services.produce( - ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DirectiveArgumentFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DocumentFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.EnumFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FieldFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FragmentFactory")); + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.ArgumentFactory")); services.produce( - ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FragmentReferenceFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InlineFragmentFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InputObjectFactory")); + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DirectiveFactory")); services.produce( - ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InputObjectFieldFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.OperationFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.VariableFactory")); - services.produce(ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.VariableTypeFactory")); + ServiceProviderBuildItem + .allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DirectiveArgumentFactory")); + services.produce( + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.DocumentFactory")); + services.produce( + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.EnumFactory")); + services.produce( + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FieldFactory")); + services.produce( + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FragmentFactory")); + services.produce( + ServiceProviderBuildItem + .allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.FragmentReferenceFactory")); + services.produce(ServiceProviderBuildItem + .allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InlineFragmentFactory")); + services.produce(ServiceProviderBuildItem + .allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InputObjectFactory")); + services.produce( + ServiceProviderBuildItem + .allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.InputObjectFieldFactory")); + services.produce( + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.OperationFactory")); + services.produce( + ServiceProviderBuildItem.allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.VariableFactory")); + services.produce(ServiceProviderBuildItem + .allProvidersFromClassPath("io.smallrye.graphql.client.core.factory.VariableTypeFactory")); } @BuildStep diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java index 99dac5dfeeb36..90f391bdec326 100644 --- a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/SSLTestingTools.java @@ -10,7 +10,6 @@ import io.vertx.core.http.ClientAuth; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; -import io.vertx.core.net.JksOptions; import io.vertx.core.net.PfxOptions; public class SSLTestingTools { @@ -54,6 +53,6 @@ public HttpServer runServer(String keystorePath, String keystorePassword, } public void close() { - vertx.close(); + vertx.close().toCompletionStage().toCompletableFuture().join(); } } diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java index e92806f8a3d8a..231989ecced25 100644 --- a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreDefaultTest.java @@ -1,20 +1,16 @@ package io.quarkus.smallrye.graphql.client.deployment.ssl; -import io.quarkus.arc.Arc; -import io.quarkus.test.QuarkusUnitTest; -import io.quarkus.tls.CertificateUpdatedEvent; -import io.quarkus.tls.TlsConfiguration; -import io.quarkus.tls.TlsConfigurationRegistry; -import io.smallrye.certs.Format; -import io.smallrye.certs.junit5.Certificate; -import io.smallrye.certs.junit5.Certificates; -import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; -import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; -import io.vertx.core.http.HttpServer; -import io.vertx.core.net.KeyCertOptions; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.UUID; + import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.event.Event; import jakarta.inject.Inject; + import org.assertj.core.api.Assertions; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.graphql.Query; @@ -26,12 +22,18 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; +import io.quarkus.arc.Arc; +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.tls.CertificateUpdatedEvent; +import io.quarkus.tls.TlsConfiguration; +import io.quarkus.tls.TlsConfigurationRegistry; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; +import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; +import io.vertx.core.http.HttpServer; +import io.vertx.core.net.KeyCertOptions; @Certificates(baseDir = "target/certs", certificates = { @Certificate(name = "wrong-test-reload", password = "password", formats = Format.PKCS12, client = true), @@ -47,11 +49,8 @@ public class TypesafeGraphQLClientReloadKeystoreDefaultTest { private static final File temp = new File("target/test-certificates-" + UUID.randomUUID()); private static final String CONFIGURATION = """ - quarkus.tls.key-store.p12.path=%s - quarkus.tls.key-store.p12.password=password - quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ - quarkus.tls.trust-all=true - """.formatted(temp.getAbsolutePath() + "/tls.p12", PORT); + # No config - overridden in the test + """; @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -60,6 +59,10 @@ public class TypesafeGraphQLClientReloadKeystoreDefaultTest { .add(new StringAsset(CONFIGURATION), "application.properties") .addClasses(MyApi.class, SSLTestingTools.class)) .overrideRuntimeConfigKey("loc", temp.getAbsolutePath()) + .overrideRuntimeConfigKey("quarkus.tls.key-store.p12.path", temp.getAbsolutePath() + "/tls.p12") + .overrideRuntimeConfigKey("quarkus.tls.key-store.p12.password", "password") + .overrideRuntimeConfigKey("quarkus.smallrye-graphql-client.my-client.url", "https://127.0.0.1:" + PORT) + .overrideRuntimeConfigKey("quarkus.tls.trust-all", "true") .setBeforeAllCustomizer(() -> { try { temp.mkdirs(); @@ -99,7 +102,8 @@ static void setupServer() throws Exception { @Test void testReloading() throws IOException { TlsConfiguration def = registry.getDefault().orElseThrow(); - KeyCertOptions keystoreOptionsBefore = (KeyCertOptions) GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions(); + KeyCertOptions keystoreOptionsBefore = (KeyCertOptions) GraphQLClientsConfiguration.getInstance().getClient("my-client") + .getTlsKeyStoreOptions(); Arc.container().requestContext().activate(); try { myApi.getResult(); @@ -116,7 +120,8 @@ void testReloading() throws IOException { event.fire(new CertificateUpdatedEvent("", def)); Arc.container().requestContext().activate(); try { - assertThat(GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions()).isNotEqualTo(keystoreOptionsBefore); + assertThat(GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions()) + .isNotEqualTo(keystoreOptionsBefore); assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); } finally { Arc.container().requestContext().terminate(); diff --git a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java index b64b69fac0a40..8b479b6b6d534 100644 --- a/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java +++ b/extensions/smallrye-graphql-client/deployment/src/test/java/io/quarkus/smallrye/graphql/client/deployment/ssl/TypesafeGraphQLClientReloadKeystoreTest.java @@ -7,8 +7,6 @@ import java.nio.file.Files; import java.util.UUID; -import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; -import io.vertx.core.net.KeyCertOptions; import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.event.Event; import jakarta.inject.Inject; @@ -32,8 +30,10 @@ import io.smallrye.certs.Format; import io.smallrye.certs.junit5.Certificate; import io.smallrye.certs.junit5.Certificates; +import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; import io.vertx.core.http.HttpServer; +import io.vertx.core.net.KeyCertOptions; @Certificates(baseDir = "target/certs", certificates = { @Certificate(name = "wrong-test-reload", password = "password", formats = Format.PKCS12, client = true), @@ -49,12 +49,8 @@ public class TypesafeGraphQLClientReloadKeystoreTest { private static final File temp = new File("target/test-certificates-" + UUID.randomUUID()); private static final String CONFIGURATION = """ - quarkus.smallrye-graphql-client.my-client.tls-configuration-name=my-tls-client - quarkus.tls.my-tls-client.key-store.p12.path=%s - quarkus.tls.my-tls-client.key-store.p12.password=password - quarkus.smallrye-graphql-client.my-client.url=https://127.0.0.1:%d/ - quarkus.tls.my-tls-client.trust-all=true - """.formatted(temp.getAbsolutePath() + "/tls.p12", PORT); + # No config - overridden in the test + """; @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -63,6 +59,11 @@ public class TypesafeGraphQLClientReloadKeystoreTest { .add(new StringAsset(CONFIGURATION), "application.properties") .addClasses(MyApi.class, SSLTestingTools.class)) .overrideRuntimeConfigKey("loc", temp.getAbsolutePath()) + .overrideRuntimeConfigKey("quarkus.smallrye-graphql-client.my-client.tls-configuration-name", "my-tls-client") + .overrideRuntimeConfigKey("quarkus.tls.my-tls-client.key-store.p12.path", temp.getAbsolutePath() + "/tls.p12") + .overrideRuntimeConfigKey("quarkus.tls.my-tls-client.key-store.p12.password", "password") + .overrideRuntimeConfigKey("quarkus.smallrye-graphql-client.my-client.url", "https://127.0.0.1:" + PORT) + .overrideRuntimeConfigKey("quarkus.tls.my-tls-client.trust-all", "true") .setBeforeAllCustomizer(() -> { try { temp.mkdirs(); @@ -102,7 +103,8 @@ static void setupServer() throws Exception { @Test void testReloading() throws IOException { TlsConfiguration tlsClient = registry.get("my-tls-client").orElseThrow(); - KeyCertOptions keystoreOptionsBefore = (KeyCertOptions) GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions(); + KeyCertOptions keystoreOptionsBefore = (KeyCertOptions) GraphQLClientsConfiguration.getInstance().getClient("my-client") + .getTlsKeyStoreOptions(); Arc.container().requestContext().activate(); try { myApi.getResult(); @@ -119,7 +121,8 @@ void testReloading() throws IOException { event.fire(new CertificateUpdatedEvent("my-tls-client", tlsClient)); Arc.container().requestContext().activate(); try { - assertThat(GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions()).isNotEqualTo(keystoreOptionsBefore); + assertThat(GraphQLClientsConfiguration.getInstance().getClient("my-client").getTlsKeyStoreOptions()) + .isNotEqualTo(keystoreOptionsBefore); assertThat(myApi.getResult()).isEqualTo(EXPECTED_RESPONSE); } finally { Arc.container().requestContext().terminate(); diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java index 201d56054af22..5d0b5b0aeff43 100644 --- a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java +++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientCertificateUpdateEventListener.java @@ -1,6 +1,7 @@ package io.quarkus.smallrye.graphql.client.runtime; -import io.smallrye.graphql.client.impl.GraphQLClientConfiguration; +import static io.quarkus.tls.runtime.config.TlsConfig.DEFAULT_NAME; + import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -9,10 +10,9 @@ import io.quarkus.tls.CertificateUpdatedEvent; import io.quarkus.tls.TlsConfiguration; +import io.smallrye.graphql.client.impl.GraphQLClientConfiguration; import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; -import static io.quarkus.tls.runtime.config.TlsConfig.DEFAULT_NAME; - @Singleton public class GraphQLClientCertificateUpdateEventListener { @@ -26,10 +26,12 @@ public void onCertificateUpdate(@Observes CertificateUpdatedEvent event) { TlsConfiguration updatedTlsConfiguration = event.tlsConfiguration(); graphQLClientsConfig.clients .forEach((configKey, clientConfig) -> { - GraphQLClientConfiguration graphQLClientConfiguration = GraphQLClientsConfiguration.getInstance().getClient(configKey); + GraphQLClientConfiguration graphQLClientConfiguration = GraphQLClientsConfiguration.getInstance() + .getClient(configKey); clientConfig.tlsConfigurationName.ifPresentOrElse(tlsConfigurationName -> { if (tlsConfigurationName.equals(updatedTlsConfigurationName)) { - updateConfiguration(updatedTlsConfigurationName, updatedTlsConfiguration, graphQLClientConfiguration, configKey); + updateConfiguration(updatedTlsConfigurationName, updatedTlsConfiguration, + graphQLClientConfiguration, configKey); } }, () -> { if (DEFAULT_NAME.equals(updatedTlsConfigurationName)) { @@ -39,7 +41,8 @@ public void onCertificateUpdate(@Observes CertificateUpdatedEvent event) { }); } - private void updateConfiguration(String tlsBucketName, TlsConfiguration updatedTlsConfiguration, GraphQLClientConfiguration graphQLClientConfiguration, String configKey) { + private void updateConfiguration(String tlsBucketName, TlsConfiguration updatedTlsConfiguration, + GraphQLClientConfiguration graphQLClientConfiguration, String configKey) { LOG.infof("Certificate reloaded for the client '%s' using the TLS configuration (bucket) name '%s'", configKey, tlsBucketName); graphQLClientConfiguration diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java index b5286242cee6b..3bd6c3e1fad03 100644 --- a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java +++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfig.java @@ -58,7 +58,7 @@ public class GraphQLClientConfig { * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem - @Deprecated + @Deprecated(forRemoval = true, since = "3.16.0") public Optional trustStore; /** @@ -69,7 +69,7 @@ public class GraphQLClientConfig { * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem - @Deprecated + @Deprecated(forRemoval = true, since = "3.16.0") public Optional trustStorePassword; /** @@ -80,7 +80,7 @@ public class GraphQLClientConfig { * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem - @Deprecated + @Deprecated(forRemoval = true, since = "3.16.0") public Optional trustStoreType; /** @@ -91,7 +91,7 @@ public class GraphQLClientConfig { * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem - @Deprecated + @Deprecated(forRemoval = true, since = "3.16.0") public Optional keyStore; /** @@ -102,7 +102,7 @@ public class GraphQLClientConfig { * {@code quarkus.smallrye-graphql-client."client-name".tls-bucket-name}. */ @ConfigItem - @Deprecated + @Deprecated(forRemoval = true, since = "3.16.0") public Optional keyStorePassword; /** @@ -114,7 +114,7 @@ public class GraphQLClientConfig { * */ @ConfigItem - @Deprecated + @Deprecated(forRemoval = true, since = "3.16.0") public Optional keyStoreType; /** diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java index f4c1294f7fba1..91f3a9aff73c6 100644 --- a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java +++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/SmallRyeGraphQLClientRecorder.java @@ -127,7 +127,8 @@ private GraphQLClientConfiguration toSmallRyeNativeConfiguration(GraphQLClientCo transformed.setTlsKeyStoreOptions(tlsConfiguration.getKeyStoreOptions()); transformed.setTlsTrustStoreOptions(tlsConfiguration.getTrustStoreOptions()); transformed.setSslOptions(tlsConfiguration.getSSLOptions()); - tlsConfiguration.getHostnameVerificationAlgorithm().ifPresent(transformed::setHostnameVerificationAlgorithm); + tlsConfiguration.getHostnameVerificationAlgorithm() + .ifPresent(transformed::setHostnameVerificationAlgorithm); transformed.setUsesSni(Boolean.valueOf(tlsConfiguration.usesSni())); }, () -> { // DEPRECATED @@ -166,8 +167,9 @@ private Optional resolveTlsConfigurationForRegistry(GraphQLCli if (Arc.container() != null) { TlsConfigurationRegistry tlsConfigurationRegistry = Arc.container().select(TlsConfigurationRegistry.class).orNull(); if (tlsConfigurationRegistry != null) { - if (tlsConfigurationRegistry.getDefault().isPresent() && (tlsConfigurationRegistry.getDefault().get().getTrustStoreOptions() != null - || tlsConfigurationRegistry.getDefault().get().isTrustAll())) { + if (tlsConfigurationRegistry.getDefault().isPresent() + && (tlsConfigurationRegistry.getDefault().get().getTrustStoreOptions() != null + || tlsConfigurationRegistry.getDefault().get().isTrustAll())) { return tlsConfigurationRegistry.getDefault(); } return TlsConfiguration.from(tlsConfigurationRegistry, quarkusConfig.tlsConfigurationName);