-
Notifications
You must be signed in to change notification settings - Fork 160
Add SN/I certificate support over mTLS Proof-of-Possession (PoP) #1040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Robbie-Microsoft
wants to merge
17
commits into
dev
Choose a base branch
from
rginsburg/sni-mtls-pop
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,161
−24
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
d8cac48
Add SN/I certificate support over mTLS Proof-of-Possession (PoP)
Robbie-Microsoft 150a554
Extract FIC Leg 2 (mTLS PoP) into a follow-up PR
Robbie-Microsoft 68d3715
Suppress CredScan finding for self-signed mTLS test certificate
Robbie-Microsoft 66d59db
Fix mTLS PoP socket factory on JDK 8 and address review feedback
Robbie-Microsoft e6dee5f
Build mTLS PoP socket factory from a live key manager (support non-ex…
Robbie-Microsoft 288df02
Point MtlsPopIT at the SN/I-allow-listed app for mTLS PoP
Robbie-Microsoft 6bf6024
Fail closed on mTLS PoP token_type downgrade
Robbie-Microsoft f848b54
Remove unused telemetryValue from TokenType
Robbie-Microsoft 3ff929c
Align mTLS PoP with MSAL.NET: sovereign-cloud guard, cache metadata, …
Robbie-Microsoft 3ef7681
Align mTLS PoP cloud eligibility with MSAL.NET: allow Azure Gov + cur…
Robbie-Microsoft d576db6
Wrap non-base64 x5c decode as CertificateException in mTLS binding cert
Robbie-Microsoft 683e54e
Harden SNI mTLS PoP E2E: prove real resource usability, skip off-CI, …
Robbie-Microsoft 3858dc3
Assert mtls_pop directly in E2E; drop skip-on-downgrade escape hatch
Robbie-Microsoft d22059a
Exercise regional mtlsauth endpoint on the deterministic Bearer E2E cell
Robbie-Microsoft 48fd92d
Merge origin/dev into rginsburg/sni-mtls-pop (resync mTLS PoP with base)
Robbie-Microsoft 29fc91b
Surface Graph error body on non-2xx in mTLS PoP resource-call helper
Robbie-Microsoft 1805895
Set explicit Accept header in mTLS PoP resource call to avoid Graph 400
Robbie-Microsoft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,9 @@ | ||
| { | ||
| "tool": "Credential Scanner", | ||
| "suppressions": [ | ||
| { | ||
| "file": "msal4j-sdk/src/test/resources/mtls_test_cert.p12", | ||
| "_justification": "Self-signed, test-only certificate (CN=msal4j-mtls-test) used by unit tests for mTLS Proof-of-Possession. Contains no production secret." | ||
| } | ||
| ] | ||
| } | ||
| } |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # SN/I certificate over mTLS Proof-of-Possession (PoP) | ||
|
|
||
| MSAL4J lets a confidential-client application present its **Subject-Name/Issuer (SN/I) certificate as | ||
| the client TLS certificate** during the mutual-TLS handshake to the token endpoint. Entra ID (ESTS) | ||
| then returns an access token that is **cryptographically bound to that certificate** | ||
| (`token_type=mtls_pop`, bound via `cnf` / `x5t#S256`), instead of a plain Bearer token. | ||
|
|
||
| The credential is exactly the same certificate you already use for SN/I authentication — only the | ||
| mechanism changes: instead of signing a `private_key_jwt` (x5c) client assertion, the certificate is | ||
| presented on the TLS handshake. | ||
|
|
||
| > mTLS PoP is a **confidential-client** feature. It is distinct from the broker-based Signed-HTTP-Request | ||
| > (SHR) PoP used by public clients (`token_type=pop`), which is unaffected. | ||
|
|
||
| ## Enabling it | ||
|
|
||
| Opt in per request with `ClientCredentialParameters.Builder.mtlsProofOfPossession()`: | ||
|
|
||
| ```java | ||
| ConfidentialClientApplication cca = | ||
| ConfidentialClientApplication.builder(CLIENT_ID, sniCertificate) | ||
| .authority("https://login.microsoftonline.com/<tenant>/") // tenanted authority required | ||
| // .azureRegion("westus") // OPTIONAL — omit for the global mtlsauth.microsoft.com endpoint | ||
| .build(); | ||
|
|
||
| ClientCredentialParameters parameters = | ||
| ClientCredentialParameters | ||
| .builder(Collections.singleton("https://graph.microsoft.com/.default")) | ||
| .mtlsProofOfPossession() // request an mTLS-bound PoP token | ||
| .build(); | ||
|
|
||
| IAuthenticationResult result = cca.acquireToken(parameters).join(); | ||
|
|
||
| result.metadata().tokenType(); // TokenType.MTLS_POP | ||
| result.metadata().bindingCertificate(); // public material only: x5c chain + x5t#S256 thumbprint | ||
| ``` | ||
|
|
||
| The resulting token is bound to the certificate. To call a protected resource, present the **same | ||
| certificate** on the TLS handshake and send the token with the `mtls_pop` authorization scheme: | ||
|
|
||
| ``` | ||
| Authorization: mtls_pop <access_token> | ||
| ``` | ||
|
|
||
| `BindingCertificate` exposes public material only (the `x5c` chain and the SHA-256 thumbprint); the | ||
| private key is never exported — it is used in place through its own provider. | ||
|
|
||
| ## Bearer vs. mTLS PoP | ||
|
|
||
| Without `mtlsProofOfPossession()`, the SN/I certificate behaves exactly as before: it **signs and sends | ||
| a `private_key_jwt` client assertion**, and the result is a `TokenType.BEARER` token with no binding | ||
| certificate. Omitting the client assertion (and presenting the certificate on the TLS handshake | ||
| instead) is **specific to the mTLS PoP path**; the legacy SNI + Bearer flow is unchanged. | ||
|
|
||
| Bearer and mTLS-PoP tokens for the same scope are cached separately (keyed on | ||
| `{token_type + certificate key id}`), so enabling PoP never aliases an existing Bearer entry. | ||
|
|
||
| ## Requirements and notes | ||
|
|
||
| - **Tenanted authority is required.** `/common` and `/organizations` are rejected on the mTLS PoP path. | ||
| - **Region is optional.** Omit `azureRegion(...)` to use the global `mtlsauth.microsoft.com` endpoint | ||
| (production-ready via ESTS-R regional failover), or set a region to target | ||
| `<region>.mtlsauth.microsoft.com` (recommended when you know your region). | ||
| - **Resource audience must be allow-listed.** ESTS gates mTLS PoP on the **final resource audience**, | ||
| which must be an ESTS mTLS-PoP allow-listed resource (for example Azure Key Vault or Microsoft Graph), | ||
| not the client app itself. | ||
| - **Cloud support.** Azure Public, Azure Government, and the current national clouds are supported (the | ||
| `login.*` authority host is rewritten to the matching `mtlsauth.*` host). Two legacy sovereign hosts | ||
| that have no `mtlsauth.*` endpoint — `login.usgovcloudapi.net` and `login.chinacloudapi.cn` — are not | ||
| supported and fail fast. | ||
|
|
||
| See also the runnable sample: | ||
| [`src/samples/confidential-client/ClientCredentialMtlsProofOfPossession.java`](../src/samples/confidential-client/ClientCredentialMtlsProofOfPossession.java), | ||
| and https://aka.ms/msal4j-pop. |
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in this PR definitely weren't released a month ago.