Skip to content

Enforce mTLS PoP minimum binding strength for Managed Identity (#6049 Phase 2)#6059

Open
Robbie-Microsoft wants to merge 2 commits into
mainfrom
rginsburg/minstrength-enforcement
Open

Enforce mTLS PoP minimum binding strength for Managed Identity (#6049 Phase 2)#6059
Robbie-Microsoft wants to merge 2 commits into
mainfrom
rginsburg/minstrength-enforcement

Conversation

@Robbie-Microsoft

Copy link
Copy Markdown
Contributor

Summary

Implements Phase 2 of #6049: enforces a minimum mTLS Proof-of-Possession (PoP) binding-strength floor for Managed Identity (MI).

A caller can now require that the host be able to produce at least a given binding strength; when the host cannot meet the floor the request fails fast. This is a floor assertion, not a downgrade selector — MSAL always uses the host's maximum binding strength.

Scope is MI only; confidential-client support is deferred.

Public API

  • New PoPOptions class (AppConfig) with MtlsBindingStrength MinStrength (default None = no floor).
  • New MI overload WithMtlsProofOfPossession(PoPOptions); the parameterless overload now delegates to it (platform/NET462 guards preserved).
  • New error MsalError.MinStrengthNotMet.
  • PublicAPI.Unshipped.txt updated for all 6 TFMs.

Behavior

  • MtlsPopMinStrength is plumbed through the common/MI parameters and exposed on the request parameters.
  • When the floor is greater than None, ManagedIdentityClient.SendTokenRequestForManagedIdentityAsync runs host capability discovery and throws MinStrengthNotMet (message names the host's actual strength and the required floor) if the host's max binding strength is below the floor. No-op when None.
  • The floor is included in the MI token cache key (mi_minstrength) so a higher-floor request cannot be served from a lower/no-floor cache entry (mirrors the existing attestation-mode partitioning).

Tests

  • 6 new tests in ImdsV2Tests.cs: floor met (KeyGuard/Software on KeyGuard host), default None behaves like parameterless, floor not met → MinStrengthNotMet, null PoPOptionsArgumentNullException, and a cache-key partitioning regression (higher-floor request does not reuse a no-floor token).
  • All 429 managed-identity unit tests pass; library builds clean on net462/net472/netstandard2.0/net8.0 with TreatWarningsAsErrors.

Notes

  • Minor follow-up (not addressed here): on an IMDSv1 TVM/CVM host the strength is reported as Software (Phase 1 behavior), so a Software floor passes the check and the request then fails with MtlsPopTokenNotSupportedinImdsV1 rather than a single coherent reason. The request fails either way.

Robbie-Microsoft and others added 2 commits June 10, 2026 16:35
…Phase 2)

Add PoPOptions with a MinStrength floor and a managed identity
WithMtlsProofOfPossession(PoPOptions) overload. When MinStrength is greater
than None, the token request runs host capability discovery and fails fast
with MsalError.MinStrengthNotMet if the host's maximum binding strength is
below the requested floor. The parameterless overload now delegates to the
new overload with a default (None) floor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Include MtlsPopMinStrength in the managed identity token cache key so a
higher-floor request cannot be satisfied from a cache entry created by a
lower/no-floor request, closing a latent gap where the MinStrength floor
(enforced only on the acquisition path) could be bypassed on a cache hit.
Mirrors the existing attestation-mode cache partitioning. Adds a regression
test proving a KeyGuard-floor request does not reuse a no-floor token entry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 10, 2026 20:50
@Robbie-Microsoft Robbie-Microsoft requested a review from a team as a code owner June 10, 2026 20:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Phase 2 of the Managed Identity (MI) mTLS Proof-of-Possession (PoP) work by introducing a public PoPOptions type with a minimum required MtlsBindingStrength floor (MinStrength) and enforcing that floor during MI token acquisition via capability discovery. The change also ensures token cache partitioning includes the requested minimum strength, preventing higher-floor requests from reusing lower/no-floor cache entries.

Changes:

  • Added PoPOptions (public API) and a new MI overload WithMtlsProofOfPossession(PoPOptions), with the parameterless overload delegating to it.
  • Enforced PoPOptions.MinStrength at request time by running MI host capability discovery and failing fast with MsalError.MinStrengthNotMet when the host max strength is below the requested floor.
  • Partitioned the MI token cache key by minimum strength (mi_minstrength) and added unit tests covering floor behavior and cache partitioning.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/ImdsV2Tests.cs Adds unit tests covering min-strength floors (met/not met), default behavior, null options, and cache-key partitioning.
src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt Declares new public APIs (PoPOptions, MinStrengthNotMet, MI PoP overload) for netstandard2.0.
src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt Declares new public APIs for net8.0.
src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt Declares new public APIs for net8.0-ios.
src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt Declares new public APIs for net8.0-android.
src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt Declares new public APIs for net472.
src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt Declares new public APIs for net462.
src/client/Microsoft.Identity.Client/MsalErrorMessage.cs Adds formatted error message text for the min-strength-not-met failure.
src/client/Microsoft.Identity.Client/MsalError.cs Adds new public error code MinStrengthNotMet.
src/client/Microsoft.Identity.Client/ManagedIdentity/ManagedIdentityPopExtensions.cs Adds WithMtlsProofOfPossession(PoPOptions) overload and delegates parameterless overload to it; plumbs MinStrength.
src/client/Microsoft.Identity.Client/ManagedIdentity/ManagedIdentityClient.cs Enforces the min-strength floor via capability discovery before proceeding with MI token acquisition.
src/client/Microsoft.Identity.Client/Internal/Requests/AuthenticationRequestParameters.cs Exposes MtlsPopMinStrength from common parameters to request parameters.
src/client/Microsoft.Identity.Client/AppConfig/PoPOptions.cs Introduces the new public options class and documents MinStrength semantics.
src/client/Microsoft.Identity.Client/ApiConfig/Parameters/AcquireTokenForManagedIdentityParameters.cs Adds MtlsPopMinStrength to MI request parameters and logs it.
src/client/Microsoft.Identity.Client/ApiConfig/Parameters/AcquireTokenCommonParameters.cs Adds MtlsPopMinStrength to common parameters (set by MI PoP options).
src/client/Microsoft.Identity.Client/ApiConfig/AcquireTokenForManagedIdentityParameterBuilder.cs Plumbs MtlsPopMinStrength into MI parameters and partitions the MI cache key by min strength.
src/client/Microsoft.Identity.Client.KeyAttestation/ManagedIdentityAttestationExtensions.cs Updates XML cref to point at the correct WithMtlsProofOfPossession overload signature.

@gladjohn

Copy link
Copy Markdown
Contributor

This PR needs a little more detailed description or a task to understand the requirements better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants