I am trying to make a PUT blob request using azurite. Using the following values.
account = "devstoreaccount1"
key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
api_version = "2021-06-08"
block_type = "BlockBlob"
the string I am trying to sign then becomes this:
string_to_sign = (f"PUT\n" # HTTP method
f"\n" # Content-Encoding
f"\n" # Content-Language
f"0\n" # Content-Length
f"\n" # Content-MD5
f"\n" # Content-Type
f"\n" # Date
f"\n" # If-Modified-Since
f"\n" # If-Match
f"\n" # If-None-Match
f"\n" # If-Unmodified-Since
f"\n" # Range
f"x-ms-date:{date_str}\n"
f"x-ms-version:{api_version}\n"
f"x-ms-blob-type:{block_type}\n"
f"/{account}/{container}/{blob}")
but when making the requests I get a 403 error (server failed to authenticate) everytime. anyone know what I am missing?
the error I get is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Error>
<Code>AuthorizationFailure</Code>
<Message>Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature.
RequestId:35ee2117-c03a-417d-84dd-be4a0b4d1163
Time:2024-10-29T16:04:11.193Z</Message>
</Error>
The python code I am using
import hmac
import hashlib
import base64
from datetime import datetime
def main():
authorization, date, api_version = blobs()
print(f"Authorization: {authorization}")
print(f"Date: {date}")
print(f"API Version: {api_version}")
input("Press any key to exit...")
def blobs():
account = "devstoreaccount1"
key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" # Replace with your access key
container = "container"
blob = "file.txt"
api_version = "2021-06-08"
block_type = "BlockBlob"
dt = datetime.utcnow()
date_str = dt.strftime('%a, %d %b %Y %H:%M:%S GMT')
string_to_sign = (f"PUT\n" # HTTP method
f"\n" # Content-Encoding
f"\n" # Content-Language
f"0\n" # Content-Length
f"\n" # Content-MD5
f"\n" # Content-Type
f"\n" # Date
f"\n" # If-Modified-Since
f"\n" # If-Match
f"\n" # If-None-Match
f"\n" # If-Unmodified-Since
f"\n" # Range
f"x-ms-date:{date_str}\n"
f"x-ms-version:{api_version}\n"
f"x-ms-blob-type:{block_type}\n"
f"/{account}/{account}/{container}/{blob}")
signature = sign_this(string_to_sign, key)
# Updated Authorization format
authorization = f"SharedKey {account}:{signature}"
return authorization, date_str, api_version
def sign_this(string_to_sign, key):
decoded_key = base64.b64decode(key)
string_to_sign = string_to_sign.encode('utf-8')
hmac_sha256 = hmac.new(decoded_key, string_to_sign, hashlib.sha256)
signature = base64.b64encode(hmac_sha256.digest()).decode('utf-8')
return signature
if __name__ == "__main__":
main()
I have then been taking the output of this and replacing the it with the value of the Authorization header in postman
Azurite Shared key generation for PUT operation fails with 403
You can use the below code that upload the file to your attached emulator with azurite using Python alone without postman.
Code:
import hmac
import hashlib
import base64
from datetime import datetime
import requests
import os
def main():
file_path = <path of your file>
with open(file_path, 'rb') as file:
blob_content = file.read()
content_length = str(len(blob_content))
authorization, date, api_version = generate_authorization(content_length, file_path)
account = "devstoreaccount1"
container = <container name>
blob = os.path.basename(file_path)
url = f"http://127.0.0.1:10000/{account}/{container}/{blob}"
headers = {
"Authorization": authorization,
"x-ms-date": date,
"x-ms-version": api_version,
"x-ms-blob-type": "BlockBlob", # Specify blob type as BlockBlob
"Content-Length": content_length,
"Content-Type": "application/octet-stream"
}
print("Request Headers:")
for key, value in headers.items():
print(f"{key}: {value}")
response = requests.put(url, headers=headers, data=blob_content)
print(f"\nStatus Code: {response.status_code}")
print(f"Response: {response.text}")
print("\nResponse Headers:")
for key, value in response.headers.items():
print(f"{key}: {value}")
def generate_authorization(content_length, file_path):
account = "devstoreaccount1"
key = "xxxxxxx"
container = "source-container"
blob = os.path.basename(file_path)
api_version = "2021-06-08"
dt = datetime.utcnow()
date_str = dt.strftime('%a, %d %b %Y %H:%M:%S GMT')
string_to_sign = (f"PUT\n" # HTTP method
f"\n" # Content-Encoding
f"\n" # Content-Language
f"{content_length}\n" # Content-Length
f"\n" # Content-MD5
f"application/octet-stream\n" # Content-Type
f"\n" # Date
f"\n" # If-Modified-Since
f"\n" # If-Match
f"\n" # If-None-Match
f"\n" # If-Unmodified-Since
f"\n" # Range
f"x-ms-blob-type:BlockBlob\n"
f"x-ms-date:{date_str}\n"
f"x-ms-version:{api_version}\n"
f"/{account}/{account}/{container}/{blob}") # Update path format
signature = sign_this(string_to_sign, key)
authorization = f"SharedKey {account}:{signature}"
return authorization, date_str, api_version
def sign_this(string_to_sign, key):
decoded_key = base64.b64decode(key)
string_to_sign = string_to_sign.encode('utf-8')
hmac_sha256 = hmac.new(decoded_key, string_to_sign, hashlib.sha256)
signature = base64.b64encode(hmac_sha256.digest()).decode('utf-8')
return signature
if __name__ == "__main__":
main()
Output:
Request Headers:
Authorization: SharedKey devstoreaccount1:IDUuFS55xxxxxxx
x-ms-date: Wed, 30 Oct 2024 04:20:06 GMT
x-ms-version: 2021-06-08
x-ms-blob-type: BlockBlob
Content-Length: 88731
Content-Type: application/octet-stream
Status Code: 201
Response:
Response Headers:
Server: Azurite-Blob/3.31.0
etag: "0xxx49A0"
last-modified: Wed, 30 Oct 2024 04:20:06 GMT
content-md5: 0wxxx0Z/aA==
x-ms-request-id: 4fc5dxxxx8-88aa-a3baba7b621c
x-ms-version: 2024-08-04
date: Wed, 30 Oct 2024 04:20:06 GMT
x-ms-request-server-encrypted: true
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 0
Storage explorer: