Reputation: 2042
I am trying to make a put request to Azure storage, basically changing the storage properties. While I can able to make the GET request work by following the tutorial here https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key#Subheading2 but I dont see a proper one to construct a PUT request in there.
So, while searching I got this but with the get, can't connect to azure file service REST api by python but this is again with a GET request. for the PUT request am always getting HTTP 403, I am not sure where it fails. here is the modified code from the link to depict what I am doing in my code.
import requests
import datetime
import hmac
import hashlib
import base64
storage_account_name = 'strtest'
storage_account_key = 'key'
api_version = '2016-05-31'
request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
string_params = {
'verb': 'PUT',
'Content-Encoding': '',
'Content-Language': '',
'Content-Length': '',
'Content-MD5': '',
'Content-Type': 'application/xml',
'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 + '/\ncomp:properties\nrestype:service'
}
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/?restype=service&comp=properties')
data = """<StorageServiceProperties></StorageServiceProperties>"""
r = requests.put(url, headers = headers, data = data)
print(r.content)
The content am trying to send is in XML format. While the code is working on GET request PUT is not.
Upvotes: 4
Views: 3204
Reputation: 55
I faced the same issue from my Python script, even after I had already added the Content-Length and Content-Type.
But the error went away after I added another header:
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
You can put your own value as the "User-Agent:.
Upvotes: 0
Reputation: 2042
Here is the working code.
import requests
import datetime
import hmac
import hashlib
import base64
storage_account_name = 'acc_name'
storage_account_key = 'ac_key'
api_version = '2018-03-28'
request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
data = "<StorageServiceProperties></StorageServiceProperties>"
content_len = str(len(data))
string_params = {
'verb': 'PUT',
'Content-Encoding': '',
'Content-Language': '',
'Content-Length': content_len,
'Content-MD5': '',
'Content-Type': 'application/xml',
'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 + '/\ncomp:properties\nrestype:service'
}
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,
'Content-Type': 'application/xml',
'Content-Length': content_len,
'Authorization' : ('SharedKey ' + storage_account_name + ':' + signed_string)
}
url = ('https://' + storage_account_name + '.blob.core.windows.net/?restype=service&comp=properties')
data = "<StorageServiceProperties></StorageServiceProperties>"
r = requests.put(url, headers = headers, data=data)
print(r.content)
Upvotes: 3
Reputation: 17790
Besides Content-Type
, for a put request, you also need to fill Content-Length
in string_params as corresponding header is probably set by sdk automatically.
Upvotes: 3