This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new b40c2e3c5b33 CAMEL-26617: camel-azure-key-vault - run the integration
tests on Floci AZ (#29237)
b40c2e3c5b33 is described below
commit b40c2e3c5b3356563f4edd6ea26df3f2a0864a15
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Nov 5 16:50:26 2026 +0100
CAMEL-26617: camel-azure-key-vault - run the integration tests on Floci AZ
(#29237)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---
.../apache/camel/catalog/test-infra/metadata.json | 11 ++
.../camel-azure/camel-azure-key-vault/pom.xml | 9 ++
.../operations/KeyVaultOperationsIT.java | 168 +++++++++++++++++++++
.../operations/KeyVaultOperationsTest.java | 110 --------------
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 8 -
test-infra/camel-test-infra-all/pom.xml | 11 ++
.../src/generated/resources/META-INF/metadata.json | 11 ++
.../camel-test-infra-azure-key-vault}/pom.xml | 64 +++-----
.../azure/key/vault/AzureKeyVaultConfigs.java | 33 ++++
.../vault/clients/AzureKeyVaultClientUtils.java | 97 ++++++++++++
.../vault/services/AzureKeyVaultInfraService.java | 37 +++++
.../AzureKeyVaultLocalContainerInfraService.java | 46 ++++++
.../services/AzureKeyVaultRemoteInfraService.java | 51 +++++++
.../key/vault/services/AzureKeyVaultService.java | 27 ++++
.../services/AzureKeyVaultServiceFactory.java | 83 ++++++++++
.../src/main/resources/META-INF/MANIFEST.MF | 0
test-infra/pom.xml | 1 +
17 files changed, 606 insertions(+), 161 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
index aced56b21e4f..e1f97d5309cd 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
@@ -284,6 +284,17 @@
"version" : "4.24.0-SNAPSHOT",
"serviceVersion" : "2026.5",
"uiSupported" : false
+}, {
+ "service" :
"org.apache.camel.test.infra.azure.key.vault.services.AzureKeyVaultInfraService",
+ "description" : "Local Azure Key Vault service with Floci AZ",
+ "implementation" :
"org.apache.camel.test.infra.azure.key.vault.services.AzureKeyVaultLocalContainerInfraService",
+ "alias" : [ "azure" ],
+ "aliasImplementation" : [ "key-vault" ],
+ "groupId" : "org.apache.camel",
+ "artifactId" : "camel-test-infra-azure-key-vault",
+ "version" : "4.24.0-SNAPSHOT",
+ "serviceVersion" : "0.16.0",
+ "uiSupported" : false
}, {
"service" :
"org.apache.camel.test.infra.openfga.services.OpenFgaInfraService",
"description" : "OpenFGA, a relationship-based fine-grained authorization
engine",
diff --git a/components/camel-azure/camel-azure-key-vault/pom.xml
b/components/camel-azure/camel-azure-key-vault/pom.xml
index cfcc9d852c0e..75418fd39b16 100644
--- a/components/camel-azure/camel-azure-key-vault/pom.xml
+++ b/components/camel-azure/camel-azure-key-vault/pom.xml
@@ -33,6 +33,9 @@
<description>Camel Azure Key Vault Component</description>
<properties>
+ <!-- Floci AZ is not available on these platforms -->
+ <skipITs.ppc64le>true</skipITs.ppc64le>
+ <skipITs.s390x>true</skipITs.s390x>
</properties>
<dependencies>
@@ -80,5 +83,11 @@
<artifactId>camel-test-junit6</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-infra-azure-key-vault</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/components/camel-azure/camel-azure-key-vault/src/test/java/org/apache/camel/component/azure/key/vault/integration/operations/KeyVaultOperationsIT.java
b/components/camel-azure/camel-azure-key-vault/src/test/java/org/apache/camel/component/azure/key/vault/integration/operations/KeyVaultOperationsIT.java
new file mode 100644
index 000000000000..0cbaa03aa4b9
--- /dev/null
+++
b/components/camel-azure/camel-azure-key-vault/src/test/java/org/apache/camel/component/azure/key/vault/integration/operations/KeyVaultOperationsIT.java
@@ -0,0 +1,168 @@
+/*
+ * 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.component.azure.key.vault.integration.operations;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import com.azure.core.exception.HttpResponseException;
+import com.azure.security.keyvault.secrets.SecretClient;
+import com.azure.security.keyvault.secrets.models.DeletedSecret;
+import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
+import com.azure.security.keyvault.secrets.models.SecretProperties;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.azure.key.vault.KeyVaultConstants;
+import org.apache.camel.test.infra.azure.key.vault.AzureKeyVaultConfigs;
+import
org.apache.camel.test.infra.azure.key.vault.clients.AzureKeyVaultClientUtils;
+import
org.apache.camel.test.infra.azure.key.vault.services.AzureKeyVaultService;
+import
org.apache.camel.test.infra.azure.key.vault.services.AzureKeyVaultServiceFactory;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * The operations of the producer against the Key Vault of a Floci AZ
container, or against a real vault when its name
+ * and a service principal are given:
+ * {@code mvn verify -DvaultName=myvault -DclientId=... -DclientSecret=...
-DtenantId=...}. The test purges the secret
+ * that it deletes: the real vault must not have purge protection, and the
service principal must be allowed to purge.
+ */
+class KeyVaultOperationsIT extends CamelTestSupport {
+
+ @RegisterExtension
+ static AzureKeyVaultService service = createService();
+
+ // a name of its own: a real vault keeps a deleted secret for days, and
refuses to create another one with its name
+ private final String secretName = "camel-it-" + UUID.randomUUID();
+
+ private SecretClient secretClient;
+
+ private static AzureKeyVaultService createService() {
+ if (isSet(AzureKeyVaultConfigs.VAULT_NAME) &&
isSet(AzureKeyVaultConfigs.CLIENT_ID)
+ && isSet(AzureKeyVaultConfigs.CLIENT_SECRET) &&
isSet(AzureKeyVaultConfigs.TENANT_ID)) {
+ System.setProperty("azure.instance.type", "remote");
+ }
+ return AzureKeyVaultServiceFactory.createService();
+ }
+
+ private static boolean isSet(String property) {
+ String value = System.getProperty(property);
+ return value != null && !value.isBlank();
+ }
+
+ private static boolean isRemote() {
+ return "remote".equals(System.getProperty("azure.instance.type"));
+ }
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+ secretClient = AzureKeyVaultClientUtils.getClient();
+ // on a real vault the endpoints build their client from the service
principal: a client in the registry would
+ // be autowired in its place
+ if (!isRemote()) {
+ context.getRegistry().bind("secretClient", secretClient);
+ }
+ return context;
+ }
+
+ @Test
+ void createGetUpdateDeleteAndPurgeSecret() {
+ Exchange created = template.send("direct:createSecret", exchange -> {
+ exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME,
secretName);
+ exchange.getMessage().setBody("TestValue");
+ });
+ assertNull(created.getException());
+ KeyVaultSecret secret = assertInstanceOf(KeyVaultSecret.class,
created.getMessage().getBody());
+ assertEquals(secretName, secret.getName());
+ assertEquals("TestValue", secret.getValue());
+
+ Exchange read = template.send("direct:getSecret",
+ exchange ->
exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME, secretName));
+ assertNull(read.getException());
+ assertEquals("TestValue", read.getMessage().getBody());
+
+ SecretProperties properties = secret.getProperties()
+ .setContentType("text/plain")
+ .setTags(Map.of("owner", "camel"));
+ Exchange updated = template.send("direct:updateSecretProperties",
+ exchange ->
exchange.getMessage().setHeader(KeyVaultConstants.SECRET_PROPERTIES,
properties));
+ assertNull(updated.getException());
+ SecretProperties updatedProperties =
assertInstanceOf(SecretProperties.class, updated.getMessage().getBody());
+ assertEquals(secretName, updatedProperties.getName());
+ assertEquals("text/plain", updatedProperties.getContentType());
+ assertEquals(Map.of("owner", "camel"), updatedProperties.getTags());
+
+ Exchange deleted = template.send("direct:deleteSecret",
+ exchange ->
exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME, secretName));
+ assertNull(deleted.getException());
+ DeletedSecret deletedSecret = assertInstanceOf(DeletedSecret.class,
deleted.getMessage().getBody());
+ assertEquals(secretName, deletedSecret.getName());
+ assertNotNull(deletedSecret.getRecoveryId());
+ assertNotNull(deletedSecret.getDeletedOn());
+ assertNotNull(deletedSecret.getScheduledPurgeDate());
+
+ Exchange missing = template.send("direct:getSecret",
+ exchange ->
exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME, secretName));
+ assertEquals(404,
+ assertInstanceOf(HttpResponseException.class,
missing.getException()).getResponse().getStatusCode());
+
+ Exchange purged = template.send("direct:purgeDeletedSecret",
+ exchange ->
exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME, secretName));
+ assertNull(purged.getException());
+ // a real vault purges the deleted secret in the background
+ await().atMost(1, TimeUnit.MINUTES)
+ .untilAsserted(() -> assertEquals(404,
+ assertThrows(HttpResponseException.class, () ->
secretClient.getDeletedSecret(secretName))
+ .getResponse().getStatusCode()));
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:createSecret").to(keyVault("createSecret"));
+ from("direct:getSecret").to(keyVault("getSecret"));
+
from("direct:updateSecretProperties").to(keyVault("updateSecretProperties"));
+ from("direct:deleteSecret").to(keyVault("deleteSecret"));
+
from("direct:purgeDeletedSecret").to(keyVault("purgeDeletedSecret"));
+ }
+ };
+ }
+
+ /*
+ * On Floci AZ the endpoints use the client of the test-infra, through the
secretClient option: the client that the
+ * component builds reaches only https://<vaultName>.vault.azure.net. On a
real vault they use the service
+ * principal, as before, so that the component builds its client.
+ */
+ private static String keyVault(String operation) {
+ String client = isRemote()
+ ?
"clientId=RAW({{clientId}})&clientSecret=RAW({{clientSecret}})&tenantId=RAW({{tenantId}})"
+ : "secretClient=#secretClient";
+ return "azure-key-vault://" + service.vaultName() + "?" + client +
"&operation=" + operation;
+ }
+}
diff --git
a/components/camel-azure/camel-azure-key-vault/src/test/java/org/apache/camel/component/azure/key/vault/integration/operations/KeyVaultOperationsTest.java
b/components/camel-azure/camel-azure-key-vault/src/test/java/org/apache/camel/component/azure/key/vault/integration/operations/KeyVaultOperationsTest.java
deleted file mode 100644
index e185592247ff..000000000000
---
a/components/camel-azure/camel-azure-key-vault/src/test/java/org/apache/camel/component/azure/key/vault/integration/operations/KeyVaultOperationsTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.component.azure.key.vault.integration.operations;
-
-import org.apache.camel.EndpointInject;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Processor;
-import org.apache.camel.ProducerTemplate;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.azure.key.vault.KeyVaultConstants;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.junit6.CamelTestSupport;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
-
-@EnabledIfSystemProperty(named = "vaultName", matches = ".*",
- disabledReason = "Make sure to supply azure key vault
Vault Name, e.g: mvn verify -DvaultName=string")
-@EnabledIfSystemProperty(named = "clientId", matches = ".*",
- disabledReason = "Make sure to supply azure key vault
Client Id, e.g: mvn verify -DclientId=string")
-@EnabledIfSystemProperty(named = "clientSecret", matches = ".*",
- disabledReason = "Make sure to supply azure key vault
Client Secret, e.g: mvn verify -DclientSecret=string")
-@EnabledIfSystemProperty(named = "tenantId", matches = ".*",
- disabledReason = "Make sure to supply azure key vault
Tenant Id, e.g: mvn verify -DtenantId=string")
-@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-public class KeyVaultOperationsTest extends CamelTestSupport {
-
- @EndpointInject("direct:createSecret")
- private ProducerTemplate template;
-
- @EndpointInject("direct:getSecret")
- private ProducerTemplate getTemplate;
-
- @EndpointInject("direct:deleteSecret")
- private ProducerTemplate deleteTemplate;
-
- @EndpointInject("mock:createSecret")
- private MockEndpoint createResult;
-
- @EndpointInject("mock:getSecret")
- private MockEndpoint getResult;
-
- @EndpointInject("mock:deleteSecret")
- private MockEndpoint deleteResult;
-
- @Test
- public void sendInOnly() throws Exception {
- createResult.expectedMessageCount(1);
- getResult.expectedMessageCount(1);
- getResult.expectedBodiesReceived("TestValue");
- deleteResult.expectedMessageCount(1);
-
- template.send("direct:createSecret", ExchangePattern.InOnly, new
Processor() {
- public void process(Exchange exchange) {
- exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME,
"Test2");
- exchange.getIn().setBody("TestValue");
- }
- });
-
- template.send("direct:getSecret", ExchangePattern.InOnly, new
Processor() {
- public void process(Exchange exchange) {
- exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME,
"Test2");
- }
- });
-
- template.send("direct:deleteSecret", ExchangePattern.InOnly, new
Processor() {
- public void process(Exchange exchange) {
- exchange.getMessage().setHeader(KeyVaultConstants.SECRET_NAME,
"Test2");
- }
- });
-
- MockEndpoint.assertIsSatisfied(context);
- }
-
- @Override
- protected RouteBuilder createRouteBuilder() {
-
- return new RouteBuilder() {
- @Override
- public void configure() {
- from("direct:createSecret")
-
.to("azure-key-vault://{{vaultName}}?clientId=RAW({{clientId}})&clientSecret=RAW({{clientSecret}})&tenantId=RAW({{tenantId}})")
- .to("mock:createSecret");
-
- from("direct:getSecret")
-
.to("azure-key-vault://{{vaultName}}?clientId=RAW({{clientId}})&clientSecret=RAW({{clientSecret}})&tenantId=RAW({{tenantId}})&operation=getSecret")
- .to("mock:getSecret");
-
- from("direct:deleteSecret")
-
.to("azure-key-vault://{{vaultName}}?clientId=RAW({{clientId}})&clientSecret=RAW({{clientSecret}})&tenantId=RAW({{tenantId}})&operation=deleteSecret")
- .to("mock:deleteSecret");
- }
- };
- }
-}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index eb8f5d08a5f7..f4f06187c8a7 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -1379,14 +1379,6 @@ the initial state (`camel.health.initial-state`, DOWN by
default) while the firs
the change feed processor cannot start, with the failure of the last attempt;
before, it was UP. To leave
the check out, as before, set
`camel.health.exclude-pattern=consumer:<routeId>`.
-=== camel-test-infra-azure - the azure.container property holds the Floci AZ
image
-
-The Azure test-infra runs its new local Data Lake Storage Gen2 service (`camel
infra run azure storage-datalake`) on
-https://github.com/floci-io/floci-az[Floci AZ], and the `azure.container`
property of `camel-test-infra-azure-common`
-now holds the Floci AZ image. The Blob and Queue services still run on
Azurite, whose image is now set with the
-`azure.storage.blob.container` and `azure.storage.queue.container` properties:
to run them on another Azurite image,
-set these instead of `azure.container`.
-
=== camel-vertx-websocket - consumers on the same host and port must use the
same SSLContextParameters
All `vertx-websocket` consumers on the same host and port are served by one
HTTP server, which is created from the
diff --git a/test-infra/camel-test-infra-all/pom.xml
b/test-infra/camel-test-infra-all/pom.xml
index 548404b3fb89..950bfdf0a4ef 100644
--- a/test-infra/camel-test-infra-all/pom.xml
+++ b/test-infra/camel-test-infra-all/pom.xml
@@ -71,6 +71,11 @@
<artifactId>camel-test-infra-rabbitmq</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-infra-azure-key-vault</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-infra-azure-storage-blob</artifactId>
@@ -418,6 +423,12 @@
<artifactId>camel-test-infra-rabbitmq</artifactId>
</dependency>
</fileSet>
+ <fileSet>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+
<artifactId>camel-test-infra-azure-key-vault</artifactId>
+ </dependency>
+ </fileSet>
<fileSet>
<dependency>
<groupId>org.apache.camel</groupId>
diff --git
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
index aced56b21e4f..e1f97d5309cd 100644
---
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
+++
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
@@ -284,6 +284,17 @@
"version" : "4.24.0-SNAPSHOT",
"serviceVersion" : "2026.5",
"uiSupported" : false
+}, {
+ "service" :
"org.apache.camel.test.infra.azure.key.vault.services.AzureKeyVaultInfraService",
+ "description" : "Local Azure Key Vault service with Floci AZ",
+ "implementation" :
"org.apache.camel.test.infra.azure.key.vault.services.AzureKeyVaultLocalContainerInfraService",
+ "alias" : [ "azure" ],
+ "aliasImplementation" : [ "key-vault" ],
+ "groupId" : "org.apache.camel",
+ "artifactId" : "camel-test-infra-azure-key-vault",
+ "version" : "4.24.0-SNAPSHOT",
+ "serviceVersion" : "0.16.0",
+ "uiSupported" : false
}, {
"service" :
"org.apache.camel.test.infra.openfga.services.OpenFgaInfraService",
"description" : "OpenFGA, a relationship-based fine-grained authorization
engine",
diff --git a/components/camel-azure/camel-azure-key-vault/pom.xml
b/test-infra/camel-test-infra-azure-key-vault/pom.xml
similarity index 52%
copy from components/camel-azure/camel-azure-key-vault/pom.xml
copy to test-infra/camel-test-infra-azure-key-vault/pom.xml
index cfcc9d852c0e..910a4c81cbbb 100644
--- a/components/camel-azure/camel-azure-key-vault/pom.xml
+++ b/test-infra/camel-test-infra-azure-key-vault/pom.xml
@@ -17,36 +17,35 @@
limitations under the License.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
+ <artifactId>camel-test-infra-parent</artifactId>
<groupId>org.apache.camel</groupId>
- <artifactId>camel-azure-parent</artifactId>
+ <relativePath>../camel-test-infra-parent/pom.xml</relativePath>
<version>4.24.0-SNAPSHOT</version>
</parent>
+ <modelVersion>4.0.0</modelVersion>
- <artifactId>camel-azure-key-vault</artifactId>
- <packaging>jar</packaging>
-
- <name>Camel :: Azure :: Key Vault</name>
- <description>Camel Azure Key Vault Component</description>
-
- <properties>
- </properties>
+ <name>Camel :: Test Infra :: Azure Key Vault</name>
+ <artifactId>camel-test-infra-azure-key-vault</artifactId>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.azure</groupId>
+ <artifactId>azure-sdk-bom</artifactId>
+ <version>${azure-sdk-bom-version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
- <artifactId>camel-azure-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.camel</groupId>
- <artifactId>camel-support</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.camel</groupId>
- <artifactId>camel-util-json</artifactId>
+ <artifactId>camel-test-infra-azure-common</artifactId>
+ <version>${project.version}</version>
</dependency>
<!-- azure sdk -->
@@ -54,31 +53,10 @@
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-secrets</artifactId>
</dependency>
- <dependency>
- <groupId>com.azure</groupId>
- <artifactId>azure-messaging-eventhubs</artifactId>
- </dependency>
- <dependency>
- <groupId>com.azure</groupId>
-
<artifactId>azure-messaging-eventhubs-checkpointstore-blob</artifactId>
- </dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
-
- <!-- extras -->
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>${commons-io-version}</version>
- </dependency>
-
- <!-- for testing -->
- <dependency>
- <groupId>org.apache.camel</groupId>
- <artifactId>camel-test-junit6</artifactId>
- <scope>test</scope>
- </dependency>
</dependencies>
+
</project>
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/AzureKeyVaultConfigs.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/AzureKeyVaultConfigs.java
new file mode 100644
index 000000000000..5c77d79f1f00
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/AzureKeyVaultConfigs.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.infra.azure.key.vault;
+
+/**
+ * The system properties that give a real vault and the service principal that
reaches it: the ones that the integration
+ * tests of camel-azure-key-vault have always taken.
+ */
+public final class AzureKeyVaultConfigs {
+ public static final String VAULT_NAME = "vaultName";
+ public static final String CLIENT_ID = "clientId";
+ public static final String CLIENT_SECRET = "clientSecret";
+ public static final String TENANT_ID = "tenantId";
+
+ private AzureKeyVaultConfigs() {
+
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/clients/AzureKeyVaultClientUtils.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/clients/AzureKeyVaultClientUtils.java
new file mode 100644
index 000000000000..b4c6144f9d53
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/clients/AzureKeyVaultClientUtils.java
@@ -0,0 +1,97 @@
+/*
+ * 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.test.infra.azure.key.vault.clients;
+
+import java.net.URL;
+import java.time.OffsetDateTime;
+
+import com.azure.core.credential.AccessToken;
+import com.azure.core.credential.TokenCredential;
+import com.azure.core.http.HttpPipelineCallContext;
+import com.azure.core.http.HttpRequest;
+import com.azure.core.http.policy.HttpPipelineSyncPolicy;
+import com.azure.identity.ClientSecretCredentialBuilder;
+import com.azure.security.keyvault.secrets.SecretClient;
+import com.azure.security.keyvault.secrets.SecretClientBuilder;
+import org.apache.camel.test.infra.azure.common.AzureConfigs;
+import org.apache.camel.test.infra.azure.key.vault.AzureKeyVaultConfigs;
+import reactor.core.publisher.Mono;
+
+public final class AzureKeyVaultClientUtils {
+
+ // Floci AZ accepts any bearer token
+ private static final TokenCredential FLOCI_AZ_CREDENTIAL
+ = request -> Mono.just(new AccessToken("floci-az",
OffsetDateTime.now().plusHours(1)));
+
+ private AzureKeyVaultClientUtils() {
+
+ }
+
+ /**
+ * A client for the Key Vault of Floci AZ, or with {@code
-Dazure.instance.type=remote} for the vault and the
+ * service principal of the {@link AzureKeyVaultConfigs} system properties
+ */
+ public static SecretClient getClient() {
+ String instanceType = System.getProperty("azure.instance.type");
+
+ if (instanceType == null ||
instanceType.equals("local-azure-container")) {
+ return getLocalClient(String.format("https://%s:%s/%s-keyvault",
System.getProperty(AzureConfigs.HOST),
+ System.getProperty(AzureConfigs.PORT),
System.getProperty(AzureConfigs.ACCOUNT_NAME)));
+ }
+
+ return new SecretClientBuilder()
+ .vaultUrl(String.format("https://%s.vault.azure.net",
System.getProperty(AzureKeyVaultConfigs.VAULT_NAME)))
+ .credential(new ClientSecretCredentialBuilder()
+
.tenantId(System.getProperty(AzureKeyVaultConfigs.TENANT_ID))
+
.clientId(System.getProperty(AzureKeyVaultConfigs.CLIENT_ID))
+
.clientSecret(System.getProperty(AzureKeyVaultConfigs.CLIENT_SECRET))
+ .build())
+ .buildClient();
+ }
+
+ /**
+ * The Key Vault SDK sends a token only to an https address, and only for
the resource of the 401 challenge of Key
+ * Vault that matches the host of the vault. Floci AZ serves http, and its
challenge names the resource
+ * {@code https://vault.azure.net}: the client is built for the https
address of the vault, with a token that Floci
+ * AZ accepts and without the check of the resource, and a policy sends
its requests over http.
+ */
+ private static SecretClient getLocalClient(String vaultUrl) {
+ return new SecretClientBuilder()
+ .vaultUrl(vaultUrl)
+ .credential(FLOCI_AZ_CREDENTIAL)
+ .addPolicy(new HttpSchemePolicy())
+ .disableChallengeResourceVerification()
+ .buildClient();
+ }
+
+ /**
+ * Sends a request over http. A policy added to the builder comes after
the credential policy, which then still sees
+ * the https address it requires.
+ */
+ private static final class HttpSchemePolicy extends HttpPipelineSyncPolicy
{
+ @Override
+ protected void beforeSendingRequest(HttpPipelineCallContext context) {
+ HttpRequest request = context.getHttpRequest();
+
+ URL url = request.getUrl();
+ if ("https".equals(url.getProtocol())) {
+ request.setUrl("http" +
url.toString().substring("https".length()));
+ }
+ }
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultInfraService.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultInfraService.java
new file mode 100644
index 000000000000..e114a2832737
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultInfraService.java
@@ -0,0 +1,37 @@
+/*
+ * 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.test.infra.azure.key.vault.services;
+
+import org.apache.camel.test.infra.common.services.InfrastructureService;
+
+/**
+ * An Azure Key Vault: the one of Floci AZ, or a real vault. {@code
AzureKeyVaultClientUtils} builds a client for it.
+ */
+public interface AzureKeyVaultInfraService extends InfrastructureService {
+
+ /**
+ * The name of the vault
+ */
+ String vaultName();
+
+ /**
+ * The address of the vault, for example {@code
http://localhost:32768/devstoreaccount1-keyvault} for Floci AZ or
+ * {@code https://myvault.vault.azure.net} for a real vault
+ */
+ String vaultUrl();
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultLocalContainerInfraService.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultLocalContainerInfraService.java
new file mode 100644
index 000000000000..0ceed9840e12
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultLocalContainerInfraService.java
@@ -0,0 +1,46 @@
+/*
+ * 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.test.infra.azure.key.vault.services;
+
+import org.apache.camel.spi.annotations.InfraService;
+import org.apache.camel.test.infra.azure.common.services.FlociAzInfraService;
+
+/**
+ * A local Key Vault: Floci AZ serves the Key Vault of the storage account
under {@code /<account>-keyvault}, over http.
+ * It accepts any bearer token, and answers a request without one with the 401
challenge of Key Vault:
+ * {@code AzureKeyVaultClientUtils} builds a client that gets through it.
+ */
+@InfraService(service = AzureKeyVaultInfraService.class,
+ description = "Local Azure Key Vault service with Floci AZ",
+ serviceAlias = "azure", serviceImplementationAlias = "key-vault")
+public class AzureKeyVaultLocalContainerInfraService extends
FlociAzInfraService implements AzureKeyVaultInfraService {
+
+ /**
+ * The name of the vault, the account: Floci AZ gives the secrets the
identifiers of
+ * {@code https://<account>.vault.azure.net}
+ */
+ @Override
+ public String vaultName() {
+ return accountName();
+ }
+
+ @Override
+ public String vaultUrl() {
+ return String.format("%s/%s-keyvault",
getContainer().serviceAddress(), accountName());
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultRemoteInfraService.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultRemoteInfraService.java
new file mode 100644
index 000000000000..877890a935b3
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultRemoteInfraService.java
@@ -0,0 +1,51 @@
+/*
+ * 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.test.infra.azure.key.vault.services;
+
+import org.apache.camel.test.infra.azure.key.vault.AzureKeyVaultConfigs;
+
+/**
+ * A real vault, named by the {@code vaultName} system property
+ */
+public class AzureKeyVaultRemoteInfraService implements
AzureKeyVaultInfraService {
+
+ @Override
+ public void registerProperties() {
+
+ }
+
+ @Override
+ public void initialize() {
+ registerProperties();
+ }
+
+ @Override
+ public void shutdown() {
+
+ }
+
+ @Override
+ public String vaultName() {
+ return System.getProperty(AzureKeyVaultConfigs.VAULT_NAME);
+ }
+
+ @Override
+ public String vaultUrl() {
+ return String.format("https://%s.vault.azure.net", vaultName());
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultService.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultService.java
new file mode 100644
index 000000000000..00f199aba3ed
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultService.java
@@ -0,0 +1,27 @@
+/*
+ * 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.test.infra.azure.key.vault.services;
+
+import org.apache.camel.test.infra.common.services.ContainerTestService;
+import org.apache.camel.test.infra.common.services.TestService;
+
+/**
+ * Test infra service for Azure Key Vault
+ */
+public interface AzureKeyVaultService extends AzureKeyVaultInfraService,
TestService, ContainerTestService {
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultServiceFactory.java
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultServiceFactory.java
new file mode 100644
index 000000000000..d6b8c730173c
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-key-vault/src/main/java/org/apache/camel/test/infra/azure/key/vault/services/AzureKeyVaultServiceFactory.java
@@ -0,0 +1,83 @@
+/*
+ * 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.test.infra.azure.key.vault.services;
+
+import org.apache.camel.test.infra.common.services.SimpleTestServiceBuilder;
+import org.apache.camel.test.infra.common.services.SingletonService;
+
+/**
+ * Creates the Key Vault of Floci AZ, or with {@code
-Dazure.instance.type=remote} the vault of the
+ * {@code AzureKeyVaultConfigs} system properties.
+ */
+public final class AzureKeyVaultServiceFactory {
+
+ private static class SingletonAzureKeyVaultService extends
SingletonService<AzureKeyVaultService>
+ implements AzureKeyVaultService {
+ public SingletonAzureKeyVaultService(AzureKeyVaultService service,
String name) {
+ super(service, name);
+ }
+
+ @Override
+ public String vaultName() {
+ return getService().vaultName();
+ }
+
+ @Override
+ public String vaultUrl() {
+ return getService().vaultUrl();
+ }
+ }
+
+ private AzureKeyVaultServiceFactory() {
+
+ }
+
+ public static SimpleTestServiceBuilder<AzureKeyVaultService> builder() {
+ return new SimpleTestServiceBuilder<>("azure");
+ }
+
+ public static AzureKeyVaultService createService() {
+ return builder()
+ .addLocalMapping(AzureKeyVaultLocalContainerService::new)
+ .addRemoteMapping(AzureKeyVaultRemoteService::new)
+ .build();
+ }
+
+ public static AzureKeyVaultService createSingletonService() {
+ return SingletonServiceHolder.INSTANCE;
+ }
+
+ private static class SingletonServiceHolder {
+ static final AzureKeyVaultService INSTANCE;
+ static {
+ SimpleTestServiceBuilder<AzureKeyVaultService> instance =
builder();
+ // a name of its own: the singleton of another Azure service of
the same JVM must not stand for this one
+ instance.addLocalMapping(
+ () -> new SingletonAzureKeyVaultService(new
AzureKeyVaultLocalContainerService(), "azure-key-vault"))
+ .addRemoteMapping(AzureKeyVaultRemoteService::new);
+ INSTANCE = instance.build();
+ }
+ }
+
+ static class AzureKeyVaultLocalContainerService extends
AzureKeyVaultLocalContainerInfraService
+ implements AzureKeyVaultService {
+ }
+
+ static class AzureKeyVaultRemoteService extends
AzureKeyVaultRemoteInfraService implements AzureKeyVaultService {
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-key-vault/src/main/resources/META-INF/MANIFEST.MF
b/test-infra/camel-test-infra-azure-key-vault/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/test-infra/pom.xml b/test-infra/pom.xml
index 2ffc2452d5e6..d2f2f875c104 100644
--- a/test-infra/pom.xml
+++ b/test-infra/pom.xml
@@ -51,6 +51,7 @@
<module>camel-test-infra-mongodb</module>
<module>camel-test-infra-rabbitmq</module>
<module>camel-test-infra-azure-common</module>
+ <module>camel-test-infra-azure-key-vault</module>
<module>camel-test-infra-azure-storage-blob</module>
<module>camel-test-infra-azure-storage-datalake</module>
<module>camel-test-infra-azure-storage-queue</module>