Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Key Vault: ChallengeAuthPolicy request-replay fix (#47742) not ported to azure-keyvault-secrets / -certificates, and absent from all stable releases

Đang mở
#48,508 2 bình luận 1 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
68/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
azure, python
Lĩnh vực
api, authentication, cloud

Hướng nghiên cứu

Bắt đầu với azure/keyvault/secrets/_shared/challenge_auth_policy.py và azure/keyvault/certificates/_shared/challenge_auth_policy.py, so sánh chúng với bản sao keys đã được sửa và regression test test_request_body_not_reused_across_requests từ #47742. Chạy reproduction Mock không có mạng trên cả hai policy chưa được port; được xem là hoàn tất khi các request sau đó vẫn giữ nguyên method, URL và body, và fix được đưa vào một bản phát hành ổn định.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Client customer-reported KeyVault needs-team-attention question
Summary

The ChallengeAuthPolicy request-replay bug fixed by #47742 ("Fix Challenge Auth replay bug and update tests", merged 2026-07-08) was applied to azure-keyvault-keys and azure-keyvault-administration, but not to azure-keyvault-secrets or azure-keyvault-certificates, which vendor their own copies of _shared/challenge_auth_policy.py.

Separately, the fix is not present in any stable release yet — every current stable Key Vault package predates the merge, including azure-keyvault-keys itself.

To be clear about severity: I am not reporting this as a security vulnerability. The replayed request goes back to the vault that originally received it, and the bearer token is the shared https://vault.azure.net/.default audience that vault was already sent. verify_challenge_resource additionally blocks the cross-resource case. This is a correctness bug — an intended request is silently replaced by a duplicate of an earlier one.

Current state at HEAD

Occurrence count of _request_copy in each package's _shared/challenge_auth_policy.py:

Package _request_copy at HEAD Status
azure-keyvault-keys 1 fixed by #47742
azure-keyvault-administration 0 fixed
azure-keyvault-securitydomain 0 not affected
azure-keyvault-secrets 4 unported
azure-keyvault-certificates 4 unported

In the unfixed copies the stash is stored on the policy instance, which is created once per client rather than once per request:

  • self._request_copy: Optional[HttpRequest] = None — client-level state
  • self._request_copy = request.http_request — stores the in-flight request
  • if self._request_copy: request.http_request = self._request_copy — transplants it onto a later request
Stable releases
Package Latest stable Uploaded Contains fix?
azure-keyvault-secrets 4.11.0 2026-04-17 no
azure-keyvault-certificates 4.11.1 2026-05-05 no
azure-keyvault-keys 4.11.1 2026-05-19 no — predates the 2026-07-08 merge
azure-keyvault-administration 4.7.0 2026-05-19 no — predates the merge

The fix currently ships only in the pre-release azure-keyvault-keys 4.12.0b3.

Reproduction

This is the regression test added by #47742 (test_request_body_not_reused_across_requests), re-pointed at the unported packages. No Azure account, no network — the transport is a Mock.

pip install azure-keyvault-secrets==4.11.0 azure-keyvault-certificates==4.11.1 azure-keyvault-keys==4.12.0b3

Send a bodied POST to vault-A (elicits a challenge), then a bodiless GET to vault-B through the same client, and inspect the 4th outbound request:

=== azure-keyvault-keys 4.12.0b3 (POSITIVE CONTROL - contains #47742) ===
  4th request method : GET    (expected GET)
  4th request url    : https://vault-b.vault.azure.net/secrets/unrelated
  4th request body   : None   (expected None)
  RESULT: ok (per-request stash)

=== azure-keyvault-secrets 4.11.0 (UNPORTED) ===
  4th request method : POST   (expected GET)
  4th request url    : https://vault-a.vault.azure.net/secrets/db-password
  4th request body   : b'a duck'   (expected None)
  RESULT: prior request replayed

=== azure-keyvault-certificates 4.11.1 (UNPORTED) ===
  ... identical: POST, vault-a URL, body b'a duck'

The positive control discriminates: the fixed package passes under the identical harness, so the result is a property of the code under test rather than of the test.

Full reproduction script
import time
from unittest.mock import Mock

from azure.core.pipeline import Pipeline
from azure.core.rest import HttpRequest
from azure.core.credentials import AccessToken

CHALLENGE = Mock(
    status_code=401,
    headers={
        "WWW-Authenticate": 'Bearer authorization="https://authority.net/tenant", '
        "resource=https://vault.azure.net"
    },
)


def exercise(policy_cls, label):
    first_content = b"a duck"
    first_url = "https://vault-a.vault.azure.net/secrets/db-password"
    second_url = "https://vault-b.vault.azure.net/secrets/unrelated"
    seen = {}

    class C:
        n = 0

    def send(request):
        C.n += 1
        if C.n == 1:
            return CHALLENGE
        if C.n == 2:
            return Mock(status_code=200)
        if C.n == 3:
            return CHALLENGE
        if C.n == 4:
            seen["method"], seen["url"], seen["body"] = request.method, request.url, request.body
            return Mock(status_code=200)
        raise ValueError("unexpected request")

    cred = Mock(spec_set=["get_token"],
                get_token=Mock(return_value=AccessToken("token", time.time() + 3600)))
    pipeline = Pipeline(policies=[policy_cls(credential=cred)], transport=Mock(send=send))

    req = HttpRequest("POST", first_url)
    req.set_bytes_body(first_content)
    pipeline.run(req)
    pipeline.run(HttpRequest("GET", second_url))

    replayed = seen.get("body") == first_content or seen.get("url") == first_url
    print(f"\n=== {label} ===")
    print(f"  4th request method : {seen.get('method')}   (expected GET)")
    print(f"  4th request url    : {seen.get('url')}")
    print(f"    expected         : {second_url}")
    print(f"  4th request body   : {seen.get('body')!r}   (expected None)")
    print("  RESULT: " + ("prior request replayed" if replayed else "ok (per-request stash)"))
    return replayed


if __name__ == "__main__":
    from azure.keyvault.keys._shared.challenge_auth_policy import ChallengeAuthPolicy as KeysPolicy
    from azure.keyvault.secrets._shared.challenge_auth_policy import ChallengeAuthPolicy as SecretsPolicy
    from azure.keyvault.certificates._shared.challenge_auth_policy import ChallengeAuthPolicy as CertsPolicy

    exercise(KeysPolicy, "azure-keyvault-keys (POSITIVE CONTROL - fixed by #47742)")
    exercise(SecretsPolicy, "azure-keyvault-secrets (UNPORTED)")
    exercise(CertsPolicy, "azure-keyvault-certificates (UNPORTED)")
Impact

A call intended for one vault is emitted as a duplicate of an earlier call — the intended operation does not happen, and the earlier one is repeated. For secrets and certificates the replayed body is secret material being written a second time, so an unintended duplicate write or rotation is possible.

Suggested fix

Port #47742 to azure-keyvault-secrets and azure-keyvault-certificates (make the stash per-request rather than per-policy), and ship it in a stable release — the fix currently exists only in the pre-release azure-keyvault-keys 4.12.0b3.

Root cause of the divergence is the duplicated _shared directories: each package vendors its own copy of challenge_auth_policy.py, so a fix in one does not propagate. The .NET and Java SDKs are unaffected — they use a single shared implementation.

Ngôn ngữ chính
Python
Star
5.6k
Fork
3.4k
Merge trung bình
2 ngày 7 giờ
Pull request đã merge (30 ngày)
206

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của Azure/azure-sdk-for-python

Tất cả issue của Azure/azure-sdk-for-python

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.