You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/08/02 06:27:27 UTC

[camel-quarkus] branch main updated: Test Azure Storage Blob with credentialType AZURE_IDENTITY

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new cf4974d5ec Test Azure Storage Blob with credentialType AZURE_IDENTITY
cf4974d5ec is described below

commit cf4974d5ec4317ad036f832ad263bbfc6a6467ca
Author: James Netherton <ja...@gmail.com>
AuthorDate: Mon Aug 1 10:21:08 2022 +0100

    Test Azure Storage Blob with credentialType AZURE_IDENTITY
    
    Fixes #3822
---
 integration-test-groups/azure/README.adoc          | 18 +++++-
 integration-test-groups/azure/azure-resources.sh   | 31 +++++++++-
 .../azure/azure-storage-blob/pom.xml               |  4 ++
 .../storage/blob/it/AzureStorageBlobProducers.java | 58 ++++++++++++++++---
 .../storage/blob/it/AzureStorageBlobRoutes.java    | 12 ++++
 .../azure/storage/blob/it/AzureStorageHelper.java  | 66 ++++++++++++++++++++++
 .../storage/blob/it/AzureStorageBlobTest.java      | 60 +++++++++++++++++++-
 integration-test-groups/azure/certs/azure-cert.pem | 54 ++++++++++++++++++
 integration-tests/azure-grouped/pom.xml            |  4 ++
 9 files changed, 296 insertions(+), 11 deletions(-)

diff --git a/integration-test-groups/azure/README.adoc b/integration-test-groups/azure/README.adoc
index 7115205941..4a234eb335 100644
--- a/integration-test-groups/azure/README.adoc
+++ b/integration-test-groups/azure/README.adoc
@@ -27,8 +27,7 @@ To create all of the above, you can use `azure-resources.sh` script as follows.
 $ ./azure-resources.sh create
 ----
 
-The script outputs a set of export commands that you may want to paste to your shell,
-or to your `.bashrc`.
+The script outputs a set of export commands that you may want to paste to your shell.
 
 Here are the environment variables you need to set:
 
@@ -36,6 +35,13 @@ Here are the environment variables you need to set:
 ----
 export AZURE_STORAGE_ACCOUNT_NAME=<your-azure-storage-account-name>
 export AZURE_STORAGE_ACCOUNT_KEY=<your-azure-storage-account-key>
+
+# optional to test alternate authentication methods
+export AZURE_CLIENT_ID=<your-azure-app-client-id>
+export AZURE_CLIENT_SECRET=<your-azure-app-client-secret>
+export AZURE_TENANT_ID=<your-azure-app-tenant-id>
+export AZURE_CLIENT_CERTIFICATE_PATH=<your-azure-app-certificate-pem-file>
+
 # the container has to exist before you run the test
 export AZURE_EVENT_HUBS_BLOB_CONTAINER_NAME=<your-container-name>
 export AZURE_EVENT_HUBS_CONNECTION_STRING="Endpoint=sb://<your-namespace>.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=<your-key>;EntityPath=<your-hub-name>"
@@ -50,4 +56,12 @@ $ ./azure-resources.sh delete
 
 You may want to `export CAMEL_QUARKUS_START_MOCK_BACKEND=false` to avoid starting the local Azurite container and make sure that you test against the real remote Azure API.
 
+==== Regenerating client certificates
+
+For convenience, a certificate is stored in this project to be used for client certificate authentication. It can be regenerated as follows.
 
+[source,shell]
+----
+openssl req -nodes -new -x509 -sha256 -days 1825 -out /tmp/azure-cert.pem -keyout /tmp/azure-cert-key.pem
+cat /tmp/azure-cert.pem /tmp/azure-cert-key.pem > ${PWD}/certs/azure-cert.pem
+----
diff --git a/integration-test-groups/azure/azure-resources.sh b/integration-test-groups/azure/azure-resources.sh
index 1e65e5b760..0e774bc022 100755
--- a/integration-test-groups/azure/azure-resources.sh
+++ b/integration-test-groups/azure/azure-resources.sh
@@ -28,6 +28,8 @@ suffix="$(az ad signed-in-user show --query displayName -o tsv | tr '[:upper:]'
 suffix="${suffix}4"
 export AZURE_STORAGE_ACCOUNT_NAME=cqacc${suffix}
 export AZURE_BLOB_CONTAINER_NAME=cq-container-${suffix}
+export AZURE_APP_NAME=cq-app-${suffix}
+export AZURE_APP_CERT_PATH=${PWD}/certs/azure-cert.pem
 
 export RESOURCE_GROUP=cq-res-group-${suffix}
 export ZONE=westeurope
@@ -42,11 +44,30 @@ function createResources() {
     az storage account create --name ${AZURE_STORAGE_ACCOUNT_NAME} --resource-group ${RESOURCE_GROUP} --location ${ZONE} --sku Standard_LRS --kind StorageV2
     az storage account blob-service-properties update --enable-change-feed true --enable-delete-retention true --delete-retention-days 1 -n ${AZURE_STORAGE_ACCOUNT_NAME} -g ${RESOURCE_GROUP}
 
+    AZURE_APP_CREDENTIALS=/tmp/app-credentials.json
+    AZURE_CLIENT_ID=$(az ad app create --display-name ${AZURE_APP_NAME} --query 'appId' -o tsv)
+    az ad app credential reset --id ${AZURE_CLIENT_ID} > ${AZURE_APP_CREDENTIALS}
+    if [[ ! -f ${AZURE_APP_CREDENTIALS} ]]; then
+      echo "Credentials generation for application ${AZURE_APP_NAME} failed"
+      exit 1
+    fi
+
+    export AZURE_CLIENT_SECRET=$(grep password ${AZURE_APP_CREDENTIALS} | cut -f4 -d\" )
+    export AZURE_TENANT_ID=$(grep tenant  ${AZURE_APP_CREDENTIALS} | cut -f4 -d\" )
+    rm -f ${AZURE_APP_CREDENTIALS}
+
+    az ad app credential reset --id ${AZURE_CLIENT_ID} --cert "@${AZURE_APP_CERT_PATH}" --append
+
     SUBSCRIPTION_ID="$(az account list --query '[0].id' -o tsv)"
     USER_ID="$(az ad signed-in-user show --query objectId -o tsv)"
-    az role assignment create --role "Storage Blob Data Contributor"  --assignee ${USER_ID} --scope "/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Storage/storageAccounts/${AZURE_STORAGE_ACCOUNT_NAME}"
+    az role assignment create --role "Storage Blob Data Contributor" --assignee ${USER_ID} --scope "/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Storage/storageAccounts/${AZURE_STORAGE_ACCOUNT_NAME}"
+
+    az ad sp create --id ${AZURE_CLIENT_ID}
+    az role assignment create --role "Storage Blob Data Contributor" --assignee ${AZURE_CLIENT_ID} --scope "/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Storage/storageAccounts/${AZURE_STORAGE_ACCOUNT_NAME}"
 
+    echo "Waiting for Azure resources to become available..."
     sleep 30
+    echo
 
     az storage container create --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --name ${AZURE_BLOB_CONTAINER_NAME} --auth-mode login
 
@@ -64,6 +85,13 @@ function createResources() {
     echo 'export AZURE_STORAGE_ACCOUNT_KEY="'${AZURE_STORAGE_ACCOUNT_KEY}'"'
     echo 'export AZURE_EVENT_HUBS_BLOB_CONTAINER_NAME="'${AZURE_BLOB_CONTAINER_NAME}'"'
     echo 'export AZURE_EVENT_HUBS_CONNECTION_STRING="'$AZURE_EVENT_HUBS_CONNECTION_STRING';EntityPath='${EH_NAME}'"'
+    echo
+    echo
+    echo "Optionally set the following to test alternate authentication mechanisms:"
+    echo 'export AZURE_CLIENT_ID="'${AZURE_CLIENT_ID}'"'
+    echo 'export AZURE_CLIENT_SECRET="'${AZURE_CLIENT_SECRET}'"'
+    echo 'export AZURE_TENANT_ID="'${AZURE_TENANT_ID}'"'
+    echo 'export AZURE_CLIENT_CERTIFICATE_PATH="'${AZURE_APP_CERT_PATH}'"'
 }
 
 
@@ -75,6 +103,7 @@ function deleteResources() {
     az storage container delete --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --name ${AZURE_BLOB_CONTAINER_NAME}
     az storage account delete --name ${AZURE_STORAGE_ACCOUNT_NAME} --resource-group ${RESOURCE_GROUP} --yes
     az group delete --name ${RESOURCE_GROUP} --yes
+    az ad app delete --id $(az ad app list --display-name ${AZURE_APP_NAME} --query '[0].appId' -o tsv)
 }
 
 case "$1" in
diff --git a/integration-test-groups/azure/azure-storage-blob/pom.xml b/integration-test-groups/azure/azure-storage-blob/pom.xml
index def22f98ac..d54482424a 100644
--- a/integration-test-groups/azure/azure-storage-blob/pom.xml
+++ b/integration-test-groups/azure/azure-storage-blob/pom.xml
@@ -51,6 +51,10 @@
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-resteasy-jsonb</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-integration-test-support-mock-backend</artifactId>
+        </dependency>
 
         <!-- test dependencies -->
         <dependency>
diff --git a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobProducers.java b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobProducers.java
index f15cabf492..44be3faff4 100644
--- a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobProducers.java
+++ b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobProducers.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.quarkus.component.azure.storage.blob.it;
 
+import java.io.IOException;
+
 import javax.inject.Named;
 
 import com.azure.core.http.policy.HttpLogDetailLevel;
@@ -24,6 +26,8 @@ import com.azure.storage.blob.BlobServiceClient;
 import com.azure.storage.blob.BlobServiceClientBuilder;
 import com.azure.storage.common.StorageSharedKeyCredential;
 import org.apache.camel.component.azure.storage.blob.BlobComponent;
+import org.apache.camel.component.azure.storage.blob.BlobConfiguration;
+import org.apache.camel.component.azure.storage.blob.CredentialType;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 
 public class AzureStorageBlobProducers {
@@ -37,21 +41,61 @@ public class AzureStorageBlobProducers {
     @ConfigProperty(name = "azure.blob.service.url")
     String azureBlobServiceUrl;
 
+    @Named("azureStorageSharedKeyCredential")
+    public StorageSharedKeyCredential azureStorageSharedKeyCredential() {
+        return new StorageSharedKeyCredential(azureStorageAccountName, azureStorageAccountKey);
+    }
+
     @Named("azureBlobServiceClient")
-    public BlobServiceClient createBlobClient() throws Exception {
-        StorageSharedKeyCredential credentials = new StorageSharedKeyCredential(azureStorageAccountName,
-                azureStorageAccountKey);
-        return new BlobServiceClientBuilder()
-                .endpoint(azureBlobServiceUrl)
-                .credential(credentials)
-                .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS).setPrettyPrintBody(true))
+    public BlobServiceClient createBlobClient(StorageSharedKeyCredential credential) {
+        return getBlobClientBuilder()
+                .credential(credential)
                 .buildClient();
     }
 
     @Named("azure-storage-blob-managed-client")
     public BlobComponent azureBlobComponentWithManagedClient() {
+        BlobConfiguration configuration = new BlobConfiguration();
+        configuration.setCredentialType(CredentialType.SHARED_KEY_CREDENTIAL);
+
         BlobComponent component = new BlobComponent();
         component.setAutowiredEnabled(false);
+        component.setConfiguration(configuration);
         return component;
     }
+
+    @Named("azure-storage-blob-client-secret-auth")
+    public BlobComponent azureStorageBlobClientSecretAuth() {
+        if (AzureStorageHelper.isClientSecretAuthEnabled()) {
+            BlobConfiguration configuration = new BlobConfiguration();
+            configuration.setCredentialType(CredentialType.AZURE_IDENTITY);
+
+            BlobComponent component = new BlobComponent();
+            component.setAutowiredEnabled(false);
+            component.setConfiguration(configuration);
+            return component;
+        }
+        return null;
+    }
+
+    @Named("azure-storage-blob-client-certificate-auth")
+    public BlobComponent azureStorageBlobClientCertificateAuth() throws IOException {
+        if (AzureStorageHelper.isClientCertificateAuthEnabled()) {
+            BlobConfiguration configuration = new BlobConfiguration();
+            configuration.setCredentialType(CredentialType.AZURE_IDENTITY);
+
+            BlobComponent component = new BlobComponent();
+            component.setAutowiredEnabled(false);
+            component.setConfiguration(configuration);
+            return component;
+        }
+        return null;
+    }
+
+    private BlobServiceClientBuilder getBlobClientBuilder() {
+        return new BlobServiceClientBuilder().endpoint(azureBlobServiceUrl)
+                .httpLogOptions(new HttpLogOptions()
+                        .setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
+                        .setPrettyPrintBody(true));
+    }
 }
diff --git a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobRoutes.java b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobRoutes.java
index 7f6cfa8d7f..d3260a0d0c 100644
--- a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobRoutes.java
+++ b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobRoutes.java
@@ -54,6 +54,18 @@ public class AzureStorageBlobRoutes extends RouteBuilder {
                 .to(componentUri("azure-storage-blob-managed-client", BlobOperationsDefinition.getBlob)
                         + "&autowiredEnabled=false");
 
+        if (AzureStorageHelper.isClientSecretAuthEnabled()) {
+            from("direct:readWithClientSecret")
+                    .to(componentUri("azure-storage-blob-client-secret-auth", BlobOperationsDefinition.getBlob)
+                            + "&autowiredEnabled=false");
+        }
+
+        if (AzureStorageHelper.isClientCertificateAuthEnabled()) {
+            from("direct:readWithClientCertificate")
+                    .to(componentUri("azure-storage-blob-client-certificate-auth", BlobOperationsDefinition.getBlob)
+                            + "&autowiredEnabled=false");
+        }
+
         from("direct:update")
                 .to(componentUri(BlobOperationsDefinition.uploadBlockBlob));
 
diff --git a/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageHelper.java b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageHelper.java
new file mode 100644
index 0000000000..b9a6c7a498
--- /dev/null
+++ b/integration-test-groups/azure/azure-storage-blob/src/main/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageHelper.java
@@ -0,0 +1,66 @@
+/*
+ * 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.storage.blob.it;
+
+import java.util.function.BooleanSupplier;
+
+import org.apache.camel.quarkus.test.mock.backend.MockBackendUtils;
+import org.eclipse.microprofile.config.ConfigProvider;
+
+public class AzureStorageHelper {
+
+    private static final BooleanSupplier clientSecretAuthEnabled = new ClientSecretAuthEnabled();
+    private static final BooleanSupplier clientCertificateAuthEnabled = new ClientCertificateAuthEnabled();
+
+    public static class ClientSecretAuthEnabled implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return !MockBackendUtils.startMockBackend() &&
+                    isAzureConfigValuePresent("azure.client.id") &&
+                    isAzureConfigValuePresent("azure.tenant.id") &&
+                    isAzureConfigValuePresent("azure.client.secret");
+        }
+    }
+
+    public static class ClientCertificateAuthEnabled implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return !MockBackendUtils.startMockBackend() &&
+                    isAzureConfigValuePresent("azure.client.id") &&
+                    isAzureConfigValuePresent("azure.tenant.id") &&
+                    isAzureConfigValuePresent("azure.client.certificate.path");
+        }
+    }
+
+    private AzureStorageHelper() {
+        // Utility class
+    }
+
+    public static boolean isClientSecretAuthEnabled() {
+        return clientSecretAuthEnabled.getAsBoolean();
+    }
+
+    public static boolean isClientCertificateAuthEnabled() {
+        return clientCertificateAuthEnabled.getAsBoolean();
+    }
+
+    private static boolean isAzureConfigValuePresent(String name) {
+        return ConfigProvider.getConfig()
+                .getOptionalValue(name, String.class)
+                .isPresent();
+    }
+}
diff --git a/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java b/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java
index de772d5902..f55e462205 100644
--- a/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java
+++ b/integration-test-groups/azure/azure-storage-blob/src/test/java/org/apache/camel/quarkus/component/azure/storage/blob/it/AzureStorageBlobTest.java
@@ -33,6 +33,8 @@ import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
 import io.restassured.path.json.JsonPath;
+import org.apache.camel.quarkus.component.azure.storage.blob.it.AzureStorageHelper.ClientCertificateAuthEnabled;
+import org.apache.camel.quarkus.component.azure.storage.blob.it.AzureStorageHelper.ClientSecretAuthEnabled;
 import org.apache.camel.quarkus.test.EnabledIf;
 import org.apache.camel.quarkus.test.mock.backend.MockBackendDisabled;
 import org.apache.camel.quarkus.test.support.azure.AzureStorageTestResource;
@@ -45,9 +47,9 @@ import org.testcontainers.shaded.org.awaitility.Awaitility;
 
 import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.matchesPattern;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.StringEndsWith.endsWith;
-import static org.hamcrest.text.MatchesPattern.matchesPattern;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
@@ -544,4 +546,60 @@ class AzureStorageBlobTest {
                     .statusCode(anyOf(is(204), is(404)));
         }
     }
+
+    // Authentication with client secrets is not possible with Azurite
+    @EnabledIf({ ClientSecretAuthEnabled.class })
+    @Test
+    public void readWithClientSecretAuth() {
+        try {
+            // Create
+            RestAssured.given()
+                    .contentType(ContentType.TEXT)
+                    .body(BLOB_CONTENT)
+                    .post("/azure-storage-blob/blob/create")
+                    .then()
+                    .statusCode(201);
+
+            // Read
+            RestAssured.given()
+                    .queryParam("uri", "direct:readWithClientSecret")
+                    .get("/azure-storage-blob/blob/read")
+                    .then()
+                    .statusCode(200)
+                    .body(is(BLOB_CONTENT));
+        } finally {
+            // Delete
+            RestAssured.delete("/azure-storage-blob/blob/delete")
+                    .then()
+                    .statusCode(anyOf(is(204), is(404)));
+        }
+    }
+
+    // Authentication with client certificates is not possible with Azurite
+    @EnabledIf({ ClientCertificateAuthEnabled.class })
+    @Test
+    public void readWithClientCertificateAuth() {
+        try {
+            // Create
+            RestAssured.given()
+                    .contentType(ContentType.TEXT)
+                    .body(BLOB_CONTENT)
+                    .post("/azure-storage-blob/blob/create")
+                    .then()
+                    .statusCode(201);
+
+            // Read
+            RestAssured.given()
+                    .queryParam("uri", "direct:readWithClientCertificate")
+                    .get("/azure-storage-blob/blob/read")
+                    .then()
+                    .statusCode(200)
+                    .body(is(BLOB_CONTENT));
+        } finally {
+            // Delete
+            RestAssured.delete("/azure-storage-blob/blob/delete")
+                    .then()
+                    .statusCode(anyOf(is(204), is(404)));
+        }
+    }
 }
diff --git a/integration-test-groups/azure/certs/azure-cert.pem b/integration-test-groups/azure/certs/azure-cert.pem
new file mode 100644
index 0000000000..1d5ba8261a
--- /dev/null
+++ b/integration-test-groups/azure/certs/azure-cert.pem
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIIEUTCCAzmgAwIBAgIUdmqSX4JJGabAaZ7KRAKRLqRphWswDQYJKoZIhvcNAQEL
+BQAwgbcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQH
+DAlUZXN0IENpdHkxJDAiBgNVBAoMG0NhbWVsIFF1YXJrdXMgQXp1cmUgVGVzdGlu
+ZzEkMCIGA1UECwwbQ2FtZWwgUXVhcmt1cyBBenVyZSBUZXN0aW5nMRIwEAYDVQQD
+DAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEGNhbWVsQGFwYWNoZS5vcmcwHhcN
+MjIwODAxMDgzMTMwWhcNMjcwNzMxMDgzMTMwWjCBtzELMAkGA1UEBhMCVVMxEzAR
+BgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCVRlc3QgQ2l0eTEkMCIGA1UECgwb
+Q2FtZWwgUXVhcmt1cyBBenVyZSBUZXN0aW5nMSQwIgYDVQQLDBtDYW1lbCBRdWFy
+a3VzIEF6dXJlIFRlc3RpbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDEfMB0GCSqGSIb3
+DQEJARYQY2FtZWxAYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALV4k8KkQ9g1jG3cimE11r6/kNkGQ5uG7EtGMMYB0k2T+JftlHFM59id
+R/lBIUelRmKacLmYymJdGLXgz5B1shBQHtIaN2PPSi3qp6vc+1S0Xz9bIF2My1aF
+hevfrg21+WUernAIrDdBSiI5/7BZOsEiq4suWBSGRiay1Mq/mHN6IdW07KjJNvIy
+V2Kx4qBU2wz3IzsB+xiCbgJSEUCJE787M6HJctBWqIOX2o4ZTBfxn2AUiSALmXwy
+3rsg2YA3tPTFIQRr66QYHJcwvQeXyZZyIi0l40MUYigwfEBLV93fdzzix/QOOz2R
+IPmGsXaSRjS6teVd02Qd3ohXm9CTnSMCAwEAAaNTMFEwHQYDVR0OBBYEFIxzv9Sk
+Ge8mm0NHmLGuAzZ82xhXMB8GA1UdIwQYMBaAFIxzv9SkGe8mm0NHmLGuAzZ82xhX
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGiMRb4wgsCh0v2Z
+YNW1RpZ/Bl+ER7ZkLwc5xMNFWklAjCrTI6tTXUvP462bItYrWqlxd2e6fUvNgcnb
+JJUsNaYmTYxAFhUVdXkXjIXsg4+av6JIB8/2AdMQiSxekqqi8AEfElFgONWoj8w4
+TbXwMYZWan6Bj/sN4lGIHvo6zhuLH4g4HbyKffXdRe83k+082WLby/3raAa/Sy2t
+S86BYWqdu+E59PuUEU/3rY1T4wSCZXjS4DAFfYcUmXI6gDgpCi3lb8GHKX9YvZCT
+3e4IQMZaXDIA1lyYLULvrGi+NP3tpWV+b3G/Hk6xmophoMsRd5NVOh7pR8ZDYYiL
+IScC1sY=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1eJPCpEPYNYxt
+3IphNda+v5DZBkObhuxLRjDGAdJNk/iX7ZRxTOfYnUf5QSFHpUZimnC5mMpiXRi1
+4M+QdbIQUB7SGjdjz0ot6qer3PtUtF8/WyBdjMtWhYXr364NtfllHq5wCKw3QUoi
+Of+wWTrBIquLLlgUhkYmstTKv5hzeiHVtOyoyTbyMldiseKgVNsM9yM7AfsYgm4C
+UhFAiRO/OzOhyXLQVqiDl9qOGUwX8Z9gFIkgC5l8Mt67INmAN7T0xSEEa+ukGByX
+ML0Hl8mWciItJeNDFGIoMHxAS1fd33c84sf0Djs9kSD5hrF2kkY0urXlXdNkHd6I
+V5vQk50jAgMBAAECggEAFXIffDQvdGC3rNAQZnaXX0mCU7OCz+F9EVRFNVFHyjU/
+fqzsCwu8poPH2rQQu8fTbpmz0qs017UK04uy2+6c0YK2cbv5ack4if6ePBhMd3Et
+hG4/f+7ApQP4lKyFhEdKJuIeWU0dFRaZLTxPdEbHQ8XWIgejDyHjLnWZ4jAMUzEb
+mOXeyXipfk6KkbVSWrXWS37jv3/6D6vXmVxWms7I2HggRVpIetuvxhoHo33MjohT
+MuR26FUWBQizouXmSQV4OGocHVtnr/mdktAh6QC00Pen3Gpi7xQHgXmVOVET0Qt6
+fZSdaYm9EmrU2EgTcjKwI80O/2SUapfXXtmmmu+z+QKBgQDtlhX+fuTReCGh+70b
+OTYiPOuVHhtgwazvg5Pmj7WiM/AeeyRuHYwKx4nFOgiVasaUqwEawDwdZzJCaphm
+4EfRvKqlbehN/kSk7Gq50+LjmISRPTzl8XzF0kuSWf6EHQKaEy1j+cckCuQks0U5
+U2F7zdiBNoaqkfvIpVVOo4K49wKBgQDDiR3VXLa3rp6Lrig9xEI4pybZbdutOXPY
+S4MI+KN2EGaobAF5icQ3RoXgyfxqxkJ8Vp6xSAuQgVQEBFOnth/GM7JHxw17GB2F
+u9a/LFkuQgC1uTLA6hpJBhmT9q9KFMaq0gOP//2xBjBU66AcVq8C11vAHwFXlgAK
+oCyHZaS+NQKBgQDQu62zG/UYe3zA/ZSVGFyRFAi9x+exyDaRb34/cD7ZtNvfS70j
+6V2iEtDdsDDeZSL2do7P29h01Ld5VoFy0NUIVcNu9/LCowPYCcVyYc/Suaqul6ir
+NNC0VCAFAn/zvjENAJA+Z7In3lG2VLIavUDGLoFqdGc38G3PSEJ8hndQ3QKBgQCH
+JpT6TnT0jLuFLEEgQDDNW6tcibRXDOjnTXoqj0DccAWkz9JNIU4ALryGXNYdLx/x
+NSXGv1dO8DUT+bGgsB9SLZVCS3Ej7c0qDGUoCg0yDejTskhEUwsMAi1Xuh/6glW2
+6CYSOAwveWmaqKooLDoXKqd+KXASC9nHfmKIy1aNKQKBgEIh4B9PoYT00HNfAwqL
+d8QDMjFmV+JktkgjGTc7CJUUn6WuE1WHZ6HrzRHCvNwMcRRZvUf79uzTj8GxNVdq
+bJwaxuW2g+/e0snnsgy3g0opN7veW0i+RvtLabE/hEazruY264Bin59VBgfoSraB
+/7a0gQ6Ez1OoP7+sAM+b5sc/
+-----END PRIVATE KEY-----
diff --git a/integration-tests/azure-grouped/pom.xml b/integration-tests/azure-grouped/pom.xml
index 659aed4c09..c41606cd5d 100644
--- a/integration-tests/azure-grouped/pom.xml
+++ b/integration-tests/azure-grouped/pom.xml
@@ -72,6 +72,10 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-seda</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-integration-test-support-mock-backend</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-junit5</artifactId>