Describe the bug
Failed to delete multiple blobs using the Blob Batch API.
(This doesn't work using the REST API as well)
Expected behavior
Successfully deleting the requested blobs
Actual behavior (include Exception or Stack Trace)
Exception:
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:dc375805-401e-000a-4717-22235b000000
Time:2020-05-04T13:22:52.7605123Z
Status: 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)
ErrorCode: AuthenticationFailed
Additional Information:
AuthenticationErrorDetail: Signature did not match. String to sign used was racwdl
2020-05-10T13:19:15Z
/blob/xxxxxxxxxxxx/$root
c147e641-9806-49d7-9768-3dd744dc1033
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
2020-05-04T13:09:15Z
2020-05-10T13:19:15Z
b
2019-07-07
2019-07-07
c
Headers:
Server: Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0
x-ms-error-code: AuthenticationFailed
x-ms-request-id: dc375805-401e-000a-4717-22235b000000
x-ms-version: 2019-07-07
x-ms-client-request-id: 05d893ad-3666-4d87-83c1-8491a1bf6177
Date: Mon, 04 May 2020 13:22:51 GMT
Content-Length: 628
Content-Type: application/xml
To Reproduce
var service = new BlobServiceClient(new Uri(sasUrl));
var container = service.GetBlobContainerClient("sample-container");
// Create three blobs named "foo", "bar", and "baz"
var foo = container.GetBlobClient("shared/db1/foo");
var bar = container.GetBlobClient("shared/db1/bar");
var baz = container.GetBlobClient("shared/db1/baz");
await foo.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("Foo!")));
await bar.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("Bar!")));
await baz.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("Baz!")));
// Delete all three blobs at once
var batch = service.GetBlobBatchClient();
await batch.DeleteBlobsAsync(new Uri[] { foo.Uri, bar.Uri, baz.Uri });
Environment:
@grisha-kotler Thanks for the issue report, we will shortly get back to you with a detailed response.
Hi @grisha-kotler, unfortunate I'm not able to reproduce. I suspect that maybe the SAS URL you are using doesn't have delete permissions. Could you post a code snippet showing how you generated your SAS token?
Hi @seanmcc-msft, I used User delegation SAS.
Could you post a code snippet showing how you generated your User Delegation SAS?
var accountName = File.ReadAllText("c:\\work\\azureFiles\\account.txt");
var containerName = File.ReadAllText("c:\\work\\azureFiles\\container.txt");
var clientId = File.ReadAllText("c:\\work\\azureFiles\\clientid.txt");
var clientSecret = File.ReadAllText("c:\\work\\azureFiles\\clientsecret.txt");
var tenantId = File.ReadAllText("c:\\work\\azureFiles\\tenantid.txt");
string blobEndpoint = string.Format("https://{0}.blob.core.windows.net", accountName);
BlobServiceClient blobServiceClient = new BlobServiceClient(new Uri(blobEndpoint),
new ClientSecretCredential(tenantId, clientId, clientSecret));
// Get a user delegation key for the Blob service that's valid for seven days.
// You can use the key to generate any number of shared access signatures over the lifetime of the key.
UserDelegationKey key = blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow,DateTimeOffset.UtcNow.AddDays(7));
// Read the key's properties.
Console.WriteLine("User delegation key properties:");
Console.WriteLine("Key signed start: {0}", key.SignedStartsOn);
Console.WriteLine("Key signed expiry: {0}", key.SignedExpiresOn);
Console.WriteLine("Key signed object ID: {0}", key.SignedObjectId);
Console.WriteLine("Key signed tenant ID: {0}", key.SignedTenantId);
Console.WriteLine("Key signed service: {0}", key.SignedService);
Console.WriteLine("Key signed version: {0}", key.SignedVersion);
// Create a SAS token that's valid for one hour.
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
BlobContainerName = containerName,
Resource = "c",
ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
};
// Specify read permissions for the SAS.
sasBuilder.SetPermissions(BlobSasPermissions.All);
// Use the key to get the SAS token.
string sasToken = sasBuilder.ToSasQueryParameters(key, accountName).ToString();
// Construct the full URI, including the SAS token.
UriBuilder fullUri = new UriBuilder()
{
Scheme = "https",
Host = string.Format("{0}.blob.core.windows.net", accountName),
Path = string.Format("{0}", containerName),
Query = sasToken
};
Console.WriteLine("User delegation SAS URI: {0}", fullUri);
Console.WriteLine();
var sasUri = fullUri.Uri;
Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @xgithubtriage.
@grisha-kotler, I can repo the issue. I'm going to talk to some colleagues to confirm my understanding of how SAS is supposed to work with Batch and get back to you.
Hi @grisha-kotler, unfortunately Batch does not support User Delegation SAS, the only type of SAS it supports is Account SAS.
I'm going to close this issue, but feel free to reopen if you have further questions.
Will it be supported in the future?
If not, can this be added in your docs (https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch)?
I don't think it will. I have a PR in an internal repro updating https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch to mention that only Account SAS is supported.
Most helpful comment
I don't think it will. I have a PR in an internal repro updating https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch to mention that only Account SAS is supported.