Skip to content

Commit 715f417

Browse files
authored
[Identity] Propagate send_certificate_chain in OBO (#36810)
Supports SNI scenarios. Signed-off-by: Paul Van Eck <[email protected]>
1 parent 38b3cd4 commit 715f417

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Bugs Fixed
1010

11+
- Fixed an issue where the `send_certificate_chain` keyword argument was not being honored when using certs with the synchronous `OnBehalfOfCredential`. ([#36810](https://github.com/Azure/azure-sdk-for-python/pull/36810))
12+
1113
### Other Changes
1214

1315
- `AzurePowerShellCredential` now supports using secure strings when authenticating with PowerShell. ([#36653](https://github.com/Azure/azure-sdk-for-python/pull/36653))

sdk/identity/azure-identity/azure/identity/_credentials/on_behalf_of.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class OnBehalfOfCredential(MsalCredential, GetTokenMixin):
4848
is a unicode string, it will be encoded as UTF-8. If the certificate requires a different encoding, pass
4949
appropriately encoded bytes instead.
5050
:paramtype password: str or bytes
51+
:keyword bool send_certificate_chain: If True when **client_certificate** is provided, the credential will send
52+
the public certificate chain in the x5c header of each token request's JWT. This is required for Subject
53+
Name/Issuer (SNI) authentication. Defaults to False.
5154
:keyword bool disable_instance_discovery: Determines whether or not instance discovery is performed when attempting
5255
to authenticate. Setting this to true will completely disable both instance discovery and authority validation.
5356
This functionality is intended for use in scenarios where the metadata endpoint cannot be reached, such as in
@@ -78,6 +81,8 @@ def __init__(
7881
client_secret: Optional[str] = None,
7982
client_assertion_func: Optional[Callable[[], str]] = None,
8083
user_assertion: str,
84+
password: Optional[Union[bytes, str]] = None,
85+
send_certificate_chain: bool = False,
8186
**kwargs: Any
8287
) -> None:
8388
self._assertion = user_assertion
@@ -98,7 +103,10 @@ def __init__(
98103
raise ValueError('Specifying both "client_certificate" and "client_secret" is not valid.')
99104
try:
100105
credential = get_client_credential(
101-
certificate_path=None, password=kwargs.pop("password", None), certificate_data=client_certificate
106+
certificate_path=None,
107+
password=password,
108+
certificate_data=client_certificate,
109+
send_certificate_chain=send_certificate_chain,
102110
)
103111
except ValueError as ex:
104112
# client_certificate isn't a valid cert.

sdk/identity/azure-identity/azure/identity/aio/_credentials/on_behalf_of.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def __init__(
6868
client_secret: Optional[str] = None,
6969
client_assertion_func: Optional[Callable[[], str]] = None,
7070
user_assertion: str,
71+
password: Optional[Union[str, bytes]] = None,
7172
**kwargs: Any
7273
) -> None:
7374
super().__init__()
@@ -90,7 +91,7 @@ def __init__(
9091
if client_secret:
9192
raise ValueError('Specifying both "client_certificate" and "client_secret" is not valid.')
9293
try:
93-
cert = get_client_credential(None, kwargs.pop("password", None), client_certificate)
94+
cert = get_client_credential(None, password, client_certificate)
9495
except ValueError as ex:
9596
message = '"client_certificate" is not a valid certificate in PEM or PKCS12 format'
9697
raise ValueError(message) from ex

sdk/identity/azure-identity/tests/test_obo.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,26 @@ def test_client_assertion_func_with_client_certificate():
279279
user_assertion="assertion",
280280
)
281281
assert "It is invalid to specify more than one of the following" in str(ex.value)
282+
283+
284+
def test_client_certificate_with_params():
285+
"""Ensure keyword arguments are passed to get_client_credential when client_certificate is provided"""
286+
expected_send_certificate_chain = True
287+
288+
cert_path = os.path.join(os.path.dirname(__file__), "certificate-with-password.pem")
289+
cert_password = "password"
290+
with open(cert_path, "rb") as f:
291+
cert_bytes = f.read()
292+
293+
credential = OnBehalfOfCredential(
294+
"tenant-id",
295+
"client-id",
296+
client_certificate=cert_bytes,
297+
password=cert_password,
298+
send_certificate_chain=expected_send_certificate_chain,
299+
user_assertion="assertion",
300+
)
301+
302+
assert "passphrase" in credential._client_credential
303+
assert credential._client_credential["passphrase"] == cert_password.encode("utf-8")
304+
assert "public_certificate" in credential._client_credential

0 commit comments

Comments
 (0)