Получение 403 ошибки авторизации при попытке освободить Azure аренду контейнера - PullRequest
0 голосов
/ 16 апреля 2020

Код ниже исправлен в соответствии с комментариями. Теперь позволяет освободить аренду для контейнера, если вы знаете идентификатор аренды.

Я использовал Azure в качестве архивной резервной копии для большого количества файлов. Я не думаю, что это имеет огромное значение для повседневного использования, но я случайно нажал опцию «приобрести аренду» в своем контейнере на портале. На портале есть только две опции: «получить» и «сломать», нет опции «релиз».

Я пытаюсь вернуться к Python, и рассматривал это как возможность попрактиковаться пытается взаимодействовать с Azure API.

[Эта ссылка] [1] формирует 95% кода (получение свойств). Я получаю успешный ответ при настройке моих учетных данных (202).

Затем я попытался изменить код для освобождения аренды:

import requests
import datetime
import hmac
import hashlib
import base64

storage_account_name = 'storageaccountname'
storage_account_key = 'storateaccountkey'
lease_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
container_name = 'containername'
api_version = '2019-07-07'
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': '',
    'Date': '',
    'If-Modified-Since': '',
    'If-Match': '',
    'If-None-Match': '',
    'If-Unmodified-Since': '',
    'Range': '',
    'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-lease-action:release' + '\nx-ms-lease-id:' + lease_id + '\nx-ms-version:' + api_version + '\n',
    'CanonicalizedResource': '/' + storage_account_name + '/' + container_name + '\ncomp:lease\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'])


print (string_to_sign)

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

headers = {
    'x-ms-date': request_time,
    'x-ms-lease-action': 'release',
    'x-ms-lease-id': lease_id,
    'x-ms-version': api_version,
    'Authorization': ('SharedKey ' + storage_account_name + ':' + signed_string)
}

url = ('https://' + storage_account_name + '.blob.core.windows.net/' + container_name + '?comp=lease&restype=container')

r = requests.put(url, headers = headers)

print (r)
print(r.content)

Я получил идентификатор аренды по входя в портал, нарушая договор аренды и затем приобретая новый.

Я получаю ошибку 403 со следующей информацией (обфусцированной по понятным причинам):

<Response [403]>
b'\xef\xbb\xbf<?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.\nRequestId:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\nTime:2020-04-15T21:59:08.6983006Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request \'XXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXX=\' is not the same as any computed signature. Server used following string to sign: \'PUT\n\n\n53\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 16 Apr 2020 21:46:56 GMT\nx-ms-lease-action:release\nx-ms-lease-id:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\nx-ms-version:2019-07-07\n/storageaccountname/containername\ncomp:lease\nrestype:container\'.</AuthenticationErrorDetail></Error>'

Как можно Я снимаю аренду? Это должно быть что-то, что я делаю в заголовках, но я не могу понять, где.

ОБНОВЛЕНИЕ (Основано на последнем коде, представленном в ответах). Получите эту ошибку сейчас:

Traceback (most recent call last):
  File "Azure_release_lease_2.py", line 49, in <module>
    signed_string = base64.b64encode(hmac.HMAC(base64.b64decode(storage_account_key), string_to_sign, hashlib.sha256).digest())
  File "C:\Program Files (x86)\Python38-32\lib\hmac.py", line 88, in __init__
    self.update(msg)
  File "C:\Program Files (x86)\Python38-32\lib\hmac.py", line 96, in update
    self.inner.update(msg)
TypeError: Unicode-objects must be encoded before hashing

1 Ответ

1 голос
/ 16 апреля 2020

Есть несколько проблем с вашим кодом, из-за которых вы получаете эту ошибку.

Во-первых, вы не включили x-ms-lease-id и x-ms-lease-action в свои CanonicalizedHeaders.

Из документации link:

Получить все заголовки для ресурса, которые начинаются с x-ms-, включая заголовок x-ms-date .

'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-lease-action:acquire' + '\nnx-ms-lease-id:' + theleaseidfromazureportal + '\nx-ms-version:' + api_version + '\n',

Далее, есть проблема с CanonicalizedResource. В настоящее время в нем отсутствует имя контейнера и указаны неправильные значения параметров запроса comp и restype.

'CanonicalizedResource': '/' + storage_account_name + '/' + container_name + '/\ncomp:lease\nrestype:container'

Наконец, ваш URL должен быть:

url = ('https://' + storage_account_name + '.blob.core.windows.net/' + container_name + '?comp=lease&restype=container')

В настоящее время контейнер отсутствует name.

Пожалуйста, обратитесь к документации REST API аренды контейнера здесь: https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container.

Более того, вам не нужно использовать REST API для потребителя, есть Python SDK для Azure Хранилище, которое является оболочкой для этого REST API. Вы можете найти больше информации о SDK здесь: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/storage.


ОБНОВЛЕНИЕ

Найдена одна проблема в вашем обновленном коде. В вашем string_to_sign вы включаете Content-Type как application/xml, однако это не входит в заголовки ваших запросов. Это приводит к тому, что ваши подписи не совпадают. Либо добавьте Content-Type заголовок запроса в вашем headers определении, либо используйте пустую строку в вашем string_to_sign. Это должно решить проблему. Учитывая, что Release Lease запрос не имеет тела запроса, я бы порекомендовал последнее.

ОБНОВЛЕНИЕ 2

Были некоторые другие проблемы с вашим кодом. Пожалуйста, используйте код ниже, он должен работать:

import requests
import datetime
import hmac
import hashlib
import base64

storage_account_name = 'storageaccountname'
storage_account_key = 'storateaccountkey'
lease_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
container_name = 'containername'
api_version = '2019-07-07'
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': '',
    'Date': '',
    'If-Modified-Since': '',
    'If-Match': '',
    'If-None-Match': '',
    'If-Unmodified-Since': '',
    'Range': '',
    'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-lease-action:release' + '\nx-ms-lease-id:' + lease_id + '\nx-ms-version:' + api_version + '\n',
    'CanonicalizedResource': '/' + storage_account_name + '/' + container_name + '\ncomp:lease\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'])


print (string_to_sign)


signed_string = base64.b64encode(hmac.HMAC(base64.b64decode(storage_account_key), string_to_sign, hashlib.sha256).digest())
print (signed_string)

headers = {
    'x-ms-date': request_time,
    'x-ms-lease-action': 'release',
    'x-ms-lease-id': lease_id,
    'x-ms-version': api_version,
    'Authorization': ('SharedKey ' + storage_account_name + ':' + signed_string) 
}

url = ('https://' + storage_account_name + '.blob.core.windows.net/' + container_name + '?comp=lease&restype=container')

#r = requests.put(url, headers = headers, data=data)
r = requests.put(url, headers = headers)

print (r)
print(r.content)
...