Commit 338e32f
committed
Fix thread-safety race in CustomChainedCredential credential initialization
The ??= compound assignment is not atomic in C#. Under concurrent
GetToken / GetTokenAsync calls before the credential chain was
initialized (e.g. parallel tool calls on server startup in HTTP mode),
two threads could both observe _credential == null, construct separate
ChainedTokenCredential instances, and have one silently discarded. The
two chains may hold diverged MSAL token cache handles, causing
intermittent authentication failures.
Fix: replace the nullable field + ??= pattern with Lazy<TokenCredential>
using LazyThreadSafetyMode.ExecutionAndPublication, which provides
guaranteed single initialization under concurrent access with no
manual locking required.
Also adds GetToken_ConcurrentCalls_InitializesCredentialExactlyOnce
test to verify the Lazy<T>.IsValueCreated post-concurrent access.
Closes #3981 parent 6393ea8 commit 338e32f
3 files changed
Lines changed: 48 additions & 7 deletions
File tree
- core
- Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Services/Azure/Authentication
- Microsoft.Mcp.Core/src/Services/Azure/Authentication
- servers/Azure.Mcp.Server/changelog-entries
Lines changed: 32 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
469 | 469 | | |
470 | 470 | | |
471 | 471 | | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
472 | 504 | | |
473 | 505 | | |
474 | 506 | | |
| |||
Lines changed: 13 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
88 | 88 | | |
89 | | - | |
90 | | - | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
91 | 99 | | |
92 | 100 | | |
93 | 101 | | |
| |||
102 | 110 | | |
103 | 111 | | |
104 | 112 | | |
105 | | - | |
106 | | - | |
| 113 | + | |
107 | 114 | | |
108 | 115 | | |
109 | 116 | | |
110 | 117 | | |
111 | | - | |
112 | | - | |
| 118 | + | |
113 | 119 | | |
114 | 120 | | |
115 | 121 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
0 commit comments