Stg102/put block right branch#48390
Stg102/put block right branch#48390browndav-msft wants to merge 6 commits intoAzure:feature/storage/stg102basefrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds SAS-focused tests in azure-storage-blob to validate Block Blob operations (upload/copy/put block+commit) succeed when a user-delegation SAS token has create-only permission, and updates the recorded test assets tag accordingly.
Changes:
- Add sync tests covering create-only permission for upload, copy-from-URL, and stageBlock+commitBlockList flows.
- Add async equivalents for the same create-only permission scenarios.
- Update
assets.jsontag to point to new/updated recordings.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java | Adds new sync SAS tests for create-only permission covering upload/copy/commit block list scenarios. |
| sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java | Adds new async SAS tests for create-only permission covering upload/copy/commit block list scenarios. |
| sdk/storage/azure-storage-blob/assets.json | Updates the assets tag for test recordings. |
| 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())); | ||
| } | ||
|
|
||
| @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)); |
There was a problem hiding this comment.
These new tests use user delegation key acquisition via getOAuthServiceClient(), which is subject to RBAC replication lag in live runs. In this class, other user-delegation SAS tests are consistently wrapped in liveTestScenarioWithRetry(...) (see blobSasUserDelegation, containerSasUserDelegation, etc.); these should follow the same pattern to avoid intermittent 403s/timeouts in CI.
| 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())); | |
| } | |
| @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)); | |
| liveTestScenarioWithRetry(rbacRetry -> { | |
| 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())); | |
| }); | |
| } | |
| @Test | |
| @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") | |
| public void transferBlobWithCreatePermission() { | |
| liveTestScenarioWithRetry(rbacRetry -> { | |
| 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)); | |
| }); |
| BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); | ||
| BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); | ||
|
|
||
| String oauthBlobName = generateBlobName(); | ||
| OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); | ||
|
|
||
| Mono<Void> 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(); | ||
|
|
There was a problem hiding this comment.
These newly added user-delegation SAS tests aren't wrapped in liveTestScenarioWithRetry(...). This suite generally wraps user-delegation SAS scenarios to mitigate RBAC replication lag (numerous existing tests in this file do so); without the retry wrapper these are more likely to flake in live CI.
| BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); | |
| BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); | |
| String oauthBlobName = generateBlobName(); | |
| OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); | |
| Mono<Void> 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(); | |
| liveTestScenarioWithRetry(() -> { | |
| BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); | |
| BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); | |
| String oauthBlobName = generateBlobName(); | |
| OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); | |
| Mono<Void> 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(); | |
| }); |
| 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<Void> 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(); |
There was a problem hiding this comment.
This new user-delegation SAS copy scenario should be wrapped in liveTestScenarioWithRetry(...) for consistency with the rest of the file and to reduce live-test flakiness from RBAC replication lag when acquiring user delegation keys.
| 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<Void> 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(); | |
| liveTestScenarioWithRetry(() -> { | |
| 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<Void> 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(); | |
| }); |
| BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); | ||
| String containerName = ccAsync.getBlobContainerName(); | ||
| BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(containerName); | ||
| String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); | ||
| List<String> blockIds = new ArrayList<>(); | ||
| blockIds.add(blockId); | ||
|
|
||
| String destinationBlobName = generateBlobName(); | ||
| OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); | ||
|
|
||
| Mono<Void> 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<ByteBuffer> data = DATA.getDefaultFlux(); | ||
|
|
||
| return destinationClient.stageBlock(blockId, data, DATA.getDefaultDataSize()) | ||
| .then(destinationClient.commitBlockList(blockIds, false)) | ||
| .then(); | ||
| }); | ||
|
|
||
| StepVerifier.create(response).verifyComplete(); | ||
|
|
There was a problem hiding this comment.
This new user-delegation SAS block staging/commit test should use the same liveTestScenarioWithRetry(...) wrapper as other user-delegation SAS tests in this file to avoid intermittent failures in live runs due to RBAC replication lag.
| BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); | |
| String containerName = ccAsync.getBlobContainerName(); | |
| BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(containerName); | |
| String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); | |
| List<String> blockIds = new ArrayList<>(); | |
| blockIds.add(blockId); | |
| String destinationBlobName = generateBlobName(); | |
| OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); | |
| Mono<Void> 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<ByteBuffer> data = DATA.getDefaultFlux(); | |
| return destinationClient.stageBlock(blockId, data, DATA.getDefaultDataSize()) | |
| .then(destinationClient.commitBlockList(blockIds, false)) | |
| .then(); | |
| }); | |
| StepVerifier.create(response).verifyComplete(); | |
| liveTestScenarioWithRetry(() -> { | |
| BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); | |
| String containerName = ccAsync.getBlobContainerName(); | |
| BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(containerName); | |
| String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); | |
| List<String> blockIds = new ArrayList<>(); | |
| blockIds.add(blockId); | |
| String destinationBlobName = generateBlobName(); | |
| OffsetDateTime expiryTime = testResourceNamer.now().plusDays(1); | |
| Mono<Void> 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<ByteBuffer> data = DATA.getDefaultFlux(); | |
| return destinationClient.stageBlock(blockId, data, DATA.getDefaultDataSize()) | |
| .then(destinationClient.commitBlockList(blockIds, false)) | |
| .then(); | |
| }); | |
| StepVerifier.create(response).verifyComplete(); | |
| }); |
| 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)); |
There was a problem hiding this comment.
This new user-delegation SAS copy scenario should be wrapped in liveTestScenarioWithRetry(...) (as other user delegation SAS tests in this class are) to mitigate intermittent failures from RBAC replication lag when acquiring/using user delegation keys in live CI.
| 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)); | |
| liveTestScenarioWithRetry(() -> { | |
| 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)); | |
| }); |
| BlobServiceClient oauthService = getOAuthServiceClient(); | ||
| String containerName = cc.getBlobContainerName(); | ||
| BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(containerName); | ||
| String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); | ||
| List<String> blockIds = new ArrayList<String>(); | ||
| 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)); |
There was a problem hiding this comment.
This new stageBlock/commitBlockList user-delegation SAS test should follow the existing pattern in this class and run inside liveTestScenarioWithRetry(...) to reduce live-test flakiness due to RBAC replication lag.
| BlobServiceClient oauthService = getOAuthServiceClient(); | |
| String containerName = cc.getBlobContainerName(); | |
| BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(containerName); | |
| String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); | |
| List<String> blockIds = new ArrayList<String>(); | |
| 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)); | |
| liveTestScenarioWithRetry(() -> { | |
| BlobServiceClient oauthService = getOAuthServiceClient(); | |
| String containerName = cc.getBlobContainerName(); | |
| BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(containerName); | |
| String blockId = Base64.getEncoder().encodeToString("blockid".getBytes(StandardCharsets.UTF_8)); | |
| List<String> blockIds = new ArrayList<String>(); | |
| 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)); | |
| }); |
| 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; |
There was a problem hiding this comment.
Unused import BlockBlobAsyncClient is introduced here but never used in this test class. This will fail Checkstyle's UnusedImports rule; please remove the import (or switch the new sync tests to actually use the async client if that was intended).
| import com.azure.storage.blob.specialized.BlockBlobAsyncClient; |
changes to this putBlock have been moved here because I selected main as the branch to merge into instead of stg102