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

davsclaus pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.22.x by this push:
     new 55003e484022 [backport camel-4.22.x] CAMEL-26284: 
camel-azure-storage-blob - validate the copyBlob source account and container 
names (#29766)
55003e484022 is described below

commit 55003e4840227eb2a4fd89e6fa49eb7bdd0a3d73
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 13 08:01:43 2026 +0100

    [backport camel-4.22.x] CAMEL-26284: camel-azure-storage-blob - validate 
the copyBlob source account and container names (#29766)
    
    Backport of #29254 onto camel-4.22.x (replaces #29255). copyBlob validates 
the
    source account and container names against the Azure naming rules. Straight:
    BlobOperations and BlobOperationsTest are those of #29255; the upgrade-guide
    notes already live on main.
    
    Co-authored-by: jiriOndrusek-agent <[email protected]>
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../storage/blob/operations/BlobOperations.java    | 14 +++++++++
 .../blob/operations/BlobOperationsTest.java        | 36 ++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git 
a/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperations.java
 
b/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperations.java
index 6c13d74215aa..ea162b32cbe2 100644
--- 
a/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperations.java
+++ 
b/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperations.java
@@ -27,6 +27,7 @@ import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import com.azure.core.http.rest.PagedIterable;
 import com.azure.core.http.rest.Response;
@@ -84,6 +85,10 @@ import org.slf4j.LoggerFactory;
 public class BlobOperations {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(BlobOperations.class);
+    // Azure naming rules for storage accounts and containers ($root and $web 
are the reserved containers)
+    private static final Pattern ACCOUNT_NAME_PATTERN = 
Pattern.compile("[a-z0-9]{3,24}");
+    private static final Pattern CONTAINER_NAME_PATTERN
+            = 
Pattern.compile("\\$root|\\$web|(?=.{3,63}$)[a-z0-9]+(-[a-z0-9]+)*");
     public static final String MISSING_EXCHANGE = "exchange cannot be null";
 
     private final BlobClientWrapper client;
@@ -459,6 +464,15 @@ public class BlobOperations {
         if (ObjectHelper.isEmpty(sourceContainerName)) {
             throw new IllegalArgumentException("Source Container Name must be 
specified for copyBlob Operation");
         }
+        if (!ACCOUNT_NAME_PATTERN.matcher(sourceAccountName).matches()) {
+            throw new IllegalArgumentException(
+                    "Invalid Source Account Name for copyBlob Operation: it 
must have 3 to 24 lowercase letters or digits");
+        }
+        if (!CONTAINER_NAME_PATTERN.matcher(sourceContainerName).matches()) {
+            throw new IllegalArgumentException(
+                    "Invalid Source Container Name for copyBlob Operation: it 
must have 3 to 63 lowercase letters, digits"
+                                               + " or single hyphens, and 
start and end with a letter or digit, or be $root or $web");
+        }
         final String response
                 = client.copyBlob(sourceBlobName, sourceAccountName, 
sourceContainerName,
                         
configurationProxy.getConfiguration().getSourceBlobAccessKey());
diff --git 
a/components/camel-azure/camel-azure-storage-blob/src/test/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperationsTest.java
 
b/components/camel-azure/camel-azure-storage-blob/src/test/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperationsTest.java
index 9c35ec259f94..f31467ccfe86 100644
--- 
a/components/camel-azure/camel-azure-storage-blob/src/test/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperationsTest.java
+++ 
b/components/camel-azure/camel-azure-storage-blob/src/test/java/org/apache/camel/component/azure/storage/blob/operations/BlobOperationsTest.java
@@ -629,6 +629,42 @@ class BlobOperationsTest extends CamelTestSupport {
                 .get("x-test-header").getValue());
     }
 
+    @Test
+    void testCopyBlobValidatesSourceNames() {
+        when(client.copyBlob(any(), any(), any(), any())).thenReturn("copyId");
+        final BlobOperations operations = new BlobOperations(configuration, 
client);
+
+        for (String account : new String[] { "abc", "account1", 
"a23456789012345678901234" }) {
+            for (String container : new String[] { "abc", "container-1", 
"$root", "$web", "a".repeat(63) }) {
+                assertEquals("copyId", 
operations.copyBlob(copyBlobExchange(account, container)).getBody());
+            }
+        }
+
+        // invalid account names: URL injection (host/path, query, fragment, 
userinfo, port), length, uppercase, hyphen
+        for (String account : new String[] {
+                "ab", "a234567890123456789012345", "Account", "acc.ount", 
"acc/ount", "acc?x", "acc#x", "user@acc",
+                "acc:8080", "acc-1" }) {
+            assertThrows(IllegalArgumentException.class,
+                    () -> operations.copyBlob(copyBlobExchange(account, 
"container")), account);
+        }
+        // invalid container names: URL injection (path, query, fragment, 
userinfo, port), length, uppercase, hyphens, $logs
+        for (String container : new String[] {
+                "ab", "a".repeat(64), "Container", "con.tainer", "con/tainer", 
"con?x", "con#x", "con@x", "con:80",
+                "-container", "container-", "con--tainer", "$logs" }) {
+            assertThrows(IllegalArgumentException.class,
+                    () -> operations.copyBlob(copyBlobExchange("account", 
container)), container);
+        }
+        verify(client, times(15)).copyBlob(any(), any(), any(), any());
+    }
+
+    private Exchange copyBlobExchange(String accountName, String 
containerName) {
+        final Exchange exchange = new DefaultExchange(context);
+        exchange.getMessage().setHeader(BlobConstants.BLOB_NAME, "blob");
+        
exchange.getMessage().setHeader(BlobConstants.SOURCE_BLOB_ACCOUNT_NAME, 
accountName);
+        
exchange.getMessage().setHeader(BlobConstants.SOURCE_BLOB_CONTAINER_NAME, 
containerName);
+        return exchange;
+    }
+
     private BlobProperties createBlobProperties() {
         return new BlobProperties(
                 OffsetDateTime.now(), null, null, 0L, null, null, null, null, 
null,

Reply via email to