Skip to content

Commit 6dbf88c

Browse files
committed
Adjust SNI behavior around .pfx files
1 parent 68cfaaf commit 6dbf88c

2 files changed

Lines changed: 14 additions & 23 deletions

File tree

msal/application.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,19 @@ def _parse_pfx(pfx_path, passphrase_bytes):
9191
# Cert concepts https://security.stackexchange.com/a/226758/125264
9292
from cryptography.hazmat.primitives.serialization import pkcs12
9393
with open(pfx_path, 'rb') as f:
94-
private_key, cert, _ = pkcs12.load_key_and_certificates( # cryptography 2.5+
94+
private_key, cert, additional_certs = pkcs12.load_key_and_certificates(
95+
# cryptography 2.5+
9596
# https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#cryptography.hazmat.primitives.serialization.pkcs12.load_key_and_certificates
9697
f.read(), passphrase_bytes)
9798
if not (private_key and cert):
9899
raise ValueError("Your PFX file shall contain both private key and cert")
99100
sha256_thumbprint, sha1_thumbprint, x5c = _extract_cert_and_thumbprints(cert)
101+
# Per RFC 7515 §4.1.6, x5c should include the full certificate chain
102+
# (leaf first, then intermediates) for SNI (Subject Name/Issuer) auth.
103+
if additional_certs:
104+
for extra_cert in additional_certs:
105+
_, _, extra_x5c = _extract_cert_and_thumbprints(extra_cert)
106+
x5c.extend(extra_x5c)
100107
return private_key, sha256_thumbprint, sha1_thumbprint, x5c
101108

102109

tests/test_agentic_e2e.py

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
3. Full 3-leg flow: FMI → assertion → user_fic → user-scoped token
77
4. Cache isolation between app-only and user-scoped tokens
88
9-
Corresponds to:
10-
- .NET: Agentic.cs
11-
- Java: AgenticIT.java
12-
139
Test configuration uses the same lab infrastructure as test_fmi_e2e.py.
1410
Requires LAB_APP_CLIENT_CERT_PFX_PATH environment variable.
1511
"""
@@ -28,7 +24,7 @@
2824
logging.basicConfig(level=logging.DEBUG if "-v" in sys.argv else logging.INFO)
2925

3026
# =============================================================================
31-
# Test configuration — matches .NET/Java agentic test constants
27+
# Test configuration — shared lab app registrations for agentic scenarios
3228
# =============================================================================
3329
_TENANT_ID = "10c419d4-4a50-45b2-aa4e-919fb84df24f"
3430
_BLUEPRINT_CLIENT_ID = "aab5089d-e764-47e3-9f28-cc11c2513821"
@@ -43,14 +39,14 @@
4339

4440

4541
# =============================================================================
46-
# Helpers — mirror .NET GetAppCredentialAsync / Java acquireFmiCredentialForAgent
42+
# Helpers
4743
# =============================================================================
4844

4945
def _acquire_fmi_credential_for_agent(agent_app_id):
5046
"""Leg 1: Blueprint app acquires FMI credential (T1) for the given agent.
5147
5248
Uses certificate authentication with SNI (sendX5C) and fmi_path set to
53-
the agent app ID — matching .NET and Java helper methods.
49+
the agent app ID.
5450
"""
5551
blueprint_app = msal.ConfidentialClientApplication(
5652
_BLUEPRINT_CLIENT_ID,
@@ -70,7 +66,7 @@ def _acquire_fmi_credential_for_agent(agent_app_id):
7066
def _acquire_fmi_credential_from_rma():
7167
"""Acquire an FMI credential from the RMA app using certificate credentials.
7268
73-
Mirrors Java's acquireFmiCredentialFromRma and Python's test_fmi_e2e helper.
69+
Uses the same RMA pattern as test_fmi_e2e._get_fmi_credential_from_rma().
7470
Used for assertion callback context tests where the callback just needs to
7571
return a valid FMI token (not specifically for an agent app).
7672
"""
@@ -118,10 +114,7 @@ def _acquire_instance_token_for_agent():
118114
# =============================================================================
119115

120116
class TestAssertionCallbackContext(LabBasedTestCase):
121-
"""Verify assertion callback receives correct context when fmi_path is set.
122-
123-
Corresponds to Java's assertionCallback_ReceivesFmiPathContext.
124-
"""
117+
"""Verify assertion callback receives correct context when fmi_path is set."""
125118

126119
def test_assertion_callback_receives_fmi_path(self):
127120
captured_context = {}
@@ -155,9 +148,6 @@ def assertion_callback(context):
155148
class TestAgentAppToken(LabBasedTestCase):
156149
"""Agent acquires app-only token for Graph using FMI-sourced assertion.
157150
158-
Corresponds to .NET's AgentGetsAppTokenForGraphTest and
159-
Java's agentGetsAppToken_UsingFmiAssertion.
160-
161151
Flow: Blueprint → T1 (assertion callback) → Agent CCA → app token
162152
"""
163153

@@ -183,9 +173,6 @@ def assertion_provider(context):
183173
class TestAgentUserIdentity(LabBasedTestCase):
184174
"""Full 3-leg agent identity flow: FMI → assertion → user_fic → user token.
185175
186-
Corresponds to .NET's AgentUserIdentityGetsTokenForGraphTest and
187-
Java's agentUserIdentity_GetsTokenForGraph.
188-
189176
Flow:
190177
1. Blueprint → T1 (FMI credential)
191178
2. Agent uses T1 → T2 (instance token)
@@ -234,10 +221,7 @@ def assertion_provider(context):
234221

235222

236223
class TestAgentCacheIsolation(LabBasedTestCase):
237-
"""App-only and user-scoped tokens are isolated in cache on the same CCA.
238-
239-
Corresponds to Java's agentCca_AppAndUserTokens_CacheIsolation.
240-
"""
224+
"""App-only and user-scoped tokens are isolated in cache on the same CCA."""
241225

242226
def test_app_and_user_tokens_are_isolated(self):
243227
def assertion_provider(context):

0 commit comments

Comments
 (0)