Skip to content
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Release History

## 2.0.0b2 (2026-01-29)

### Bugs Fixed

- Fixed authentication failure on HTTP redirects by preserving sensitive headers during service-managed redirects within the Confidential Ledger endpoint.

## 2.0.0b1 (2025-10-20)

### Features Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential
self._config.custom_hook_policy,
self._config.logging_policy,
policies.DistributedTracingPolicy(**kwargs),
policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None,
# Redirect cleanup is disabled to preserve authentication and ledger-specific headers
# on service-managed redirects. Confidential Ledger redirects are expected to stay within
# the same trusted ledger endpoint, so forwarding these sensitive headers is required
# for correct authentication behavior.
policies.SensitiveHeaderCleanupPolicy(
disable_redirect_cleanup=True, **kwargs
) if self._config.redirect_policy else None,
self._config.http_logging_policy,
]
self._client: PipelineClient = PipelineClient(base_url=_endpoint, policies=_policies, **kwargs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

VERSION = "2.0.0b1"
VERSION = "2.0.0b2"
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential
self._config.custom_hook_policy,
self._config.logging_policy,
policies.DistributedTracingPolicy(**kwargs),
policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None,
policies.SensitiveHeaderCleanupPolicy(
disable_redirect_cleanup=True, **kwargs
) if self._config.redirect_policy else None,
self._config.http_logging_policy,
]
self._client: AsyncPipelineClient = AsyncPipelineClient(base_url=_endpoint, policies=_policies, **kwargs)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
"""Unit tests for ConfidentialLedgerClient configuration."""

import pytest
from unittest.mock import patch, MagicMock
from azure.core.pipeline import policies

# Import the generated client directly to test its policy configuration
from azure.confidentialledger._client import ConfidentialLedgerClient as GeneratedClient


class TestClientConfiguration:
"""Tests for client configuration settings."""

def test_sensitive_header_cleanup_policy_disable_redirect_cleanup_enabled(self):
"""Test that SensitiveHeaderCleanupPolicy has disable_redirect_cleanup=True.

This ensures that authentication and ledger-specific headers are preserved
on service-managed redirects, which is required for correct authentication
behavior within the trusted Confidential Ledger endpoint.
"""
# Mock the PipelineClient to capture the policies passed to it
with patch("azure.confidentialledger._client.PipelineClient") as mock_pipeline_client:
mock_pipeline_client.return_value = MagicMock()

# Create the generated client directly - this will trigger policy creation
# The generated client only requires ledger_endpoint
client = GeneratedClient(
ledger_endpoint="https://test-ledger.confidentialledger.azure.com"
)

# Get the policies argument passed to PipelineClient
call_args = mock_pipeline_client.call_args
policies_arg = call_args.kwargs.get("policies") or call_args[1].get("policies")

# Find the SensitiveHeaderCleanupPolicy in the policies list
sensitive_header_policy = None
for policy in policies_arg:
if isinstance(policy, policies.SensitiveHeaderCleanupPolicy):
sensitive_header_policy = policy
break

# Assert the policy exists and has disable_redirect_cleanup=True
assert sensitive_header_policy is not None, (
"SensitiveHeaderCleanupPolicy should be present in the client's policies"
)
assert sensitive_header_policy._disable_redirect_cleanup is True, (
"SensitiveHeaderCleanupPolicy should have disable_redirect_cleanup=True "
"to preserve authentication headers on Confidential Ledger redirects"
)

client.close()

def test_sensitive_header_cleanup_policy_is_in_correct_position(self):
"""Test that SensitiveHeaderCleanupPolicy is positioned after authentication_policy.

The policy should be placed after the authentication policy so that it can
properly handle the redirect cleanup for authentication headers.
"""
with patch("azure.confidentialledger._client.PipelineClient") as mock_pipeline_client:
mock_pipeline_client.return_value = MagicMock()

client = GeneratedClient(
ledger_endpoint="https://test-ledger.confidentialledger.azure.com"
)

# Get the policies argument passed to PipelineClient
call_args = mock_pipeline_client.call_args
policies_arg = call_args.kwargs.get("policies") or call_args[1].get("policies")

# Filter out None values
non_none_policies = [p for p in policies_arg if p is not None]

# Find positions of key policies
sensitive_header_idx = None
distributed_tracing_idx = None

for idx, policy in enumerate(non_none_policies):
if isinstance(policy, policies.SensitiveHeaderCleanupPolicy):
sensitive_header_idx = idx
elif isinstance(policy, policies.DistributedTracingPolicy):
distributed_tracing_idx = idx

# SensitiveHeaderCleanupPolicy should come after DistributedTracingPolicy
assert sensitive_header_idx is not None, (
"SensitiveHeaderCleanupPolicy should be present in the policies"
)
assert distributed_tracing_idx is not None, (
"DistributedTracingPolicy should be present in the policies"
)
assert sensitive_header_idx > distributed_tracing_idx, (
"SensitiveHeaderCleanupPolicy should be positioned after DistributedTracingPolicy"
)

client.close()