Search code examples
azureutf-8azure-blob-storagesha256azure-storage-account

Creating Azure storage authorization header using python


I am trying to create the Authorization header for using Azure storage REST APIs. What a nightmare. The reason I am trying to do this is because I am trying to use a workflow builder (Alteryx) to call the API so my only programmatic options are Alteryx, python, or command line.

I think I'm close, but I just don't understand these last three lines of code, following this article - https://learn.microsoft.com/en-us/azure/storage/common/storage-rest-api-auth?toc=%2fazure%2fstorage%2fblobs%2ftoc.json

// Now turn it into a byte array. byte[] SignatureBytes = Encoding.UTF8.GetBytes(MessageSignature);

// Create the HMACSHA256 version of the storage key. HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(storageAccountKey));

// Compute the hash of the SignatureBytes and convert it to a base64 string. string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));

So if I follow this correctly, I have to create a SHA256 version of the storage key but then I make a SHA256 hash of the SHA256 hash of the signaturebytes?

I'm current googling and not getting far, but basically trying to do the same thing above in .net using python.


Solution

  • In python, you can just use this line of code:

    signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
    

    Here is the complete code of using List blobs api:

    import requests
    import datetime
    import hmac
    import hashlib
    import base64
    
    storage_account_name = 'xx'
    storage_account_key = 'xxx'
    container_name='aa1'
    api_version = '2017-07-29'
    request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    
    string_params = {
        'verb': 'GET',
        'Content-Encoding': '',
        'Content-Language': '',
        'Content-Length': '',
        'Content-MD5': '',
        'Content-Type': '',
        'Date': '',
        'If-Modified-Since': '',
        'If-Match': '',
        'If-None-Match': '',
        'If-Unmodified-Since': '',
        'Range': '',
        'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-version:' + api_version + '\n',
        'CanonicalizedResource': '/' + storage_account_name +'/'+container_name+ '\ncomp:list\nrestype:container'
    }
    
    string_to_sign = (string_params['verb'] + '\n' 
                      + string_params['Content-Encoding'] + '\n'
                      + string_params['Content-Language'] + '\n'
                      + string_params['Content-Length'] + '\n'
                      + string_params['Content-MD5'] + '\n' 
                      + string_params['Content-Type'] + '\n' 
                      + string_params['Date'] + '\n' 
                      + string_params['If-Modified-Since'] + '\n'
                      + string_params['If-Match'] + '\n'
                      + string_params['If-None-Match'] + '\n'
                      + string_params['If-Unmodified-Since'] + '\n'
                      + string_params['Range'] + '\n'
                      + string_params['CanonicalizedHeaders']
                      + string_params['CanonicalizedResource'])
    
    signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
    
    headers = {
        'x-ms-date' : request_time,
        'x-ms-version' : api_version,
        'Authorization' : ('SharedKey ' + storage_account_name + ':' + signed_string)
    }
    
    url = ('https://' + storage_account_name + '.blob.core.windows.net/'+container_name+'?restype=container&comp=list')
    
    r = requests.get(url, headers = headers)
    print(r.status_code)
    print('\n\n'+r.text)
    

    Test result:

    enter image description here