Skip to content

Add Managed Identity v2 KeyGuard mTLS PoP support - #1059

Open
Gladwin Johnson VR (gladjohn) wants to merge 11 commits into
devfrom
gladjohn/java-msi-v2-mtls-binding-context-local
Open

Add Managed Identity v2 KeyGuard mTLS PoP support#1059
Gladwin Johnson VR (gladjohn) wants to merge 11 commits into
devfrom
gladjohn/java-msi-v2-mtls-binding-context-local

Conversation

@gladjohn

@gladjohn Gladwin Johnson VR (gladjohn) commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds production-shaped Managed Identity v2 mTLS support for Java using Windows
VBS KeyGuard and optional Microsoft Azure Attestation.

Java retains native interop only for KeyGuard/CNG signing and attestation.
JCA/JSSE owns TLS, and mTLS PoP callers receive a reusable
IMtlsBindingContext for independent downstream Java HTTP calls.

Reviewer entry point: managed-identity-v2-mtls-pop-review-guide.md

Architecture

ManagedIdentityApplication
  -> IMDS v2 platform metadata
  -> KeyGuard non-exportable RSA key
  -> optional MAA attestation
  -> IMDS v2 binding certificate
  -> normal MSAL OAuth token pipeline over JSSE mTLS
  -> mtls_pop token + reusable IMtlsBindingContext

Native signing remains limited to:

JSSE
  -> X509ExtendedKeyManager
  -> CngRsaPrivateKey
  -> CngSignatureSpi
  -> NCryptSignHash
  -> VBS KeyGuard

Changes

  • Adds managed-identity mTLS PoP and binding-aware token caching keyed by token
    type, complete leaf-certificate DER SHA-256 identity, and attestation mode.
  • Routes the ESTS mTLS exchange through the normal MSAL token pipeline for
    claims, client capabilities, telemetry, correlation IDs, retries, error
    handling, and response parsing.
  • Adds an optional Windows extension for CNG, KeyGuard, CSR generation,
    attestation, certificate rotation, and reusable JSSE binding contexts.
  • Bundles and verifies the Microsoft-signed
    Microsoft.Azure.Security.KeyGuardAttestation 1.1.5
    AttestationClientLib.dll.
  • Requires exact token_type=mtls_pop, HTTPS token endpoints, IMDS-specific
    retry behavior, validated IMDS response origin, and disabled redirects for
    credential-bound requests.
  • Defines IMtlsCapableHttpClient for custom transports and fails fast when a
    custom client does not consume request-specific mTLS configuration.
  • Detects and recreates stale per-boot KeyGuard keys using a private signing
    liveness probe.
  • Keeps the manual Key Vault E2E application in a separate profile-only module.

.NET parity follow-up

The following parity changes are included in this PR branch:

  • Moves the public attestation opt-in out of core and into the optional
    com.microsoft.azure:msal4j-key-attestation artifact through
    ManagedIdentityAttestationExtensions.withAttestationSupport(...), matching
    the MSAL.NET package boundary.
  • Adds bearer-over-mTLS through withRequestOverMtls(). It authenticates the
    ESTS connection with KeyGuard, requests token_type=bearer, uses a distinct
    cache partition, and intentionally returns no downstream binding context.
  • Adds SLF4J-backed native attestation logging with correlation IDs, safe native
    callback lifetime, and suppression of raw native debug payloads.
  • Adds MSAL_MI_DISABLE_IMDS_V2; true or 1 disables v2, capability
    discovery reports no mTLS binding, and explicit PoP or bearer-over-mTLS
    requests fail before metadata, key, CSR, certificate, or attestation work.
  • Keeps the KeyGuard key container persistent but the issued certificate and
    binding context process-memory only. No Windows certificate-store persistence
    is required.
  • Does not add token-revocation reminting, claims-triggered certificate
    replacement, or bypass_cache.

The optional bounded capability-discovery timeout proposed in MSAL.NET issue
#6180 remains a separate follow-up. It is useful for credential-chain failover,
but is not currently shipped by MSAL.NET and requires a Java cancellation and
transport-budget contract rather than a superficial future timeout.

Validation

  • Full msal4j-sdk tests pass.
  • Targeted optional-package API and native logger tests pass.
  • Production classes remain Java 8 compatible.
  • The production extension and shaded E2E JAR contain the verified native DLL;
    the production extension excludes the manual E2E app.
  • Live validation passed on a Windows Server 2025 Trusted Launch Azure VM:
    • acquired an attested mtls_pop token;
    • returned the binding certificate and reusable JSSE SSLContext;
    • verified JWT cnf.x5t#S256 against SHA-256 of the complete leaf certificate
      DER;
    • independently called a token-binding-enforced Azure Key Vault with
      HttpsURLConnection and received HTTP 200;
    • retried the same token without its binding certificate and received HTTP
      401 Unauthorized;
    • reacquired through MSAL and received TokenSource.CACHE with the matching
      live binding context;
    • force-refreshed and received TokenSource.IDENTITY_PROVIDER, then completed
      another HTTP 200 Key Vault call;
    • acquired an ordinary Bearer token over attested mTLS, exposed no binding
      context, and verified the second acquisition was a cache hit;
    • enabled MSAL_MI_DISABLE_IMDS_V2 and verified mTLS PoP failed before native
      attestation work.

Security properties

  • Private-key bytes are never exported into Java memory.
  • TLS is performed by Java JCA/JSSE, not WinHTTP or Schannel as the HTTP stack.
  • Attestation failures fail closed when attestation is requested.
  • Ordinary bearer, bearer-over-mTLS, mTLS PoP, attested, and unattested cache
    entries cannot cross-hit.
  • Same-key certificate renewal creates a new token-cache partition because the
    complete certificate DER changes.
  • Credential-bound redirects are disabled.
  • Custom HTTP clients fail fast unless they support request-specific mTLS.
  • Retired native key handles are cleaned after certificate expiry.

MSAL.NET parity gap analysis

A feature-by-feature comparison, intentional platform differences, validation evidence, and prioritized remaining release gaps are documented in managed-identity-v2-dotnet-java-parity-gap-analysis.md.

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

Adds optional Windows KeyGuard-backed Managed Identity v2 mTLS PoP support, including core SDK integration, native CNG/attestation extensions, caching, tests, documentation, and manual validation.

Changes:

  • Extends token acquisition, HTTP, result, and cache pipelines for mTLS-bound tokens.
  • Adds the Windows CNG/KeyGuard provider and IMDS v2 credential flow.
  • Adds unit tests, documentation, Maven modules, and an e2e validation app.

Reviewed changes

Copilot reviewed 61 out of 61 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
run-java-msi-v2-mtls-devapp.ps1 Builds and runs manual validation.
README.md Introduces the mTLS extension.
pom.xml Registers extension and e2e modules.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/TokenRequestExecutorTest.java Tests mTLS OAuth request construction.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsProviderLoaderTest.java Tests missing-provider failure.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsParametersTest.java Tests parameters, cache partitioning, and token validation.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsBindingTest.java Tests token endpoint validation.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/DefaultHttpClientMtlsTest.java Tests redirect prevention.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/AuthenticationResultMtlsTest.java Tests binding serialization and equality.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenResponse.java Parses OAuth token type.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java Sends request-specific mTLS token requests.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenCache.java Supports explicit extended cache hashes.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/OAuthHttpRequest.java Propagates request socket factories.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MsalRequest.java Stores extended cache-key hashes.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MsalError.java Defines mTLS error codes.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityResponse.java Parses relative expiration values.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityParameters.java Adds mTLS and attestation options.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsRequest.java Defines the provider request contract.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsProviderLoader.java Discovers optional providers.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsHttpResponse.java Defines callback HTTP responses.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsHttpRequest.java Defines callback HTTP requests.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityMtlsBinding.java Represents validated binding generations.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/IMtlsCapableHttpClient.java Marks mTLS-capable custom clients.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/IMtlsBindingContext.java Exposes process-local JSSE bindings.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/IManagedIdentityMtlsProvider.java Defines the optional provider SPI.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/IManagedIdentityMtlsHttpClient.java Defines the MSAL HTTP callback.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/IAuthenticationResult.java Exposes token and binding metadata.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/HttpRequest.java Carries request-specific socket factories.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/DefaultHttpClient.java Applies mTLS factories and disables redirects.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AuthenticationResult.java Stores token type and live bindings.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByManagedIdentitySupplier.java Integrates binding, cache, IMDS, and OAuth flows.
msal4j-sdk/docs/managed-identity-v2-mtls-pop.md Documents architecture and validation.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/Pkcs10BuilderTest.java Tests CSR DER generation.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/KeyGuardMtlsBindingContextTest.java Tests binding key IDs and contexts.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/KeyGuardManagedIdentityMtlsProviderTest.java Tests certificate rotation timing.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/ImdsV2ClientTest.java Tests IMDS v2 contracts.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/CngX509ExtendedKeyManagerTest.java Tests RSA alias selection.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/CngSignatureParametersTest.java Tests PSS parameter validation.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/CngRsaPrivateKeyTest.java Tests non-exportability and cleanup.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/CngProviderTest.java Tests provider registration and delegation.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/CngKeyGuardTest.java Tests stale native-key deletion.
msal4j-mtls-extensions/src/test/java/com/microsoft/aad/msal4j/mtls/AttestationTokenCacheTest.java Tests attestation caching and concurrency.
msal4j-mtls-extensions/src/main/resources/META-INF/services/com.microsoft.aad.msal4j.IManagedIdentityMtlsProvider Registers the KeyGuard provider.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/Pkcs10Builder.java Builds PKCS#10 CSRs.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/NCryptLibrary.java Defines Windows NCrypt bindings.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/MtlsMsiException.java Defines extension failures.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/KeyGuardMtlsBindingContext.java Creates JSSE binding contexts.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/KeyGuardManagedIdentityMtlsProvider.java Manages binding creation and rotation.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/ImdsV2Client.java Implements IMDS v2 requests and parsing.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/CngX509ExtendedKeyManager.java Supplies KeyGuard credentials to JSSE.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/CngSignatureSpi.java Implements CNG-backed RSA signing.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/CngRsaPrivateKey.java Wraps non-exportable CNG keys.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/CngProvider.java Registers CNG signature services.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/CngKeyGuard.java Implements KeyGuard and attestation interop.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/AttestationTokenCache.java Caches fresh attestation JWTs.
msal4j-mtls-extensions/src/main/java/com/microsoft/aad/msal4j/mtls/AttestationLibrary.java Defines attestation DLL bindings.
msal4j-mtls-extensions/README.md Documents extension usage.
msal4j-mtls-extensions/pom.xml Configures the extension artifact.
msal4j-mtls-extensions-e2e/src/main/java/com/microsoft/aad/msal4j/mtls/e2e/ManagedIdentityMtlsPopKeyVaultDevApp.java Implements manual Key Vault validation.
msal4j-mtls-extensions-e2e/pom.xml Builds the shaded validation app.
.github/copilot-instructions.md Documents the new architecture and modules.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/copilot-instructions.md Outdated
@gladjohn Gladwin Johnson VR (gladjohn) changed the title Gladjohn/java msi v2 mtls binding context local Add Managed Identity v2 KeyGuard mTLS PoP support Aug 16, 2026
@gladjohn
Gladwin Johnson VR (gladjohn) force-pushed the gladjohn/java-msi-v2-mtls-binding-context-local branch 3 times, most recently from e2b03ec to a0b0785 Compare August 16, 2026 15:09
Comment thread msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/HttpRequest.java

@g2vinay Vinay Gera (g2vinay) left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-reviewed after the latest fix commit. The mTLS PoP surface looks solid. Most of my remaining notes are consumer-side integration questions from the Azure SDK for Java side (azure-identity / azure-core), where these bindings will be wired into the HTTP pipeline across pluggable transports.

The higher-priority items are the SSLEngine alias path and issuer-independent alias selection in CngX509ExtendedKeyManager (our default reactor-netty and JDK HttpClient transports are engine-based and MI certs are self-issued), the resource-facing contract (whether the same cert must ride the data-plane call and what Authorization scheme to use for mtls_pop), and the transient-binding cache-reload path. The rest are clarifications on thread-safety, binding identity/rotation lifecycle, and the keyManager() vs sslContext() trust scope. None are blocking; mostly confirmations and a couple of test/javadoc asks. Thanks.

@Robbie-Microsoft
Robbie-Microsoft dismissed their stale review September 8, 2026 16:25

Review submitted in error and withdrawn.

Comment thread msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/DefaultHttpClient.java Outdated
Comment thread msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityResponse.java Outdated
Comment thread msal4j-mtls-extensions/pom.xml Outdated
Comment thread msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AuthenticationResult.java Outdated
@gladjohn
Gladwin Johnson VR (gladjohn) force-pushed the gladjohn/java-msi-v2-mtls-binding-context-local branch 2 times, most recently from 97351af to 0521d1e Compare September 9, 2026 20:56
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Add binding capability discovery and strength enforcement, expose transport-neutral TLS material, harden native loading, and expand local mTLS coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Re-check completed capability discovery synchronously so Java 8 cannot return a transiently unavailable result before the asynchronous cache-reset callback runs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Move attestation opt-in to the optional package, add bearer-over-mTLS, native logging, the IMDS v2 kill switch, DevEx documentation, and real-VM validation coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Add dedicated IMDS v1 and attested IMDS v2 pipeline jobs, preserve the existing hosted build, and bootstrap checksum-verified Java and Maven distributions on the Managed Identity agents.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
@gladjohn
Gladwin Johnson VR (gladjohn) force-pushed the gladjohn/java-msi-v2-mtls-binding-context-local branch from 0521d1e to 90f2d0a Compare September 9, 2026 21:00
Comment thread changelog.txt Outdated
Comment thread build/run-java-msi-v2-mtls-devapp.ps1
Remove the unreleased changelog entry and move the manual Managed Identity v2 validation script into the build directory while preserving repository-root execution and documentation links.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Move the existing IMDS v1 coverage into a separate managed identity E2E change so this PR remains focused on attested mTLS PoP.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
Disable redirects for credential-bound OAuth requests, clean failed attestation DLL extractions, and retain returned binding generations until certificate expiry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30714a3c-b1e6-4578-8223-e07611e44e1d
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.

6 participants