Skip to content

Instantly share code, notes, and snippets.

@robherley
Last active September 28, 2023 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robherley/64e656f8326b70ecd9cafec65f9e68f4 to your computer and use it in GitHub Desktop.
Save robherley/64e656f8326b70ecd9cafec65f9e68f4 to your computer and use it in GitHub Desktop.
Go Azure Blob SDK Repro

Context

When trying to call Blob Batch Delete API via Azure Go SDK, any requests to blob paths with / don't correctly form the Authorization header that the server is expecting.

Output

2023/09/28 15:10:12 uploading "file1.txt" with content "This can be deleted"
2023/09/28 15:10:12 uploading "foo/bar/file2.txt" with content "This can't be deleted"
2023/09/28 15:10:12 ℹ️  deleting "file1.txt"
2023/09/28 15:10:12 ✅ deleted "file1.txt"
2023/09/28 15:10:12 ℹ️  deleting "foo/bar/file2.txt"
2023/09/28 15:10:12 ❌ DELETE https://robstorage123.blob.core.windows.net/go-sdk-repro/foo/bar/file2.txt
--------------------------------------------------------------------------------
RESPONSE 403: 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
ERROR CODE: AuthenticationFailed
--------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:adcf2208-801e-0025-293f-f249821e3713
Time:2023-09-28T19:10:12.2592251Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request &apos;1Z4JigwM6+SBWsHckBnT/6fzoQWw5GBKZA2ULkYxNM8=&apos; is not the same as any computed signature. Server used following string to sign: &apos;DELETE











x-ms-date:Thu, 28 Sep 2023 19:10:12 GMT
/robstorage123/go-sdk-repro/foo/bar/file2.txt&apos;.</AuthenticationErrorDetail></Error>
--------------------------------------------------------------------------------
package main
import (
"context"
"log"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
)
const (
ContainerName = "go-sdk-repro"
AccountName = ""
AccountKey = ""
URL = ""
)
var (
Files = [][2]string{
{"file1.txt", "This can be deleted"},
{"foo/bar/file2.txt", "This can't be deleted"},
}
)
func authenticate(url string) *azblob.Client {
cred, err := azblob.NewSharedKeyCredential(AccountName, AccountKey)
if err != nil {
log.Fatal(err)
}
client, err := azblob.NewClientWithSharedKeyCredential(url, cred, nil)
if err != nil {
log.Fatal(err)
}
return client
}
func batchDeleteBlobs(ctx context.Context, client *azblob.Client, paths ...string) error {
svcClient := client.ServiceClient()
batchBuilder, err := svcClient.NewBatchBuilder()
if err != nil {
return err
}
for _, path := range paths {
err := batchBuilder.Delete(ContainerName, path, nil)
if err != nil {
return err
}
}
response, err := svcClient.SubmitBatch(ctx, batchBuilder, nil)
if err != nil {
return err
}
for _, res := range response.Responses {
if err := res.Error; err != nil {
return err
}
}
return nil
}
func createContainerWithFiles(ctx context.Context, client *azblob.Client) {
_, err := client.CreateContainer(ctx, ContainerName, nil)
if err != nil && !bloberror.HasCode(err, bloberror.ContainerAlreadyExists) {
log.Fatal(err)
}
for _, file := range Files {
log.Printf("uploading %q with content %q", file[0], file[1])
_, err := client.UploadBuffer(ctx, ContainerName, file[0], []byte(file[1]), nil)
if err != nil {
log.Fatal(err)
}
}
}
func main() {
ctx := context.Background()
client := authenticate(URL)
createContainerWithFiles(ctx, client)
for _, file := range Files {
log.Printf("ℹ️ deleting %q", file[0])
err := batchDeleteBlobs(ctx, client, file[0])
if err != nil {
log.Fatal("❌ ", err)
}
log.Printf("✅ deleted %q", file[0])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment