| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- # coding=utf-8
- """
- HMAC-SHA256 Authorization 函数单元测试
- 针对 ddns.provider._base.hmac_sha256_authorization 函数的完整测试套件。
- 测试覆盖多种典型使用场景,包括各大云服务商的认证模式,
- 所有期望结果都是预先计算好的,确保测试结果的可复现性。
- Test suite for ddns.provider._base.hmac_sha256_authorization function.
- Covers various typical use cases including authentication patterns of major cloud providers.
- All expected results are pre-calculated to ensure reproducible test results.
- """
- import unittest
- from ddns.provider._base import hmac_sha256_authorization, sha256_hash, hmac_sha256
- class TestHmacSha256Authorization(unittest.TestCase):
- """HMAC-SHA256 Authorization 函数测试类"""
- def test_basic_functionality(self):
- """测试基本功能 - 简单的签名生成"""
- secret_key = "test_secret_key"
- method = "GET"
- path = "/api/test"
- query = ""
- headers = {"Host": "api.example.com", "Date": "20231201T120000Z"}
- body_hash = sha256_hash("") # 空请求体的哈希
- auth_header_template = "TEST {SignedHeaders} {Signature}"
- signing_string_template = "TEST\n{HashedCanonicalRequest}"
- result = hmac_sha256_authorization(
- secret_key=secret_key,
- method=method,
- path=path,
- query=query,
- headers=headers,
- body_hash=body_hash,
- authorization_format=auth_header_template,
- signing_string_format=signing_string_template,
- )
- # 严格验证基本功能测试的完整结果 - 精确匹配
- expected_result = "TEST date;host b5b3ee3c39b1c749faa31c1b5bd3a5609a3e5408dfb7f90eca5ea17d8aeb1ba2"
- self.assertEqual(result, expected_result)
- def test_alibaba_cloud_official_example(self):
- """测试阿里云官方文档示例 - ACS3-HMAC-SHA256签名算法"""
- # 使用阿里云官方文档中的固定参数示例
- # 来源: https://help.aliyun.com/zh/sdk/product-overview/v3-request-structure-and-signature
- secret_key = "YourAccessKeySecret"
- method = "POST"
- path = "/"
- query = "ImageId=win2019_1809_x64_dtc_zh-cn_40G_alibase_20230811.vhd&RegionId=cn-shanghai"
- headers = {
- "host": "ecs.cn-shanghai.aliyuncs.com",
- "x-acs-action": "RunInstances",
- "x-acs-content-sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "x-acs-date": "2023-10-26T10:22:32Z",
- "x-acs-signature-nonce": "3156853299f313e23d1673dc12e1703d",
- "x-acs-version": "2014-05-26",
- }
- body_hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
- auth_header_template = (
- "ACS3-HMAC-SHA256 Credential=YourAccessKeyId," "SignedHeaders={SignedHeaders},Signature={Signature}"
- )
- signing_string_template = "ACS3-HMAC-SHA256\n{HashedCanonicalRequest}"
- result = hmac_sha256_authorization(
- secret_key=secret_key,
- method=method,
- path=path,
- query=query,
- headers=headers,
- body_hash=body_hash,
- authorization_format=auth_header_template,
- signing_string_format=signing_string_template,
- )
- # 严格验证阿里云官方示例的完整授权头 - 精确匹配
- expected_result = (
- "ACS3-HMAC-SHA256 Credential=YourAccessKeyId,"
- "SignedHeaders=host;x-acs-action;x-acs-content-sha256;x-acs-date;x-acs-signature-nonce;x-acs-version,"
- "Signature=06563a9e1b43f5dfe96b81484da74bceab24a1d853912eee15083a6f0f3283c0"
- )
- self.assertEqual(result, expected_result)
- def test_huawei_cloud_official_example(self):
- """测试华为云官方文档示例 - SDK-HMAC-SHA256签名算法"""
- # 使用华为云官方文档中的查询VPC列表示例
- # 来源: https://support.huaweicloud.com/devg-apisign/api-sign-algorithm-002.html
- secret_key = "your_secret_access_key"
- method = "GET"
- path = "/v1/77b6a44cba5143ab91d13ab9a8ff44fd/vpcs/" # 注意官方示例要求以/结尾
- query = "limit=2&marker=13551d6b-755d-4757-b956-536f674975c0"
- headers = {
- "content-type": "application/json",
- "host": "service.region.example.com",
- "x-sdk-date": "20191115T033655Z",
- }
- body_hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
- auth_header_template = (
- "SDK-HMAC-SHA256 Access=your_access_key_id, " "SignedHeaders={SignedHeaders}, Signature={Signature}"
- )
- signing_string_template = "SDK-HMAC-SHA256\n20191115T033655Z\n{HashedCanonicalRequest}"
- result = hmac_sha256_authorization(
- secret_key=secret_key,
- method=method,
- path=path,
- query=query,
- headers=headers,
- body_hash=body_hash,
- authorization_format=auth_header_template,
- signing_string_format=signing_string_template,
- )
- # 严格验证华为云官方示例的完整授权头 - 精确匹配
- expected_result = (
- "SDK-HMAC-SHA256 Access=your_access_key_id, "
- "SignedHeaders=content-type;host;x-sdk-date, "
- "Signature=8037a231336d8904f667c082dd84fc06d7e6c7c278c2d8599db31d14e8ee19f9"
- )
- self.assertEqual(result, expected_result)
- def test_tencent_cloud_official_example(self):
- """测试腾讯云官方文档示例 - TC3-HMAC-SHA256签名算法"""
- # 使用腾讯云官方文档中的固定参数示例
- # 来源: https://cloud.tencent.com/document/api/213/30654
- # 注意:腾讯云使用派生密钥,这里模拟最终的签名密钥
- # Python 2/3 compatible hex to bytes conversion
- hex_string = "b596b923aad85185e2d1f6659d2a062e0a86731226e021e61bfe06f7ed05f5af"
- try:
- final_signing_key = bytes.fromhex(hex_string)
- except AttributeError: # Python 2.7
- final_signing_key = hex_string.decode("hex") # type: ignore[attr-defined]
- method = "POST"
- path = "/"
- query = "" # POST请求,查询字符串为空
- headers = {
- "content-type": "application/json; charset=utf-8",
- "host": "cvm.tencentcloudapi.com",
- "x-tc-action": "describeinstances",
- }
- # 官方示例中的请求体
- # body = '{"Limit": 1, "Filters": [{"Values": ["\\u672a\\u547d\\u540d"], "Name": "instance-name"}]}'
- body_hash = "35e9c5b0e3ae67532d3c9f17ead6c90222632e5b1ff7f6e89887f1398934f064"
- auth_header_template = (
- "TC3-HMAC-SHA256 Credential=AKID********************************/2019-02-25/cvm/tc3_request, "
- "SignedHeaders={SignedHeaders}, Signature={Signature}"
- )
- signing_string_template = "TC3-HMAC-SHA256\n1551113065\n2019-02-25/cvm/tc3_request\n{HashedCanonicalRequest}"
- result = hmac_sha256_authorization(
- secret_key=final_signing_key,
- method=method,
- path=path,
- query=query,
- headers=headers,
- body_hash=body_hash,
- authorization_format=auth_header_template,
- signing_string_format=signing_string_template,
- )
- # 严格验证腾讯云官方示例的完整授权头 - 精确匹配
- expected_result = (
- "TC3-HMAC-SHA256 Credential=AKID********************************/2019-02-25/cvm/tc3_request, "
- "SignedHeaders=content-type;host;x-tc-action, "
- "Signature=10b1a37a7301a02ca19a647ad722d5e43b4b3cff309d421d85b46093f6ab6c4f"
- )
- self.assertEqual(result, expected_result)
- def test_edge_cases(self):
- """测试边界情况"""
- # 测试空字符串参数 - 严格验证
- result1 = hmac_sha256_authorization(
- secret_key="key",
- method="GET",
- path="",
- query="",
- headers={},
- body_hash=sha256_hash(""),
- authorization_format="AUTH {Signature}",
- signing_string_format="{HashedCanonicalRequest}",
- )
- expected_result1 = "AUTH 1d29fda5ce641f10c7e16b1e607ce10f1cad4fd4b071f1b3a4465e051b9a7d6d"
- self.assertEqual(result1, expected_result1)
- # 测试包含特殊字符的参数 - 严格验证
- result2 = hmac_sha256_authorization(
- secret_key="special!@#$%^&*()key",
- method="POST",
- path="/path/with spaces",
- query="param1=value with spaces¶m2=value%20encoded",
- headers={"Custom-Header": "value with spaces and symbols!@#"},
- body_hash=sha256_hash("body with 中文 and symbols"),
- authorization_format="SPECIAL {SignedHeaders} {Signature}",
- signing_string_format="SPECIAL\n{HashedCanonicalRequest}",
- )
- expected_result2 = "SPECIAL custom-header edbf4d68ebb33f305e8d0e2f72c012997543a0bdc6a9f42142d1dfa236fa1dd5"
- self.assertEqual(result2, expected_result2)
- def test_header_normalization(self):
- """测试头部规范化处理"""
- secret_key = "test_key"
- method = "GET"
- path = "/test"
- query = ""
- body_hash = sha256_hash("")
- # 测试头部大小写混合和值的前后空格处理
- headers = {
- "Host": " example.com ", # 前后有空格
- "X-Custom-Header": "value",
- "x-another-header": "another_value",
- "CONTENT-TYPE": "application/json",
- }
- auth_header_template = "TEST {SignedHeaders} {Signature}"
- signing_string_template = "{HashedCanonicalRequest}"
- result = hmac_sha256_authorization(
- secret_key=secret_key,
- method=method,
- path=path,
- query=query,
- headers=headers,
- body_hash=body_hash,
- authorization_format=auth_header_template,
- signing_string_format=signing_string_template,
- )
- # 验证头部已被正确规范化(小写且按字母顺序排列)
- # 模板格式是 "TEST {SignedHeaders} {Signature}",所以直接检查signed headers部分
- self.assertIn("content-type;host;x-another-header;x-custom-header", result)
- def test_reproducible_signatures(self):
- """测试签名结果的可复现性"""
- params = {
- "secret_key": "reproducible_test_key",
- "method": "POST",
- "path": "/api/v1/test",
- "query": "param1=value1¶m2=value2",
- "headers": {"Host": "api.test.com", "Content-Type": "application/json", "Date": "20231201T120000Z"},
- "body_hash": sha256_hash('{"test": "data"}'),
- "authorization_format": "REPRO {SignedHeaders} {Signature}",
- "signing_string_format": "REPRO\n{HashedCanonicalRequest}",
- }
- # 多次调用应该产生相同的结果
- result1 = hmac_sha256_authorization(**params)
- result2 = hmac_sha256_authorization(**params)
- result3 = hmac_sha256_authorization(**params)
- self.assertEqual(result1, result2)
- self.assertEqual(result2, result3)
- # 验证结果包含预期的组件
- self.assertIn("REPRO", result1)
- self.assertIn("content-type;date;host", result1)
- # 提取签名部分进行验证 - 格式是 "REPRO {SignedHeaders} {Signature}"
- parts = result1.split()
- self.assertEqual(len(parts), 3) # "REPRO", signed_headers, signature
- signature_part = parts[2]
- self.assertEqual(len(signature_part), 64) # SHA256签名应该是64个十六进制字符
- self.assertTrue(all(c in "0123456789abcdef" for c in signature_part))
- def test_different_key_types(self):
- """测试不同类型的密钥输入"""
- base_params = {
- "method": "GET",
- "path": "/test",
- "query": "",
- "headers": {"Host": "example.com"},
- "body_hash": sha256_hash(""),
- "authorization_format": "TYPE {Signature}",
- "signing_string_format": "{HashedCanonicalRequest}",
- }
- # 字符串密钥
- result_str = hmac_sha256_authorization(secret_key="string_key", **base_params)
- # 字节密钥
- result_bytes = hmac_sha256_authorization(secret_key=b"string_key", **base_params)
- # 相同内容的字符串和字节密钥应该产生相同的签名
- self.assertEqual(result_str, result_bytes)
- def test_hmac_sha256_basic_functionality(self):
- """测试 hmac_sha256 基础功能"""
- key = "test_key"
- message = "test_message"
- # 测试返回的是 HMAC 对象
- hmac_obj = hmac_sha256(key, message)
- # 验证可以调用 digest() 和 hexdigest() 方法
- digest_result = hmac_obj.digest()
- hexdigest_result = hmac_obj.hexdigest()
- # 验证结果类型
- self.assertIsInstance(digest_result, bytes)
- self.assertIsInstance(hexdigest_result, str)
- # 验证 hexdigest 结果长度 (SHA256 产生64个十六进制字符)
- self.assertEqual(len(hexdigest_result), 64)
- # 验证结果的可复现性
- hmac_obj2 = hmac_sha256(key, message)
- self.assertEqual(hmac_obj.hexdigest(), hmac_obj2.hexdigest())
- def test_hmac_sha256_different_key_types(self):
- """测试 hmac_sha256 不同密钥类型"""
- message = "test_message"
- # 字符串密钥
- hmac_str = hmac_sha256("test_key", message)
- # 字节密钥
- hmac_bytes = hmac_sha256(b"test_key", message)
- # 相同内容的字符串和字节密钥应该产生相同的结果
- self.assertEqual(hmac_str.hexdigest(), hmac_bytes.hexdigest())
- def test_hmac_sha256_different_message_types(self):
- """测试 hmac_sha256 不同消息类型"""
- key = "test_key"
- # 字符串消息
- hmac_str = hmac_sha256(key, "test_message")
- # 字节消息
- hmac_bytes = hmac_sha256(key, b"test_message")
- # 相同内容的字符串和字节消息应该产生相同的结果
- self.assertEqual(hmac_str.hexdigest(), hmac_bytes.hexdigest())
- def test_hmac_sha256_known_vector(self):
- """测试 hmac_sha256 已知测试向量"""
- # 使用已知的测试向量验证实现正确性
- key = "key"
- message = "The quick brown fox jumps over the lazy dog"
- hmac_obj = hmac_sha256(key, message)
- result = hmac_obj.hexdigest()
- # 预期结果(可以通过其他实现验证)
- expected = "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"
- self.assertEqual(result, expected)
- if __name__ == "__main__":
- unittest.main()
|