From c2a088f1d671f48d23ab52423b6c34fb18c5969a Mon Sep 17 00:00:00 2001 From: James Netherton Date: Wed, 5 Jun 2024 14:06:31 +0100 Subject: [PATCH] Add missing HTTP client dependency to azure-key-vault extension Fixes #6157 --- .../azure-key-vault/deployment/pom.xml | 4 + .../azure-key-vault/runtime/pom.xml | 16 +--- integration-tests-jvm/azure-key-vault/pom.xml | 22 +++++ .../key/vault/it/AzureKeyVaultResource.java | 59 +++++++++--- .../key/vault/it/AzureKeyVaultRoutes.java | 58 ++++++++++++ .../src/main/resources/application.properties | 21 +++++ .../azure/key/vault/it/AzureKeyVaultTest.java | 94 +++++++++++++++++-- 7 files changed, 241 insertions(+), 33 deletions(-) create mode 100644 integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultRoutes.java create mode 100644 integration-tests-jvm/azure-key-vault/src/main/resources/application.properties diff --git a/extensions-jvm/azure-key-vault/deployment/pom.xml b/extensions-jvm/azure-key-vault/deployment/pom.xml index e7d4d0d4fc19..a3642a7ecf18 100644 --- a/extensions-jvm/azure-key-vault/deployment/pom.xml +++ b/extensions-jvm/azure-key-vault/deployment/pom.xml @@ -34,6 +34,10 @@ org.apache.camel.quarkus camel-quarkus-core-deployment + + org.apache.camel.quarkus + camel-quarkus-support-azure-core-http-client-vertx-deployment + org.apache.camel.quarkus camel-quarkus-azure-key-vault diff --git a/extensions-jvm/azure-key-vault/runtime/pom.xml b/extensions-jvm/azure-key-vault/runtime/pom.xml index ebc1a7b4b0f8..6279f65c2e46 100644 --- a/extensions-jvm/azure-key-vault/runtime/pom.xml +++ b/extensions-jvm/azure-key-vault/runtime/pom.xml @@ -40,20 +40,12 @@ camel-quarkus-core - org.apache.camel - camel-azure-key-vault - - - reactor-core - io.projectreactor - - + org.apache.camel.quarkus + camel-quarkus-support-azure-core-http-client-vertx - - - reactor-core - io.projectreactor + org.apache.camel + camel-azure-key-vault diff --git a/integration-tests-jvm/azure-key-vault/pom.xml b/integration-tests-jvm/azure-key-vault/pom.xml index ec34faf50f00..970b2fc7891f 100644 --- a/integration-tests-jvm/azure-key-vault/pom.xml +++ b/integration-tests-jvm/azure-key-vault/pom.xml @@ -54,6 +54,10 @@ org.apache.camel.quarkus camel-quarkus-azure-key-vault + + org.apache.camel.quarkus + camel-quarkus-direct + io.quarkus quarkus-resteasy @@ -70,6 +74,11 @@ rest-assured test + + org.apache.camel.quarkus + camel-quarkus-integration-tests-support-azure + test + @@ -95,6 +104,19 @@ + + org.apache.camel.quarkus + camel-quarkus-direct-deployment + ${project.version} + pom + test + + + * + * + + + diff --git a/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java b/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java index c2687569cb4d..3251da5c43ec 100644 --- a/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java +++ b/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultResource.java @@ -16,35 +16,64 @@ */ package org.apache.camel.quarkus.component.azure.key.vault.it; +import com.azure.security.keyvault.secrets.models.KeyVaultSecret; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import org.apache.camel.CamelContext; -import org.jboss.logging.Logger; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.azure.key.vault.KeyVaultConstants; @Path("/azure-key-vault") @ApplicationScoped public class AzureKeyVaultResource { - - private static final Logger LOG = Logger.getLogger(AzureKeyVaultResource.class); - - private static final String COMPONENT_AZURE_KEY_VAULT = "azure-key-vault"; @Inject - CamelContext context; + ProducerTemplate producerTemplate; + + @Path("/secret/{secretName}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public Response createSecret(@PathParam("secretName") String secretName, String secret) { + KeyVaultSecret result = producerTemplate.requestBodyAndHeader("direct:createSecret", secret, + KeyVaultConstants.SECRET_NAME, secretName, KeyVaultSecret.class); + return Response.ok(result.getName()).build(); + } - @Path("/load/component/azure-key-vault") + @Path("/secret/{secretName}") @GET @Produces(MediaType.TEXT_PLAIN) - public Response loadComponentAzureKeyVault() throws Exception { - /* This is an autogenerated test */ - if (context.getComponent(COMPONENT_AZURE_KEY_VAULT) != null) { - return Response.ok().build(); - } - LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_AZURE_KEY_VAULT); - return Response.status(500, COMPONENT_AZURE_KEY_VAULT + " could not be loaded from the Camel context").build(); + public String getSecret(@PathParam("secretName") String secretName) { + return producerTemplate.requestBodyAndHeader("direct:getSecret", null, + KeyVaultConstants.SECRET_NAME, secretName, String.class); + } + + @Path("/secret/{secretName}") + @DELETE + public Response deleteSecret(@PathParam("secretName") String secretName) { + producerTemplate.requestBodyAndHeader("direct:deleteSecret", null, + KeyVaultConstants.SECRET_NAME, secretName, Void.class); + return Response.ok().build(); + } + + @Path("/secret/{secretName}/purge") + @DELETE + public Response purgeSecret(@PathParam("secretName") String secretName) { + producerTemplate.requestBodyAndHeader("direct:purgeDeletedSecret", null, + KeyVaultConstants.SECRET_NAME, secretName, Void.class); + return Response.ok().build(); + } + + @Path("/secret/from/placeholder") + @GET + public String getSecretFromPropertyPlaceholder() { + return producerTemplate.requestBody("direct:propertyPlaceholder", null, String.class); } } diff --git a/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultRoutes.java b/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultRoutes.java new file mode 100644 index 000000000000..a29c9a07f346 --- /dev/null +++ b/integration-tests-jvm/azure-key-vault/src/main/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultRoutes.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.azure.key.vault.it; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.PropertiesComponent; + +public class AzureKeyVaultRoutes extends RouteBuilder { + @Override + public void configure() throws Exception { + from("direct:createSecret") + .to(azureKeyVault("createSecret")); + + from("direct:getSecret") + .to(azureKeyVault("getSecret")); + + from("direct:deleteSecret") + .to(azureKeyVault("deleteSecret")); + + from("direct:purgeDeletedSecret") + .to(azureKeyVault("purgeDeletedSecret")); + + from("direct:propertyPlaceholder") + .process(new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + Message message = exchange.getMessage(); + PropertiesComponent component = exchange.getContext().getPropertiesComponent(); + component.resolveProperty("azure:camel-quarkus-secret").ifPresent(message::setBody); + } + }); + } + + private String azureKeyVault(String operation) { + return "azure-key-vault://{{camel.vault.azure.vaultName}}" + + "?clientId=RAW({{camel.vault.azure.clientId}})" + + "&clientSecret=RAW({{camel.vault.azure.clientSecret}})" + + "&tenantId=RAW({{camel.vault.azure.tenantId}})" + + "&operation=" + operation; + } +} diff --git a/integration-tests-jvm/azure-key-vault/src/main/resources/application.properties b/integration-tests-jvm/azure-key-vault/src/main/resources/application.properties new file mode 100644 index 000000000000..251f65d06e4c --- /dev/null +++ b/integration-tests-jvm/azure-key-vault/src/main/resources/application.properties @@ -0,0 +1,21 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# +camel.vault.azure.tenantId = ${AZURE_TENANT_ID} +camel.vault.azure.clientId = ${AZURE_CLIENT_ID} +camel.vault.azure.clientSecret = ${AZURE_CLIENT_SECRET} +camel.vault.azure.vaultName = ${AZURE_VAULT_NAME:cq-vault-testing} \ No newline at end of file diff --git a/integration-tests-jvm/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java b/integration-tests-jvm/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java index d20f8bc47f31..74c243146634 100644 --- a/integration-tests-jvm/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java +++ b/integration-tests-jvm/azure-key-vault/src/test/java/org/apache/camel/quarkus/component/azure/key/vault/it/AzureKeyVaultTest.java @@ -16,19 +16,101 @@ */ package org.apache.camel.quarkus.component.azure.key.vault.it; +import java.util.UUID; + import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; + +import static org.hamcrest.Matchers.is; +// Azure Key Vault is not supported by Azurite https://github.com/Azure/Azurite/issues/619 +@EnabledIfEnvironmentVariable(named = "AZURE_TENANT_ID", matches = ".+") +@EnabledIfEnvironmentVariable(named = "AZURE_CLIENT_ID", matches = ".+") +@EnabledIfEnvironmentVariable(named = "AZURE_CLIENT_SECRET", matches = ".+") +@EnabledIfEnvironmentVariable(named = "AZURE_VAULT_NAME", matches = ".+") @QuarkusTest class AzureKeyVaultTest { - @Test - public void loadComponentAzureKeyVault() { - /* A simple autogenerated test */ - RestAssured.get("/azure-key-vault/load/component/azure-key-vault") - .then() - .statusCode(200); + void secretCreateRetrieveDeletePurge() { + String secretName = UUID.randomUUID().toString(); + String secret = "Hello Camel Quarkus Azure Key Vault"; + + try { + // Create secret + RestAssured.given() + .body(secret) + .post("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(200) + .body(is(secretName)); + + // Retrieve secret + RestAssured.given() + .get("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(200) + .body(is(secret)); + } finally { + // Delete secret + RestAssured.given() + .delete("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(200); + + // Purge secret + RestAssured.given() + .delete("/azure-key-vault/secret/{secretName}/purge", secretName) + .then() + .statusCode(200); + + // Confirm deletion + RestAssured.given() + .get("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(500); + } } + @Test + void propertyPlaceholder() { + String secretName = "camel-quarkus-secret"; + String secret = "Hello Camel Quarkus Azure Key Vault From Property Placeholder"; + + try { + // Create secret + RestAssured.given() + .body(secret) + .post("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(200) + .body(is(secretName)); + + // Retrieve secret + RestAssured.given() + .get("/azure-key-vault/secret/from/placeholder") + .then() + .statusCode(200) + .body(is(secret)); + } finally { + // Delete secret + RestAssured.given() + .delete("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(200); + + // Purge secret + RestAssured.given() + .delete("/azure-key-vault/secret/{secretName}/purge", secretName) + .then() + .statusCode(200); + + // Confirm deletion + RestAssured.given() + .get("/azure-key-vault/secret/{secretName}", secretName) + .then() + .statusCode(500); + } + } }