azure-sdk-for-python: [azure-storage-blob] Blob uploads and downloads give authentication error when certain characters are in the blob path

  • Package Name: azure-storage-blob
  • Package Version: 12.3.0
  • Operating System: Ubuntu Linux 16.04.6
  • Python Version: 3.8.2

Describe the bug An authentication error “The MAC signature found in the HTTP request ‘<snip>’ is not the same as any computed signature. Server used following string to sign: ‘<snip>’” occurs when the following characters are in the blob path name:

! $ & ' ( ) * , : ; = @

To Reproduce Steps to reproduce the behavior:

  1. Blob storage with or without data lake
  2. Create an empty container (e.g. test)
  3. Upload/create a blob to a path with special character (e.g. /test/test=/test.txt)
  4. You will receive an authentication error

Expected behavior Upload should work as expected. Creating the same folder structure in the portal or locally and then uploading using the azcopy tool works.

Additional context Example code, to make it run you need the following:

  • empty container called test
  • pupulated container called azcopy with the following directory structure:
/test`/test.txt
/test^/test.txt
/test~/test.txt
/test</test.txt
/test=/test.txt
/test>/test.txt
/test|/test.txt
/test_/test.txt
/test-/test.txt
/test,/test.txt
/test;/test.txt
/test:/test.txt
/test!/test.txt
/test?/test.txt
/test./test.txt
/test'/test.txt
/test"/test.txt
/test(/test.txt
/test)/test.txt
/test[/test.txt
/test]/test.txt
/test{/test.txt
/test}/test.txt
/test@/test.txt
/test$/test.txt
/test*/test.txt
/test&/test.txt
/test#/test.txt
/test%/test.txt
/test+/test.txt
/test2=/test.txt
import os
import asyncio
from azure.core.exceptions import ClientAuthenticationError

TEST_FILE = "test.txt"
UPLOAD_CONTAINER_NAME = "test"
DOWNLOAD_CONTAINER_NAME = "azcopytest"

connection_string = os.getenv("AZURE_STORAGE_CONNECTION_STRING")


async def create_blob_in_folder(folder, debug_info=False):

    from azure.storage.blob.aio import BlobServiceClient

    blob_service_client = BlobServiceClient.from_connection_string(connection_string)

    try:
        async with blob_service_client:
            container_client = blob_service_client.get_container_client(
                UPLOAD_CONTAINER_NAME
            )

            with open(TEST_FILE, "rb") as data:
                blob_client = container_client.get_blob_client(
                    "{}/test.txt".format(folder)
                )
                await blob_client.upload_blob(data, blob_type="BlockBlob")
    except ClientAuthenticationError as e:
        print("uploading to folder: {}".format(folder), "Authentication error")
        if debug_info:
            print(e)
    else:
        print("uploading to folder: {}".format(folder), "Success")


async def download_blob_from_folder(folder, debug_info=False):

    from azure.storage.blob.aio import BlobServiceClient

    blob_service_client = BlobServiceClient.from_connection_string(connection_string)

    try:
        async with blob_service_client:
            container_client = blob_service_client.get_container_client(
                DOWNLOAD_CONTAINER_NAME
            )

            blob_client = container_client.get_blob_client("{}/test.txt".format(folder))
            stream = await blob_client.download_blob()
            data = await stream.readall()
    except ClientAuthenticationError as e:
        print("uploading to folder: {}".format(folder), "Authentication error")
        if debug_info:
            print(e)
    else:
        print("downloading from folder: {}".format(folder), "Success")


async def main():
    await create_blob_in_folder("test!")
    await create_blob_in_folder('test"')
    await create_blob_in_folder("test#")
    await create_blob_in_folder("test$")
    await create_blob_in_folder("test%")
    await create_blob_in_folder("test&")
    await create_blob_in_folder("test'")
    await create_blob_in_folder("test(")
    await create_blob_in_folder("test)")
    await create_blob_in_folder("test*")
    await create_blob_in_folder("test+")
    await create_blob_in_folder("test,")
    await create_blob_in_folder("test-")
    await create_blob_in_folder("test.")
    await create_blob_in_folder("test:")
    await create_blob_in_folder("test;")
    await create_blob_in_folder("test<")
    await create_blob_in_folder("test=")
    await create_blob_in_folder("test>")
    await create_blob_in_folder("test?")
    await create_blob_in_folder("test@")
    await create_blob_in_folder("test[")
    await create_blob_in_folder("test]")
    await create_blob_in_folder("test^")
    await create_blob_in_folder("test_")
    await create_blob_in_folder("test`")
    await create_blob_in_folder("test{")
    await create_blob_in_folder("test|")
    await create_blob_in_folder("test}")
    await create_blob_in_folder("test~")
    await create_blob_in_folder("test2=", True)

    await download_blob_from_folder("test!")
    await download_blob_from_folder('test"')
    await download_blob_from_folder("test#")
    await download_blob_from_folder("test$")
    await download_blob_from_folder("test%")
    await download_blob_from_folder("test&")
    await download_blob_from_folder("test'")
    await download_blob_from_folder("test(")
    await download_blob_from_folder("test)")
    await download_blob_from_folder("test*")
    await download_blob_from_folder("test+")
    await download_blob_from_folder("test,")
    await download_blob_from_folder("test-")
    await download_blob_from_folder("test.")
    await download_blob_from_folder("test:")
    await download_blob_from_folder("test;")
    await download_blob_from_folder("test<")
    await download_blob_from_folder("test=")
    await download_blob_from_folder("test>")
    await download_blob_from_folder("test?")
    await download_blob_from_folder("test@")
    await download_blob_from_folder("test[")
    await download_blob_from_folder("test]")
    await download_blob_from_folder("test^")
    await download_blob_from_folder("test_")
    await download_blob_from_folder("test`")
    await download_blob_from_folder("test{")
    await download_blob_from_folder("test|")
    await download_blob_from_folder("test}")
    await download_blob_from_folder("test~")
    await download_blob_from_folder("test2=", True)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Output:

uploading to folder: test! Authentication error
uploading to folder: test" Success
uploading to folder: test# Success
uploading to folder: test$ Authentication error
uploading to folder: test% Success
uploading to folder: test& Authentication error
uploading to folder: test' Authentication error
uploading to folder: test( Authentication error
uploading to folder: test) Authentication error
uploading to folder: test* Authentication error
uploading to folder: test+ Success
uploading to folder: test, Authentication error
uploading to folder: test- Success
uploading to folder: test. Success
uploading to folder: test: Authentication error
uploading to folder: test; Authentication error
uploading to folder: test< Success
uploading to folder: test= Authentication error
uploading to folder: test> Success
uploading to folder: test? Success
uploading to folder: test@ Authentication error
uploading to folder: test[ Success
uploading to folder: test] Success
uploading to folder: test^ Success
uploading to folder: test_ Success
uploading to folder: test` Success
uploading to folder: test{ Success
uploading to folder: test| Success
uploading to folder: test} Success
uploading to folder: test~ Success
uploading to folder: test2= Authentication error
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:<snip>
Time:<snip>
ErrorCode:AuthenticationFailed
Error:None
AuthenticationErrorDetail:The MAC signature found in the HTTP request '<snip>' is not the same as any computed signature. Server used following string to sign: '<snip>'.
downloading from folder: test! Authentication error
downloading from folder: test" Success
downloading from folder: test# Success
downloading from folder: test$ Authentication error
downloading from folder: test% Success
downloading from folder: test& Authentication error
downloading from folder: test' Authentication error
downloading from folder: test( Authentication error
downloading from folder: test) Authentication error
downloading from folder: test* Authentication error
downloading from folder: test+ Success
downloading from folder: test, Authentication error
downloading from folder: test- Success
downloading from folder: test. Success
downloading from folder: test: Authentication error
downloading from folder: test; Authentication error
downloading from folder: test< Success
downloading from folder: test= Authentication error
downloading from folder: test> Success
downloading from folder: test? Success
downloading from folder: test@ Authentication error
downloading from folder: test[ Success
downloading from folder: test] Success
downloading from folder: test^ Success
downloading from folder: test_ Success
downloading from folder: test` Success
downloading from folder: test{ Success
downloading from folder: test| Success
downloading from folder: test} Success
downloading from folder: test~ Success
downloading from folder: test2= Authentication error
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:<snip>
Time:<snip>
ErrorCode:AuthenticationFailed
Error:None
AuthenticationErrorDetail:The MAC signature found in the HTTP request '<snip>' is not the same as any computed signature. Server used following string to sign: '<snip>'.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 21 (13 by maintainers)

Most upvoted comments

I already created a wheel in my fork. Thanks anyway!

Hi @aviramha and @blokje

We will take a look if we can find a workaround! Sorry about this