【问题标题】:Getting 403 authorisation error when try to release Azure container lease尝试释放 Azure 容器租约时出现 403 授权错误
【发布时间】:2020-04-20 23:08:43
【问题描述】:

以下代码已根据帮助 cmets 修复。现在允许我释放容器的租约,假设您知道租约 ID。

我一直使用 Azure 作为大量文件的存档备份。我认为这对日常使用没有太大影响,但我不小心在门户中的容器上点击了“获取租约”选项。门户中仅有的两个选项是获取和中断,没有“释放”选项。

我正在尝试重新使用 Python,并认为这是一种通过尝试与 Azure API 交互来练习的可能性。

[此链接][1] 构成了 95% 的代码(检索属性)。使用我的凭据 (a 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)

我通过进入门户获得了租约 ID,打破了租约,然后获得了新的租约。

我收到一个 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

【问题讨论】:

    标签: python azure azure-blob-storage


    【解决方案1】:

    您的代码存在一些问题,因此您会收到此错误。

    首先,您的CanonicalizedHeaders 中没有包含x-ms-lease-idx-ms-lease-action

    来自文档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 存在问题。目前它缺少容器名称,并且 comprestype 查询参数的值不正确。

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

    最后你的网址应该是:

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

    目前缺少容器名称。

    请参阅此处的租赁容器 REST API 文档:https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container

    此外,您实际上不必使用 REST API,有一个用于 Azure 存储的 Python SDK,它是此 REST API 的包装器。您可以在此处找到有关 SDK 的更多信息:https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/storage


    更新

    在您更新的代码中发现了一个问题。在您的string_to_sign 中,您将Content-Type 包含为application/xml,但同样不包含在您的请求标头中。这会导致您的签名不匹配。在headers 定义中添加Content-Type 请求标头或在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)
    

    【讨论】:

    • 感谢您的反馈。烦人的是,我仍然遇到同样的错误。
    • 您能否更新您的问题并包含修改后的代码?
    • 已经做了(在我回复您的评论之前)- 我正在尝试编辑我的评论,但在 5 分钟的编辑窗口中没有完成!一个想法 - 签名字符串中的日期是否需要是最初获得租约的日期?我快速浏览了 SDK(请参阅下面的示例代码 URL)。如果这是首选解决方案,我可能会提出一个新问题(因为我遇到了不同的错误)。 github.com/Azure/azure-sdk-for-python/blob/master/sdk/storage/… 再次感谢!
    • 感谢更新代码。我又发现了一个问题。更新了我的答案。关于does the date in the signed string need to be the date that the lease was originally acquired?,答案是否定的。它应该是发出请求的日期/时间,即 UTC 中的当前日期/时间。 HTH。
    • 进行了额外的更改,但仍然没有进展。还有其他建议吗?我仔细检查了所有参数,它们是有效的。否则我将不得不学习如何正确使用 SDK,然后尝试这种方式(或者让我的一位 Java 朋友尝试一下!)。
    猜你喜欢
    • 1970-01-01
    • 2020-12-20
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 2020-05-13
    相关资源
    最近更新 更多