Detach ImdsV2ManagedIdentitySource from AbstractManagedIdentity (refused-bequest cleanup)#6089
Merged
Conversation
ImdsV2ManagedIdentitySource inherited AbstractManagedIdentity but used none of its token template and stubbed the abstract CreateRequestAsync with a throw (a refused bequest). ManagedIdentityClient selected via the shared AbstractManagedIdentity-typed path and downcast back to ImdsV2ManagedIdentitySource. Introduce IImdsV2MtlsBindingSource implemented by ImdsV2ManagedIdentitySource instead of inheriting AbstractManagedIdentity. Split source selection in ManagedIdentityClient into a decision helper (SelectManagedIdentitySourceType) and instantiation, removing the downcast. All guards, discovery cache, and routing behavior preserved. Remove the obsolete ValidateServerCertificate_NotSetForImdsV2 test (asserted a base-class validation-callback behavior IMDSv2 no longer has). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR removes the “refused bequest” relationship between ImdsV2ManagedIdentitySource and AbstractManagedIdentity by introducing a focused internal interface for IMDSv2 mTLS binding minting, and refactors managed identity source selection to avoid downcasts while preserving existing routing/guard behavior.
Changes:
- Introduced
IImdsV2MtlsBindingSourceand moved IMDSv2 “mint binding for delegation” behind the interface. - Refactored
ManagedIdentityClientto separate source decision (SelectManagedIdentitySourceType) from instantiation, and to construct IMDSv2 via the interface for the PoP path. - Removed an obsolete IMDSv2 server-certificate-validation callback unit test that depended on the old inheritance structure.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/ManagedIdentityTests.cs | Removes an obsolete test tied to the previous IMDSv2 base-class behavior. |
| src/client/Microsoft.Identity.Client/ManagedIdentity/V2/ImdsV2ManagedIdentitySource.cs | Detaches IMDSv2 from AbstractManagedIdentity and exposes binding minting via the new interface. |
| src/client/Microsoft.Identity.Client/ManagedIdentity/V2/IImdsV2MtlsBindingSource.cs | Adds an internal abstraction for the IMDSv2 mTLS binding minting operation used by delegation. |
| src/client/Microsoft.Identity.Client/ManagedIdentity/ManagedIdentityClient.cs | Refactors selection/instantiation logic and routes PoP binding mint via the interface without downcasts. |
Comments suppressed due to low confidence (1)
src/client/Microsoft.Identity.Client/ManagedIdentity/V2/ImdsV2ManagedIdentitySource.cs:416
- AcquireMtlsBindingForDelegationAsync accepts a CancellationToken but only checks it once (ThrowIfCancellationRequested) and then performs all subsequent key/network operations using _requestContext.UserCancellationToken (e.g., GetCsrMetadataAsync / ExecuteCertificateRequestAsync / GetOrCreateKeyAsync). If these tokens ever differ, cancellation will not reliably abort the mint flow, which is inconsistent with other managed identity paths that pass the provided token through to HttpManager.
public async Task<MtlsBindingInfo> AcquireMtlsBindingForDelegationAsync(
ApiConfig.Parameters.AcquireTokenForManagedIdentityParameters parameters,
bool forceRemint,
CancellationToken cancellationToken)
{
_attestationTokenProvider = parameters.AttestationTokenProvider;
_isMtlsPopRequested = true;
if (forceRemint && _mtlsCache is MtlsBindingCache bindingCache)
{
bindingCache.RemoveBadCert(GetMtlsCertCacheKey(), _requestContext.Logger);
}
cancellationToken.ThrowIfCancellationRequested();
return await AcquireMtlsBindingAsync().ConfigureAwait(false);
}
neha-bhargava
approved these changes
Jun 24, 2026
gladjohn
approved these changes
Jun 25, 2026
This was referenced Jun 27, 2026
Open
fix: Bump Microsoft.Identity.Client from 4.85.1 to 4.85.2
Halceyon/open-telemetry-trace-listener#204
Closed
Merged
Closed
Open
This was referenced Jun 29, 2026
Open
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Removes the "refused bequest" code smell introduced by #6070:
ImdsV2ManagedIdentitySourceinheritedAbstractManagedIdentitybut used none of its token template, was forced to stub the abstractCreateRequestAsyncwith athrow, and was reached via a downcast inManagedIdentityClient.Fixes #6088.
Changes
IImdsV2MtlsBindingSourceexposingAcquireMtlsBindingForDelegationAsync.ImdsV2ManagedIdentitySourcenow implementsIImdsV2MtlsBindingSourceinstead of inheritingAbstractManagedIdentity; it owns its_requestContext/_isMtlsPopRequestedfields, and the throwingCreateRequestAsyncoverride is deleted.ManagedIdentityClientsource selection is split into a decision helper (SelectManagedIdentitySourceType→(source, isImdsV2)) and instantiation. The PoP path constructs IMDSv2 directly through the interface — the downcast (is not ImdsV2ManagedIdentitySource) is gone. The bearer path resolves IMDS to IMDSv1 only.ValidateServerCertificate_NotSetForImdsV2test (asserted a base-class validation-callback behavior IMDSv2 no longer has).Behavior preserved
All source-selection guards are unchanged:
NoneFoundthrow, the per-request IMDSv1 fallback (isImdsV2 && !isMtlsPopRequested), the IMDSv1+PoPMtlsPopTokenNotSupportedinImdsV1throw, the no-environment defaults, and the discovery cache (s_cachedSourceResult). The PoP→delegation vs. bearer routing inManagedIdentityAuthRequestkeeps the two paths mutually exclusive, and the mTLS PoP min-strength enforcement added in #6059 is retained at the top ofAcquireImdsV2MtlsBindingAsync.Validation
TreatWarningsAsErrors=true).ImdsV2Tests: 92/92 pass.ManagedIdentityTests: 433 pass / 1 skip / 0 fail.internal;PublicAPI.Unshipped.txtuntouched).Context
Follow-up to review feedback on #6070 (thread).