-
Notifications
You must be signed in to change notification settings - Fork 404
WIP POP improvements #2070
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
WIP POP improvements #2070
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 |
|---|---|---|
|
|
@@ -371,7 +371,6 @@ public T WithCorrelationId(Guid correlationId) | |
| /// <param name="httpRequestMessage">An HTTP request to the protected resource which requires a PoP token. The PoP token will be cryptographically bound to the request.</param> | ||
| /// <remarks> | ||
| /// <list type="bullet"> | ||
| /// <item>This is an experimental API. The method signature may change in the future without involving a major version upgrade.</item> | ||
| /// <item> An Authentication header is automatically added to the request</item> | ||
| /// <item> The PoP token is bound to the HTTP request, more specifically to the HTTP method (GET, POST, etc.) and to the Uri (path and query, but not query parameters). </item> | ||
| /// <item>MSAL creates, reads and stores a key in memory that will be cycled every 8 hours.</item> | ||
|
|
@@ -383,16 +382,23 @@ public T WithProofOfPosession(HttpRequestMessage httpRequestMessage) | |
| return WithProofOfPosession(httpRequestMessage, defaultCryptoProvider); | ||
| } | ||
|
|
||
| // Allows testing the PoP flow with any crypto. Consider making this public. | ||
| /// <summary> | ||
| /// Modifies the token acquisition request so that the acquired token is a Proof of Possession token (PoP), rather than a Bearer token. | ||
| /// PoP tokens are similar to Bearer tokens, but are bound to the HTTP request and to a cryptographic key, which MSAL can manage on Windows. | ||
| /// See https://aka.ms/msal-net-pop | ||
| /// </summary> | ||
| /// <param name="httpRequestMessage">An HTTP request to the protected resource which requires a PoP token. The PoP token will be cryptographically bound to the request.</param> | ||
| /// <param name="popCryptoProvider">A provider that can handle the asymmetric key operations needed by POP, that encapsulates a pair of | ||
| /// public and private keys and some typical crypto operations.</param> | ||
| /// <remarks> | ||
| /// <list type="bullet"> | ||
| /// <item> An Authentication header is automatically added to the request</item> | ||
| /// <item> The PoP token is bound to the HTTP request, more specifically to the HTTP method (GET, POST, etc.) and to the Uri (path and query, but not query parameters). </item> | ||
| /// <item>MSAL creates, reads and stores a key in memory that will be cycled every 8 hours.</item> | ||
| /// </list> | ||
| /// </remarks> | ||
| internal T WithProofOfPosession(HttpRequestMessage httpRequestMessage, IPoPCryptoProvider popCryptoProvider) | ||
| { | ||
| if (!ServiceBundle.Config.ExperimentalFeaturesEnabled) | ||
| { | ||
| throw new MsalClientException( | ||
| MsalError.ExperimentalFeature, | ||
| MsalErrorMessage.ExperimentalFeature(nameof(WithProofOfPosession))); | ||
| } | ||
|
|
||
| if (httpRequestMessage is null) | ||
| { | ||
| throw new ArgumentNullException(nameof(httpRequestMessage)); | ||
|
|
@@ -406,7 +412,67 @@ internal T WithProofOfPosession(HttpRequestMessage httpRequestMessage, IPoPCrypt | |
| CommonParameters.AddApiTelemetryFeature(ApiTelemetryFeature.WithPoPScheme); | ||
| CommonParameters.AuthenticationScheme = new PoPAuthenticationScheme(httpRequestMessage, popCryptoProvider); | ||
|
|
||
| return this as T; | ||
| return (T)this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Modifies the token acquisition request so that the acquired token is a Proof of Possession token (PoP), rather than a Bearer token. | ||
| /// PoP tokens are similar to Bearer tokens, but are bound to the HTTP request and to a cryptographic key, which MSAL can manage on Windows. | ||
| /// See https://aka.ms/msal-net-pop | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// <list type="bullet"> | ||
| /// <item> An Authentication header is automatically added to the request</item> | ||
| /// <item> The PoP token is bound to the HTTP request, more specifically to the HTTP method (GET, POST, etc.) and to the Uri (path and query, but not query parameters). </item> | ||
| /// <item>MSAL creates, reads and stores a key in memory that will be cycled every 8 hours.</item> | ||
| /// </list> | ||
| /// </remarks> | ||
| public T WithProofOfPosession() | ||
| { | ||
| CommonParameters.UsingProofOfPossesion = true; | ||
| return (T)this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Specifies the HTTP method of the HTTP request to the protected resource which requires a PoP token. | ||
| /// The PoP token will be cryptographically bound to the request. | ||
| /// </summary> | ||
| /// <param name="httpMethod">Http Method for proof of possesion request.</param> | ||
| /// <returns></returns> | ||
| public T WithProofOfPosessionMethod(HttpMethod httpMethod) | ||
| { | ||
| CommonParameters.PopMethod = httpMethod; | ||
| return (T)this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Specifies the URL of the HTTP request to the protected resource which requires a PoP token. | ||
| /// The PoP token will be cryptographically bound to the request. | ||
| /// </summary> | ||
| /// <param name="uri">Protected resource URL.</param> | ||
| /// <returns></returns> | ||
| public T WithProofOfPosessionUri(Uri uri) | ||
| { | ||
| CommonParameters.PopUri = uri; | ||
| return (T)this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Specifies a provider that can handle the asymmetric key operations needed by POP, that encapsulates a pair of | ||
| /// public and private keys and some typical crypto operations. | ||
| /// All symetric operations are SHA256 | ||
| /// </summary> | ||
| /// <param name="popCryptoProvider"> Proof of posession cryptography provider</param> | ||
| /// <returns></returns> | ||
| public T WithPopCryptoProvider(IPoPCryptoProvider popCryptoProvider) | ||
|
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 think you are trying to tackle 2 stories at the same time, which makes it difficult to implement and review:
I don't think you should tackle #2 right now, nobody asked for it and it will complicate things.
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 think To help figure out the best solution, I would recommend you try to create 2 implementations that will help our users:
Also, I believe that this public API should be discussed with Brian and George as well. |
||
| { | ||
| if (popCryptoProvider is null) | ||
| { | ||
| throw new ArgumentNullException(nameof(popCryptoProvider)); | ||
| } | ||
|
|
||
| CommonParameters.PopCryptoProvider = popCryptoProvider; | ||
| return (T)this; | ||
| } | ||
| #endif | ||
|
|
||
|
|
@@ -423,6 +489,25 @@ internal void ValidateAndCalculateApiId() | |
| CommonParameters.ApiId = CalculateApiEventId(); | ||
| CommonParameters.ApiTelemId = ApiTelemetryId; | ||
| CommonParameters.CorrelationId = CommonParameters.UseCorrelationIdFromUser ? CommonParameters.UserProvidedCorrelationId : Guid.NewGuid(); | ||
|
|
||
| #if DESKTOP || NET_CORE | ||
| if (CommonParameters.UsingProofOfPossesion) | ||
| { | ||
| if (CommonParameters.PopUri == null ) | ||
| { | ||
| throw new MsalClientException(MsalError.PopUriCannotBeNull, "Proof of possesion endpoint is null."); | ||
|
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. Uri is not mandatory as far as I understand. Please check with Brian / George. |
||
| } | ||
|
|
||
| HttpRequestMessage message = new HttpRequestMessage(CommonParameters.PopMethod != null ? CommonParameters.PopMethod : HttpMethod.Get, | ||
|
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. No, this isn't how it's supposed to work. The user has the ability to say "don't bind the method to the pop token". |
||
| CommonParameters.PopUri); | ||
|
|
||
| IPoPCryptoProvider defaultCryptoProvider = CommonParameters.PopCryptoProvider != null ? | ||
| CommonParameters.PopCryptoProvider : ServiceBundle.PlatformProxy.GetDefaultPoPCryptoProvider(); | ||
|
|
||
| CommonParameters.AddApiTelemetryFeature(ApiTelemetryFeature.WithPoPScheme); | ||
| CommonParameters.AuthenticationScheme = new PoPAuthenticationScheme(message, defaultCryptoProvider); | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
| } | ||
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.
I don't like this strategy of piling on options on the AcquireToken* method because it "polutes" . There will be at least 4 params on SHR -> 4 methods on each AcqurieToken* entry point.
Instead, you can add a simple config object, similar to
microsoft-authentication-library-for-dotnet/src/client/Microsoft.Identity.Client/ApiConfig/AcquireTokenInteractiveParameterBuilder.cs
Line 125 in 530d9f0
So we could have a single method:
WithPoP(PoPOptions options = null)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 main question here is - what should the default be here? I would argue for a secure default, where POP takes into account the method (GET / POST) and the url ...