Skip to content

Add FIC Leg 2 over mTLS Proof-of-Possession (stacked on #1040)#1041

Open
Robbie-Microsoft wants to merge 6 commits into
rginsburg/sni-mtls-popfrom
rginsburg/sni-mtls-pop-fic-leg2
Open

Add FIC Leg 2 over mTLS Proof-of-Possession (stacked on #1040)#1041
Robbie-Microsoft wants to merge 6 commits into
rginsburg/sni-mtls-popfrom
rginsburg/sni-mtls-pop-fic-leg2

Conversation

@Robbie-Microsoft

@Robbie-Microsoft Robbie-Microsoft commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1040. Adds the 2-leg Federated Identity Credential (FIC) over mTLS Proof-of-Possession (PoP), where the consuming app authenticates with a federated client assertion yet still binds the resulting token to a certificate. Both legs are cert-bound and the final token is bound to the Leg-1 certificate thumbprint.

Stacked on #1040. This PR targets rginsburg/sni-mtls-pop so its diff is exactly the Leg-2 additions on top of the core direct SN/I → mTLS PoP work. Retarget the base to dev after #1040 merges.

Public API

// FIC Leg 2: assertion-authenticated app that must still bind to a cert
ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromClientAssertion(t1))
        .mtlsBindingCertificate(sniCert)   // binding cert presented on the TLS handshake
        .build();
  • ConfidentialClientApplication.Builder.mtlsBindingCertificate(IClientCertificate)

Internal changes

  • Request building (TokenRequestExecutor): when authenticating with a client assertion under mTLS PoP, the assertion is sent with client_assertion_type=...:jwt-pop and the binding certificate is presented on the mutual-TLS handshake.
  • MtlsClientCertificateHelper resolves the binding certificate from the configured mtlsBindingCertificate(...) when the request/app credential is a federated assertion (rather than a direct certificate).
  • AssertionRequestOptions carries the PoP flag through to assertion construction; ClientAssertion.ASSERTION_TYPE_JWT_POP constant added.

Testing

  • Unit: re-adds ficLeg2_assertionWithBindingCert_usesJwtPopAssertionType (MtlsProofOfPossessionTest) and resolveBindingCertificate_assertionWithBindingCert_returnsBindingCert (MtlsClientCertificateHelperTest).
  • E2E: re-adds acquireTokenFic_TwoLeg_MtlsPop_BothLegsBound (MtlsPopIT, CI-only — requires the lab SN/I cert + an ESTS allow-listed resource).

Notes

Adds the 2-leg Federated Identity Credential (FIC) flow over mTLS PoP: an assertion-authenticated confidential client can bind to a certificate via ConfidentialClientApplication.Builder.mtlsBindingCertificate(...), presenting the binding certificate on the TLS handshake and authenticating the federated assertion with client_assertion_type=...:jwt-pop. Both legs are cert-bound and the final token is bound to the Leg-1 certificate thumbprint.

Stacked on #1040 (core direct SN/I -> mTLS PoP); retarget base to dev after #1040 merges.

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

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

This PR extends MSAL4J’s confidential-client mTLS Proof-of-Possession (PoP) support to cover 2-leg Federated Identity Credential (FIC) “Leg 2” scenarios, where the app authenticates using a client assertion while still binding the resulting token to a certificate presented on the mTLS handshake.

Changes:

  • Add ConfidentialClientApplication.Builder.mtlsBindingCertificate(IClientCertificate) to supply a binding certificate for assertion-authenticated mTLS PoP requests.
  • Update token request construction to use client_assertion_type=...:jwt-pop when mtlsProofOfPossession() is set with a client assertion credential.
  • Re-introduce unit/integration tests and expand the sample/docs to demonstrate the 2-leg FIC over mTLS PoP flow.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ConfidentialClientApplication.java Adds builder option + getter for mtlsBindingCertificate used to present a cert on the mTLS handshake for assertion-authenticated apps.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java Switches client-assertion requests to jwt-pop assertion type under mTLS PoP and threads PoP context to assertion construction.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MtlsClientCertificateHelper.java Extends binding-certificate resolution to fall back to mtlsBindingCertificate for assertion-authenticated scenarios.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ClientCredentialParameters.java Updates mTLS PoP Javadoc to mention mtlsBindingCertificate(...) for assertion-authenticated apps.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ClientAssertion.java Introduces ASSERTION_TYPE_JWT_POP constant for client_assertion_type.
msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AssertionRequestOptions.java Adds a PoP flag to the context passed to context-aware assertion providers.
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MtlsProofOfPossessionTest.java Re-adds unit coverage for “FIC Leg 2” behavior (jwt-pop + binding cert).
msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MtlsClientCertificateHelperTest.java Adds unit test to ensure binding cert resolves correctly for assertion-authenticated apps.
msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/MtlsPopIT.java Re-adds CI-only E2E test covering the 2-leg FIC mTLS PoP flow.
msal4j-sdk/src/samples/confidential-client/ClientCredentialMtlsProofOfPossession.java Adds an end-to-end sample scenario showing developer-orchestrated 2-leg FIC over mTLS PoP.
changelog.txt Notes the new 2-leg FIC over mTLS PoP capability.
.github/copilot-instructions.md Updates internal repo guidance to mention mtlsBindingCertificate(...) for 2-leg FIC over mTLS PoP.

The Unit Tests build's Credential Scanner (Guardian) gate flags the checked-in PKCS12 test cert (mtls_test_cert.p12), failing the build. It is a self-signed, test-only certificate (CN=msal4j-mtls-test) with no production secret, so allowlist it in build/credscan-exclude.json.

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

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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Comment thread msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/MtlsProofOfPossessionTest.java Outdated
Robbie-Microsoft and others added 4 commits July 7, 2026 18:25
Pulls in the mTLS PoP socket-factory JDK 8 fix and the ClientCredentialParameters thread-safety/comment fixes from #1040. Resolved copilot-instructions.md to keep the FIC Leg 2 sentence alongside the Key Classes markdown split.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The FIC Leg 2 mTLS PoP test now parses the url-encoded body and asserts exact decoded values for client_assertion, client_assertion_type (via the JWT_POP_ASSERTION_TYPE constant, previously unused), and token_type, instead of brittle substring checks.

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

# Conflicts:
#	msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MtlsClientCertificateHelper.java
…-leg2

# Conflicts:
#	msal4j-sdk/src/integrationtest/java/com/microsoft/aad/msal4j/MtlsPopIT.java
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.

2 participants