From c3832b26872363f268daa388a565a8e45b0bbb4a Mon Sep 17 00:00:00 2001 From: browndav-msft Date: Thu, 26 Feb 2026 12:17:23 -0500 Subject: [PATCH 1/7] Stg102/versions (#48118) * bump latest service version from 2026_04_06 to 2026_06_06 for stg102 * refactor transformutils to use switch * made changes based on comments --- .../storage/blob/BlobServiceVersion.java | 9 +- .../azure-storage-common/ci.system.properties | 4 +- .../common/implementation/Constants.java | 4 +- .../file/datalake/DataLakeServiceVersion.java | 9 +- .../implementation/util/TransformUtils.java | 159 +++++++++++------- .../file/share/ShareServiceVersion.java | 9 +- .../storage/queue/QueueServiceVersion.java | 9 +- 7 files changed, 129 insertions(+), 74 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceVersion.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceVersion.java index efa24e69b84d..75fb74a59a5d 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceVersion.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceVersion.java @@ -157,7 +157,12 @@ public enum BlobServiceVersion implements ServiceVersion { /** * Service version {@code 2026-04-06}. */ - V2026_04_06("2026-04-06"); + V2026_04_06("2026-04-06"), + + /** + * Service version {@code 2026-06-06}. + */ + V2026_06_06("2026-06-06"); private final String version; @@ -179,6 +184,6 @@ public String getVersion() { * @return the latest {@link BlobServiceVersion} */ public static BlobServiceVersion getLatest() { - return V2026_04_06; + return V2026_06_06; } } diff --git a/sdk/storage/azure-storage-common/ci.system.properties b/sdk/storage/azure-storage-common/ci.system.properties index bc23f62e8aac..1d1c46cd13b4 100644 --- a/sdk/storage/azure-storage-common/ci.system.properties +++ b/sdk/storage/azure-storage-common/ci.system.properties @@ -1,2 +1,2 @@ -AZURE_LIVE_TEST_SERVICE_VERSION=V2026_04_06 -AZURE_STORAGE_SAS_SERVICE_VERSION=2026-04-06 +AZURE_LIVE_TEST_SERVICE_VERSION=V2026_06_06 +AZURE_STORAGE_SAS_SERVICE_VERSION=2026-06-06 diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java index f3a229f64482..d40b9b82d585 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java @@ -88,7 +88,7 @@ public final class Constants { public static final String PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION = "AZURE_STORAGE_SAS_SERVICE_VERSION"; public static final String SAS_SERVICE_VERSION - = Configuration.getGlobalConfiguration().get(PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, "2026-04-06"); + = Configuration.getGlobalConfiguration().get(PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, "2026-06-06"); public static final String ADJUSTED_BLOB_LENGTH_KEY = "adjustedBlobLength"; @@ -220,7 +220,7 @@ public static final class HeaderConstants { * @deprecated For SAS Service Version use {@link Constants#SAS_SERVICE_VERSION}. */ @Deprecated - public static final String TARGET_STORAGE_VERSION = "2026-04-06"; + public static final String TARGET_STORAGE_VERSION = "2026-06-06"; /** * Error code returned from the service. diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeServiceVersion.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeServiceVersion.java index edce1f35ee0f..3e3ec7595cee 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeServiceVersion.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeServiceVersion.java @@ -157,7 +157,12 @@ public enum DataLakeServiceVersion implements ServiceVersion { /** * Service version {@code 2026-04-06}. */ - V2026_04_06("2026-04-06"); + V2026_04_06("2026-04-06"), + + /** + * Service version {@code 2026-06-06}. + */ + V2026_06_06("2026-06-06"); private final String version; @@ -179,6 +184,6 @@ public String getVersion() { * @return the latest {@link DataLakeServiceVersion} */ public static DataLakeServiceVersion getLatest() { - return V2026_04_06; + return V2026_06_06; } } diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/TransformUtils.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/TransformUtils.java index ed8ffdd6a4f4..fe07d636f95c 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/TransformUtils.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/TransformUtils.java @@ -12,68 +12,103 @@ public static BlobServiceVersion toBlobServiceVersion(DataLakeServiceVersion ver if (version == null) { return null; } - if (DataLakeServiceVersion.V2019_12_12.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2019_12_12; - } else if (DataLakeServiceVersion.V2019_07_07.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2019_07_07; - } else if (DataLakeServiceVersion.V2019_02_02.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2019_02_02; - } else if (DataLakeServiceVersion.V2020_02_10.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2020_02_10; - } else if (DataLakeServiceVersion.V2020_04_08.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2020_04_08; - } else if (DataLakeServiceVersion.V2020_06_12.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2020_06_12; - } else if (DataLakeServiceVersion.V2020_08_04.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2020_08_04; - } else if (DataLakeServiceVersion.V2020_10_02.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2020_10_02; - } else if (DataLakeServiceVersion.V2020_12_06.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2020_12_06; - } else if (DataLakeServiceVersion.V2021_02_12.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2021_02_12; - } else if (DataLakeServiceVersion.V2021_04_10.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2021_04_10; - } else if (DataLakeServiceVersion.V2021_06_08.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2021_06_08; - } else if (DataLakeServiceVersion.V2021_08_06.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2021_08_06; - } else if (DataLakeServiceVersion.V2021_10_04.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2021_10_04; - } else if (DataLakeServiceVersion.V2021_12_02.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2021_12_02; - } else if (DataLakeServiceVersion.V2022_11_02.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2022_11_02; - } else if (DataLakeServiceVersion.V2023_01_03.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2023_01_03; - } else if (DataLakeServiceVersion.V2023_05_03.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2023_05_03; - } else if (DataLakeServiceVersion.V2023_08_03.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2023_08_03; - } else if (DataLakeServiceVersion.V2023_11_03.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2023_11_03; - } else if (DataLakeServiceVersion.V2024_02_04.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2024_02_04; - } else if (DataLakeServiceVersion.V2024_05_04.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2024_05_04; - } else if (DataLakeServiceVersion.V2024_08_04.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2024_08_04; - } else if (DataLakeServiceVersion.V2024_11_04.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2024_11_04; - } else if (DataLakeServiceVersion.V2025_01_05.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2025_01_05; - } else if (DataLakeServiceVersion.V2025_05_05.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2025_05_05; - } else if (DataLakeServiceVersion.V2025_07_05.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2025_07_05; - } else if (DataLakeServiceVersion.V2025_11_05.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2025_11_05; - } else if (DataLakeServiceVersion.V2026_02_06.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2026_02_06; - } else if (DataLakeServiceVersion.V2026_04_06.ordinal() == version.ordinal()) { - return BlobServiceVersion.V2026_04_06; - } - return null; + switch (version) { + case V2019_02_02: + return BlobServiceVersion.V2019_02_02; + + case V2019_07_07: + return BlobServiceVersion.V2019_07_07; + + case V2019_12_12: + return BlobServiceVersion.V2019_12_12; + + case V2020_02_10: + return BlobServiceVersion.V2020_02_10; + + case V2020_04_08: + return BlobServiceVersion.V2020_04_08; + + case V2020_06_12: + return BlobServiceVersion.V2020_06_12; + + case V2020_08_04: + return BlobServiceVersion.V2020_08_04; + + case V2020_10_02: + return BlobServiceVersion.V2020_10_02; + + case V2020_12_06: + return BlobServiceVersion.V2020_12_06; + + case V2021_02_12: + return BlobServiceVersion.V2021_02_12; + + case V2021_04_10: + return BlobServiceVersion.V2021_04_10; + + case V2021_06_08: + return BlobServiceVersion.V2021_06_08; + + case V2021_08_06: + return BlobServiceVersion.V2021_08_06; + + case V2021_10_04: + return BlobServiceVersion.V2021_10_04; + + case V2021_12_02: + return BlobServiceVersion.V2021_12_02; + + case V2022_11_02: + return BlobServiceVersion.V2022_11_02; + + case V2023_01_03: + return BlobServiceVersion.V2023_01_03; + + case V2023_05_03: + return BlobServiceVersion.V2023_05_03; + + case V2023_08_03: + return BlobServiceVersion.V2023_08_03; + + case V2023_11_03: + return BlobServiceVersion.V2023_11_03; + + case V2024_02_04: + return BlobServiceVersion.V2024_02_04; + + case V2024_05_04: + return BlobServiceVersion.V2024_05_04; + + case V2024_08_04: + return BlobServiceVersion.V2024_08_04; + + case V2024_11_04: + return BlobServiceVersion.V2024_11_04; + + case V2025_01_05: + return BlobServiceVersion.V2025_01_05; + + case V2025_05_05: + return BlobServiceVersion.V2025_05_05; + + case V2025_07_05: + return BlobServiceVersion.V2025_07_05; + + case V2025_11_05: + return BlobServiceVersion.V2025_11_05; + + case V2026_02_06: + return BlobServiceVersion.V2026_02_06; + + case V2026_04_06: + return BlobServiceVersion.V2026_04_06; + + case V2026_06_06: + return BlobServiceVersion.V2026_06_06; + + default: + return null; + } } } diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareServiceVersion.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareServiceVersion.java index 3d00281ac334..20d1e6de7cea 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareServiceVersion.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareServiceVersion.java @@ -157,7 +157,12 @@ public enum ShareServiceVersion implements ServiceVersion { /** * Service version {@code 2026-04-06}. */ - V2026_04_06("2026-04-06"); + V2026_04_06("2026-04-06"), + + /** + * Service version {@code 2026-06-06}. + */ + V2026_06_06("2026-06-06"); private final String version; @@ -179,6 +184,6 @@ public String getVersion() { * @return the latest {@link ShareServiceVersion} */ public static ShareServiceVersion getLatest() { - return V2026_04_06; + return V2026_06_06; } } diff --git a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceVersion.java b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceVersion.java index a91ee8d85a1b..efd0cded7d73 100644 --- a/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceVersion.java +++ b/sdk/storage/azure-storage-queue/src/main/java/com/azure/storage/queue/QueueServiceVersion.java @@ -157,7 +157,12 @@ public enum QueueServiceVersion implements ServiceVersion { /** * Service version {@code 2026-04-06}. */ - V2026_04_06("2026-04-06"); + V2026_04_06("2026-04-06"), + + /** + * Service version {@code 2026-06-06}. + */ + V2026_06_06("2026-06-06"); private final String version; @@ -179,6 +184,6 @@ public String getVersion() { * @return the latest {@link QueueServiceVersion} */ public static QueueServiceVersion getLatest() { - return V2026_04_06; + return V2026_06_06; } } From 247b28ecf04700f9b16829c6d71664685e4926cf Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 4 Mar 2026 16:05:27 -0500 Subject: [PATCH 2/7] finish upload for put block --- sdk/storage/azure-storage-blob/assets.json | 2 +- .../storage/blob/SasAsyncClientTests.java | 32 +++++++++++++++++++ .../azure/storage/blob/SasClientTests.java | 28 ++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index d98b4bc847a7..06a80624826d 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_4ab10936db" + "Tag": "java/storage/azure-storage-blob_c21aadb9a6" } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 5bbb4c809db4..0840b8c4aba9 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -583,6 +583,37 @@ public void containerSasFilterBlobsFail() { StepVerifier.create(client.setTags(tags)).verifyError(BlobStorageException.class); } + @Test + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + public void createPermissionUpload() { + BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); + BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); + + String oauthBlobName = generateBlobName(); + OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); + + Mono response = oauthService.getUserDelegationKey(null, expiryTime).flatMap(key -> { + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + String saoid = testResourceNamer.randomUuid(); + + BlobSasPermission permissions = new BlobSasPermission().setCreatePermission(true); + BlobServiceSasSignatureValues sasValues + = new BlobServiceSasSignatureValues(expiryTime, permissions).setPreauthorizedAgentObjectId(saoid); + + String sasWithPermissions = oauthContainer.generateUserDelegationSas(sasValues, key); + + BlockBlobAsyncClient blockClient + = instrument(new SpecializedBlobClientBuilder().endpoint(oauthContainer.getBlobContainerUrl()) + .blobName(oauthBlobName) + .sasToken(sasWithPermissions)).buildBlockBlobAsyncClient(); + + return blockClient.upload(DATA.getDefaultFlux(), DATA.getDefaultDataSize()).then(); + }); + + StepVerifier.create(response).verifyComplete(); + + } + // RBAC replication lag @Test public void blobUserDelegationSaoid() { @@ -1484,4 +1515,5 @@ public void blobSasUserDelegationDelegatedTenantIdFail() { e -> assertExceptionStatusCodeAndMessage(e, 403, BlobErrorCode.AUTHENTICATION_FAILED)); }); } + } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 843fa2c8a125..813e7a51582d 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -17,6 +17,7 @@ import com.azure.storage.blob.sas.BlobSasPermission; import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.blob.specialized.AppendBlobClient; +import com.azure.storage.blob.specialized.BlockBlobAsyncClient; import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder; import com.azure.storage.common.implementation.AccountSasImplUtil; @@ -1296,6 +1297,33 @@ public void blobSasImplUtilCanonicalizedResource(String containerName, String bl assertEquals(expectedResource, queryParams.getResource()); } + @Test + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + public void createPermissionUpload() { + BlobServiceClient oauthService = getOAuthServiceClient(); + String oauthContainerName = cc.getBlobContainerName(); + BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(oauthContainerName); + + String oauthBlobName = generateBlobName(); + OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); + + UserDelegationKey key = oauthService.getUserDelegationKey(null, expiryTime); + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + String saoid = testResourceNamer.randomUuid(); + + BlobSasPermission permissions = new BlobSasPermission().setCreatePermission(true); + BlobServiceSasSignatureValues sasValues + = new BlobServiceSasSignatureValues(expiryTime, permissions).setPreauthorizedAgentObjectId(saoid); + + String sasWithPermissions = oauthContainer.generateUserDelegationSas(sasValues, key); + BlockBlobClient blockClient + = instrument(new SpecializedBlobClientBuilder().endpoint(oauthContainer.getBlobContainerUrl()) + .blobName(oauthBlobName) + .sasToken(sasWithPermissions)).buildBlockBlobClient(); + + assertDoesNotThrow(() -> blockClient.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())); + } + private static Stream blobSasImplUtilCanonicalizedResourceSupplier() { return Stream.of( Arguments.of("c", "b", "id", OffsetDateTime.now(), "bs", From ed2be71bb12d5a3f948e08128b7a4c9dd29086c1 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 4 Mar 2026 19:13:00 -0500 Subject: [PATCH 3/7] add test for transfer with create permission --- .../azure/storage/blob/SasClientTests.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 813e7a51582d..4d2e9ff57f60 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -42,10 +42,13 @@ import org.junit.jupiter.params.provider.ValueSource; import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -1324,6 +1327,45 @@ public void createPermissionUpload() { assertDoesNotThrow(() -> blockClient.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())); } + @Test + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + public void transferBlobWithCreatePermission() { + BlobServiceClient oauthService = getOAuthServiceClient(); + String containerName = cc.getBlobContainerName(); + BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(containerName); + + String sourceBlobName = generateBlobName(); + String destinationBlobName = generateBlobName(); + OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); + + // Upload source blob via OAuth client + BlockBlobClient sourceBlob = oauthContainer.getBlobClient(sourceBlobName).getBlockBlobClient(); + sourceBlob.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize()); + + UserDelegationKey key = oauthService.getUserDelegationKey(null, expiryTime); + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + String saoid = testResourceNamer.randomUuid(); + + // Create-only permission for destination blob + BlobSasPermission destinationPermissions = new BlobSasPermission().setCreatePermission(true); + BlobServiceSasSignatureValues sasValues = new BlobServiceSasSignatureValues(expiryTime, destinationPermissions) + .setPreauthorizedAgentObjectId(saoid); + String createPermissionsOnly = oauthContainer.generateUserDelegationSas(sasValues, key); + BlockBlobClient destinationClient + = instrument(new SpecializedBlobClientBuilder().endpoint(oauthContainer.getBlobContainerUrl()) + .blobName(destinationBlobName) + .sasToken(createPermissionsOnly)).buildBlockBlobClient(); + + // Read permission for source blob + BlobSasPermission readPermission = new BlobSasPermission().setReadPermission(true); + BlobServiceSasSignatureValues readValues + = new BlobServiceSasSignatureValues(expiryTime, readPermission).setPreauthorizedAgentObjectId(saoid); + String readSas = oauthContainer.generateUserDelegationSas(readValues, key); + String sourceUrl = sourceBlob.getBlobUrl() + "?" + readSas; + + assertDoesNotThrow(() -> destinationClient.copyFromUrl(sourceUrl)); + } + private static Stream blobSasImplUtilCanonicalizedResourceSupplier() { return Stream.of( Arguments.of("c", "b", "id", OffsetDateTime.now(), "bs", From b85c06b04bed41e8677c72bf28d4d85913a2542b Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 4 Mar 2026 19:20:14 -0500 Subject: [PATCH 4/7] add recording for transferBlobWithCreatePermission --- sdk/storage/azure-storage-blob/assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index 06a80624826d..252d9c11bfed 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_c21aadb9a6" + "Tag": "java/storage/azure-storage-blob_8e17f88016" } From 4334b81cff38dfe282010667f1b09ea26951edc5 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 4 Mar 2026 19:32:00 -0500 Subject: [PATCH 5/7] create commitBlockLIst sync with recording --- sdk/storage/azure-storage-blob/assets.json | 2 +- .../azure/storage/blob/SasClientTests.java | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index 252d9c11bfed..48db88893158 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_8e17f88016" + "Tag": "java/storage/azure-storage-blob_afa540467e" } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 4d2e9ff57f60..40248e3c8072 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -1366,6 +1366,38 @@ public void transferBlobWithCreatePermission() { assertDoesNotThrow(() -> destinationClient.copyFromUrl(sourceUrl)); } + @Test + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + public void commitBlockListWithCreatePermission() { + BlobServiceClient oauthService = getOAuthServiceClient(); + String containerName = cc.getBlobContainerName(); + BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(containerName); + String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); + List blockIds = new ArrayList(); + blockIds.add(blockId); + + String destinationBlobName = generateBlobName(); + OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); + + UserDelegationKey key = oauthService.getUserDelegationKey(null, expiryTime); + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + String saoid = testResourceNamer.randomUuid(); + + // Create-only permission for destination blob + BlobSasPermission destinationPermissions = new BlobSasPermission().setCreatePermission(true); + BlobServiceSasSignatureValues sasValues = new BlobServiceSasSignatureValues(expiryTime, destinationPermissions) + .setPreauthorizedAgentObjectId(saoid); + String createPermissionsOnly = oauthContainer.generateUserDelegationSas(sasValues, key); + BlockBlobClient destinationClient + = instrument(new SpecializedBlobClientBuilder().endpoint(oauthContainer.getBlobContainerUrl()) + .blobName(destinationBlobName) + .sasToken(createPermissionsOnly)).buildBlockBlobClient(); + + destinationClient.stageBlock(blockId, DATA.getDefaultInputStream(), DATA.getDefaultDataSize()); + + assertDoesNotThrow(() -> destinationClient.commitBlockList(blockIds, false)); + } + private static Stream blobSasImplUtilCanonicalizedResourceSupplier() { return Stream.of( Arguments.of("c", "b", "id", OffsetDateTime.now(), "bs", From 16f9fb25ce6e359854433358762284975ce544d9 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 4 Mar 2026 20:15:02 -0500 Subject: [PATCH 6/7] create transfer async with recording --- sdk/storage/azure-storage-blob/assets.json | 2 +- .../storage/blob/SasAsyncClientTests.java | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index 48db88893158..ee4b2246947c 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_afa540467e" + "Tag": "java/storage/azure-storage-blob_8942d332d5" } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 0840b8c4aba9..758f669696ee 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -22,6 +22,7 @@ import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.blob.specialized.AppendBlobAsyncClient; import com.azure.storage.blob.specialized.BlockBlobAsyncClient; +import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder; import com.azure.storage.common.implementation.AccountSasImplUtil; import com.azure.storage.common.implementation.Constants; @@ -50,10 +51,13 @@ import reactor.util.function.Tuples; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -614,6 +618,51 @@ public void createPermissionUpload() { } + @Test + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + public void transferBlobWithCreatePermission() { + BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); + String containerName = ccAsync.getBlobContainerName(); + BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(containerName); + + String sourceBlobName = generateBlobName(); + String destinationBlobName = generateBlobName(); + OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); + + // Upload source blob via OAuth client + BlockBlobAsyncClient sourceBlob = oauthContainer.getBlobAsyncClient(sourceBlobName).getBlockBlobAsyncClient(); + sourceBlob.upload(DATA.getDefaultFlux(), DATA.getDefaultDataSize()).block(); + + Mono response = oauthService.getUserDelegationKey(null, expiryTime).flatMap(key -> { + + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + String saoid = testResourceNamer.randomUuid(); + + // Create-only permission for destination blob + BlobSasPermission destinationPermissions = new BlobSasPermission().setCreatePermission(true); + BlobServiceSasSignatureValues sasValues + = new BlobServiceSasSignatureValues(expiryTime, destinationPermissions) + .setPreauthorizedAgentObjectId(saoid); + String createPermissionsOnly = oauthContainer.generateUserDelegationSas(sasValues, key); + BlockBlobAsyncClient destinationClient + = instrument(new SpecializedBlobClientBuilder().endpoint(oauthContainer.getBlobContainerUrl()) + .blobName(destinationBlobName) + .sasToken(createPermissionsOnly)).buildBlockBlobAsyncClient(); + + // Read permission for source blob + BlobSasPermission readPermission = new BlobSasPermission().setReadPermission(true); + BlobServiceSasSignatureValues readValues + = new BlobServiceSasSignatureValues(expiryTime, readPermission).setPreauthorizedAgentObjectId(saoid); + String readSas = oauthContainer.generateUserDelegationSas(readValues, key); + String sourceUrl = sourceBlob.getBlobUrl() + "?" + readSas; + + return destinationClient.copyFromUrl(sourceUrl).then(); + }); + + StepVerifier.create(response).verifyComplete(); + } + + // RBAC replication lag @Test public void blobUserDelegationSaoid() { From 9afbd99c06c0923e30646613863dc5805038e063 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 4 Mar 2026 20:54:21 -0500 Subject: [PATCH 7/7] finish commitblocklist with permission and recording --- sdk/storage/azure-storage-blob/assets.json | 2 +- .../storage/blob/SasAsyncClientTests.java | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index ee4b2246947c..b43d2d75931c 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_8942d332d5" + "Tag": "java/storage/azure-storage-blob_8b827141a3" } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 758f669696ee..dc648e59e676 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -22,7 +22,6 @@ import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.blob.specialized.AppendBlobAsyncClient; import com.azure.storage.blob.specialized.BlockBlobAsyncClient; -import com.azure.storage.blob.specialized.BlockBlobClient; import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder; import com.azure.storage.common.implementation.AccountSasImplUtil; import com.azure.storage.common.implementation.Constants; @@ -662,6 +661,45 @@ public void transferBlobWithCreatePermission() { StepVerifier.create(response).verifyComplete(); } + @Test + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + public void commitBlockListWithCreatePermission() { + BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); + String containerName = ccAsync.getBlobContainerName(); + BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(containerName); + String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); + List blockIds = new ArrayList<>(); + blockIds.add(blockId); + + String destinationBlobName = generateBlobName(); + OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); + + Mono response = oauthService.getUserDelegationKey(null, expiryTime).flatMap(key -> { + + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + String saoid = testResourceNamer.randomUuid(); + + // Create-only permission for destination blob + BlobSasPermission destinationPermissions = new BlobSasPermission().setCreatePermission(true); + BlobServiceSasSignatureValues sasValues + = new BlobServiceSasSignatureValues(expiryTime, destinationPermissions) + .setPreauthorizedAgentObjectId(saoid); + String createPermissionsOnly = oauthContainer.generateUserDelegationSas(sasValues, key); + BlockBlobAsyncClient destinationClient + = instrument(new SpecializedBlobClientBuilder().endpoint(oauthContainer.getBlobContainerUrl()) + .blobName(destinationBlobName) + .sasToken(createPermissionsOnly)).buildBlockBlobAsyncClient(); + + Flux data = DATA.getDefaultFlux(); + + return destinationClient.stageBlock(blockId, data, DATA.getDefaultDataSize()) + .then(destinationClient.commitBlockList(blockIds, false)) + .then(); + }); + + StepVerifier.create(response).verifyComplete(); + + } // RBAC replication lag @Test