-
Notifications
You must be signed in to change notification settings - Fork 241
MsAuth10AtPop part2 #2109
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
MsAuth10AtPop part2 #2109
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Security.Cryptography.X509Certificates; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Identity.Client; | ||
| using Microsoft.Identity.Client.Extensibility; | ||
| using Microsoft.IdentityModel.JsonWebTokens; | ||
| using Microsoft.IdentityModel.Tokens; | ||
|
|
||
| namespace Microsoft.Identity.Web | ||
| { | ||
| internal static class MsAuth10AtPop | ||
| { | ||
| public static AcquireTokenForClientParameterBuilder WithAtPop( | ||
| this AcquireTokenForClientParameterBuilder builder, | ||
| X509Certificate2 clientCertificate, | ||
| string popPublicKey, | ||
| string jwkClaim, | ||
| string clientId) | ||
| { | ||
| builder.WithProofOfPosessionKeyId(popPublicKey); | ||
| builder.OnBeforeTokenRequest((data) => | ||
| { | ||
| string? signedAssertion = GetSignedClientAssertion( | ||
| clientCertificate, | ||
| data.RequestUri.AbsoluteUri, | ||
| jwkClaim, | ||
| clientId); | ||
|
|
||
| data.BodyParameters.Remove("client_assertion"); | ||
| data.BodyParameters.Add("request", signedAssertion); | ||
| return Task.CompletedTask; | ||
| }); | ||
|
|
||
| return builder; | ||
| } | ||
|
|
||
| private static string? GetSignedClientAssertion( | ||
| X509Certificate2 certificate, | ||
| string audience, | ||
| string jwkClaim, | ||
| string clientId) | ||
| { | ||
| // no need to add exp, nbf as JsonWebTokenHandler will add them by default | ||
| var claims = new Dictionary<string, object>() | ||
| { | ||
| { "aud", audience }, | ||
| { "iss", clientId }, | ||
| { "jti", Guid.NewGuid().ToString() }, | ||
| { "sub", clientId }, | ||
| { "pop_jwk", jwkClaim } | ||
| }; | ||
|
|
||
| var securityTokenDescriptor = new SecurityTokenDescriptor | ||
| { | ||
| Claims = claims, | ||
| SigningCredentials = new X509SigningCredentials(certificate) | ||
| }; | ||
|
|
||
| var handler = new JsonWebTokenHandler(); | ||
| return handler.CreateToken(securityTokenDescriptor); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -370,15 +370,26 @@ public Task<AuthenticationResult> GetAuthenticationResultForAppAsync( | |
| { | ||
| builder.WithProofOfPossession(tokenAcquisitionOptions.PoPConfiguration); | ||
| } | ||
| if (tokenAcquisitionOptions.PopPublicKey != null) | ||
| if (!string.IsNullOrEmpty(tokenAcquisitionOptions.PopPublicKey)) | ||
| { | ||
| builder.WithProofOfPosessionKeyId(tokenAcquisitionOptions.PopPublicKey, "pop"); | ||
| builder.OnBeforeTokenRequest((data) => | ||
| if (string.IsNullOrEmpty(tokenAcquisitionOptions.JwkClaim)) | ||
| { | ||
| data.BodyParameters.Add("req_cnf", tokenAcquisitionOptions.PopPublicKey); | ||
| data.BodyParameters.Add("token_type", "pop"); | ||
| return Task.CompletedTask; | ||
| }); | ||
| builder.WithProofOfPosessionKeyId(tokenAcquisitionOptions.PopPublicKey, "pop"); | ||
| builder.OnBeforeTokenRequest((data) => | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this is "new POP" as defined by ESTS (as opposed to MsAuth10ATPOP)? I would add some comments here to make it clear. Not critical: For "new POP" I would recommend that you use MSAL's higher level API class CryptoProvider : IPoPCryptoProvider
{
string CannonicalPublicKeyJwk { get; } => JwkClaim;
string CryptographicAlgorithm { get; } => "RS256"; // RSA only
public byte[] Sign(byte[] data)
{
throw new NotImplementedException(); // Wilson will generate the SHR
}
}
PoPAuthenticationConfiguration config = new PoPAuthenticationConfiguration();
config.CryptoProvider = new CryptoProvider();
builder.WithProofOfPossesion(config);Note that this implies that MSAL computes the key id based on the JWK, i.e.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also note that this is RSA only. If you need to support other algorithms such as ECD, we need to run a small test to see if another param needs to be exposed or not. In MSAL we decided to expose
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also happy to hear how we can re-design the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jmprieur said you synced off-line and are okay with this proposal, is that right? |
||
| { | ||
| data.BodyParameters.Add("req_cnf", tokenAcquisitionOptions.PopPublicKey); | ||
| data.BodyParameters.Add("token_type", "pop"); | ||
| return Task.CompletedTask; | ||
| }); | ||
| } | ||
| else | ||
| { | ||
| builder.WithAtPop( | ||
| application.AppConfig.ClientCredentialCertificate, | ||
| tokenAcquisitionOptions.PopPublicKey, | ||
| tokenAcquisitionOptions.JwkClaim, | ||
| application.AppConfig.ClientId); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
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.
@bgavrilMS
Would it be possible, when we use builder.WithProofOfPosessionKeyId(popPublicKey) that MSAL does not compute the signed assertion? (as it's not necessary)
I can create a GitHub issue in the MSAL.NET repo if you agree.