Skip to content

Commit 4d18f82

Browse files
trwalketrwalke
andauthored
Adding WithExtraBodyParameters api (#5389)
* adding attribute authentication operation * Update * Adding WithExtraBodyParameters api * Adding extraBodyParameters api * Update * Update StorageCreationPropertiesBuilder.cs * Test fix * Adding additional checks to tests * Refactoring * Renaming test method * Reslving test error --------- Co-authored-by: trwalke <[email protected]>
1 parent 79234e2 commit 4d18f82

20 files changed

+466
-54
lines changed

src/client/Microsoft.Identity.Client/ApiConfig/AcquireTokenForClientParameterBuilder.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
using Microsoft.Identity.Client.Utils;
1616
using Microsoft.Identity.Client.Extensibility;
1717
using Microsoft.Identity.Client.OAuth2;
18+
using System.Security.Cryptography;
19+
using System.Text;
1820

1921
namespace Microsoft.Identity.Client
2022
{
@@ -44,9 +46,9 @@ internal static AcquireTokenForClientParameterBuilder Create(
4446

4547
if (!string.IsNullOrEmpty(confidentialClientApplicationExecutor.ServiceBundle.Config.CertificateIdToAssociateWithToken))
4648
{
47-
builder.WithAdditionalCacheKeyComponents(new SortedList<string, string>
49+
builder.WithAdditionalCacheKeyComponents(new SortedList<string, Func<CancellationToken, Task<string>>>
4850
{
49-
{ Constants.CertSerialNumber, confidentialClientApplicationExecutor.ServiceBundle.Config.CertificateIdToAssociateWithToken }
51+
{ Constants.CertSerialNumber, (CancellationToken ct) => { return Task.FromResult(confidentialClientApplicationExecutor.ServiceBundle.Config.CertificateIdToAssociateWithToken); } }
5052
});
5153
}
5254

@@ -141,9 +143,9 @@ public AcquireTokenForClientParameterBuilder WithFmiPath(string pathSuffix)
141143
throw new ArgumentNullException(nameof(pathSuffix));
142144
}
143145

144-
var cacheKey = new SortedList<string, string>
146+
var cacheKey = new SortedList<string, Func<CancellationToken, Task<string>>>
145147
{
146-
{ OAuth2Parameter.FmiPath, pathSuffix }
148+
{ OAuth2Parameter.FmiPath, (CancellationToken ct) => {return Task.FromResult(pathSuffix);} }
147149
};
148150

149151
this.WithAdditionalCacheKeyComponents(cacheKey);

src/client/Microsoft.Identity.Client/ApiConfig/Executors/ClientApplicationBaseExecutor.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
3333
var requestParameters = await _clientApplicationBase.CreateRequestParametersAsync(
3434
commonParameters,
3535
requestContext,
36-
_clientApplicationBase.UserTokenCacheInternal).ConfigureAwait(false);
36+
_clientApplicationBase.UserTokenCacheInternal,
37+
cancellationToken).ConfigureAwait(false);
3738

3839
requestParameters.SendX5C = silentParameters.SendX5C ?? false;
3940

@@ -59,7 +60,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
5960
var requestParameters = await _clientApplicationBase.CreateRequestParametersAsync(
6061
commonParameters,
6162
requestContext,
62-
_clientApplicationBase.UserTokenCacheInternal).ConfigureAwait(false);
63+
_clientApplicationBase.UserTokenCacheInternal,
64+
cancellationToken).ConfigureAwait(false);
6365

6466
requestContext.Logger.Info(() => LogMessages.UsingXScopesForRefreshTokenRequest(commonParameters.Scopes.Count()));
6567

src/client/Microsoft.Identity.Client/ApiConfig/Executors/ConfidentialClientExecutor.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
3939
AuthenticationRequestParameters requestParams = await _confidentialClientApplication.CreateRequestParametersAsync(
4040
commonParameters,
4141
requestContext,
42-
_confidentialClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
42+
_confidentialClientApplication.UserTokenCacheInternal,
43+
cancellationToken).ConfigureAwait(false);
4344
requestParams.SendX5C = authorizationCodeParameters.SendX5C ?? false;
4445

4546
var handler = new ConfidentialAuthCodeRequest(
@@ -60,7 +61,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
6061
AuthenticationRequestParameters requestParams = await _confidentialClientApplication.CreateRequestParametersAsync(
6162
commonParameters,
6263
requestContext,
63-
_confidentialClientApplication.AppTokenCacheInternal).ConfigureAwait(false);
64+
_confidentialClientApplication.AppTokenCacheInternal,
65+
cancellationToken).ConfigureAwait(false);
6466

6567
requestParams.SendX5C = clientParameters.SendX5C ?? false;
6668

@@ -82,7 +84,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
8284
AuthenticationRequestParameters requestParams = await _confidentialClientApplication.CreateRequestParametersAsync(
8385
commonParameters,
8486
requestContext,
85-
_confidentialClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
87+
_confidentialClientApplication.UserTokenCacheInternal,
88+
cancellationToken).ConfigureAwait(false);
8689

8790
requestParams.SendX5C = onBehalfOfParameters.SendX5C ?? false;
8891
requestParams.UserAssertion = onBehalfOfParameters.UserAssertion;
@@ -106,7 +109,8 @@ public async Task<Uri> ExecuteAsync(
106109
AuthenticationRequestParameters requestParameters = await _confidentialClientApplication.CreateRequestParametersAsync(
107110
commonParameters,
108111
requestContext,
109-
_confidentialClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
112+
_confidentialClientApplication.UserTokenCacheInternal,
113+
cancellationToken).ConfigureAwait(false);
110114

111115
requestParameters.Account = authorizationRequestUrlParameters.Account;
112116
requestParameters.LoginHint = authorizationRequestUrlParameters.LoginHint;
@@ -142,7 +146,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
142146
AuthenticationRequestParameters requestParams = await _confidentialClientApplication.CreateRequestParametersAsync(
143147
commonParameters,
144148
requestContext,
145-
_confidentialClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
149+
_confidentialClientApplication.UserTokenCacheInternal,
150+
cancellationToken).ConfigureAwait(false);
146151

147152
requestParams.SendX5C = usernamePasswordParameters.SendX5C ?? false;
148153

src/client/Microsoft.Identity.Client/ApiConfig/Executors/ManagedIdentityExecutor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
3838
var requestParams = await _managedIdentityApplication.CreateRequestParametersAsync(
3939
commonParameters,
4040
requestContext,
41-
_managedIdentityApplication.AppTokenCacheInternal).ConfigureAwait(false);
41+
_managedIdentityApplication.AppTokenCacheInternal,
42+
cancellationToken).ConfigureAwait(false);
4243

4344
var handler = new ManagedIdentityAuthRequest(
4445
ServiceBundle,

src/client/Microsoft.Identity.Client/ApiConfig/Executors/PublicClientExecutor.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
3131
AuthenticationRequestParameters requestParams = await _publicClientApplication.CreateRequestParametersAsync(
3232
commonParameters,
3333
requestContext,
34-
_publicClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
34+
_publicClientApplication.UserTokenCacheInternal,
35+
cancellationToken).ConfigureAwait(false);
3536

3637
requestParams.LoginHint = interactiveParameters.LoginHint;
3738
requestParams.Account = interactiveParameters.Account;
@@ -52,7 +53,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
5253
var requestParams = await _publicClientApplication.CreateRequestParametersAsync(
5354
commonParameters,
5455
requestContext,
55-
_publicClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
56+
_publicClientApplication.UserTokenCacheInternal,
57+
cancellationToken).ConfigureAwait(false);
5658

5759
var handler = new DeviceCodeRequest(
5860
ServiceBundle,
@@ -72,7 +74,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
7274
var requestParams = await _publicClientApplication.CreateRequestParametersAsync(
7375
commonParameters,
7476
requestContext,
75-
_publicClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
77+
_publicClientApplication.UserTokenCacheInternal,
78+
cancellationToken).ConfigureAwait(false);
7679

7780
var handler = new IntegratedWindowsAuthRequest(
7881
ServiceBundle,
@@ -92,7 +95,8 @@ public async Task<AuthenticationResult> ExecuteAsync(
9295
var requestParams = await _publicClientApplication.CreateRequestParametersAsync(
9396
commonParameters,
9497
requestContext,
95-
_publicClientApplication.UserTokenCacheInternal).ConfigureAwait(false);
98+
_publicClientApplication.UserTokenCacheInternal,
99+
cancellationToken).ConfigureAwait(false);
96100

97101
var handler = new UsernamePasswordRequest(
98102
ServiceBundle,

src/client/Microsoft.Identity.Client/ApiConfig/Parameters/AcquireTokenCommonParameters.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Security.Cryptography.X509Certificates;
7+
using System.Threading;
78
using System.Threading.Tasks;
89
using Microsoft.Identity.Client.AppConfig;
910
using Microsoft.Identity.Client.AuthScheme;
@@ -27,10 +28,10 @@ internal class AcquireTokenCommonParameters
2728
public IAuthenticationOperation AuthenticationOperation { get; set; } = new BearerAuthenticationOperation();
2829
public IDictionary<string, string> ExtraHttpHeaders { get; set; }
2930
public PoPAuthenticationConfiguration PopAuthenticationConfiguration { get; set; }
30-
public Func<OnBeforeTokenRequestData, Task> OnBeforeTokenRequestHandler { get; internal set; }
31+
public IList<Func<OnBeforeTokenRequestData, Task>> OnBeforeTokenRequestHandler { get; internal set; }
3132
public X509Certificate2 MtlsCertificate { get; internal set; }
3233
public List<string> AdditionalCacheParameters { get; set; }
33-
public SortedList<string, string> CacheKeyComponents { get; internal set; }
34+
public SortedList<string, Func<CancellationToken, Task<string>>> CacheKeyComponents { get; internal set; }
3435
public string FmiPathSuffix { get; internal set; }
3536
public string ClientAssertionFmiPath { get; internal set; }
3637
}

src/client/Microsoft.Identity.Client/ApplicationBase.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the MIT License.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Threading;
57
using System.Threading.Tasks;
68
using Microsoft.Identity.Client.ApiConfig.Parameters;
79
using Microsoft.Identity.Client.Internal;
@@ -27,18 +29,41 @@ internal ApplicationBase(ApplicationConfiguration config)
2729
internal virtual async Task<AuthenticationRequestParameters> CreateRequestParametersAsync(
2830
AcquireTokenCommonParameters commonParameters,
2931
RequestContext requestContext,
30-
ITokenCacheInternal cache)
32+
ITokenCacheInternal cache,
33+
CancellationToken cancellationToken)
3134
{
3235
Instance.Authority authority = await Instance.Authority.CreateAuthorityForRequestAsync(
3336
requestContext,
3437
commonParameters.AuthorityOverride).ConfigureAwait(false);
3538

39+
var cacheKeyComponents = await InitializeCacheKeyComponentsAsync(commonParameters.CacheKeyComponents, cancellationToken).ConfigureAwait(false);
40+
3641
return new AuthenticationRequestParameters(
3742
ServiceBundle,
3843
cache,
3944
commonParameters,
4045
requestContext,
41-
authority);
46+
authority,
47+
cacheKeyComponents: cacheKeyComponents);
48+
}
49+
50+
internal async Task<SortedList<string, string>> InitializeCacheKeyComponentsAsync(SortedList<string, Func<CancellationToken, Task<string>>> cacheKeyComponents, CancellationToken cancellationToken)
51+
{
52+
if (cacheKeyComponents != null && cacheKeyComponents.Count > 0)
53+
{
54+
var initializedCacheKeyComponents = new SortedList<string, string>();
55+
56+
foreach (var kvp in cacheKeyComponents)
57+
{
58+
if (kvp.Value != null)
59+
{
60+
initializedCacheKeyComponents.Add(kvp.Key, await kvp.Value.Invoke(cancellationToken).ConfigureAwait(false));
61+
}
62+
}
63+
return initializedCacheKeyComponents;
64+
}
65+
66+
return null;
4267
}
4368

4469
internal static void GuardMobileFrameworks()

src/client/Microsoft.Identity.Client/ConfidentialClientApplication.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,10 @@ AcquireTokenByRefreshTokenParameterBuilder IByRefreshToken.AcquireTokenByRefresh
207207
internal override async Task<AuthenticationRequestParameters> CreateRequestParametersAsync(
208208
AcquireTokenCommonParameters commonParameters,
209209
RequestContext requestContext,
210-
ITokenCacheInternal cache)
210+
ITokenCacheInternal cache,
211+
CancellationToken cancellationToken)
211212
{
212-
AuthenticationRequestParameters requestParams = await base.CreateRequestParametersAsync(commonParameters, requestContext, cache).ConfigureAwait(false);
213+
AuthenticationRequestParameters requestParams = await base.CreateRequestParametersAsync(commonParameters, requestContext, cache, cancellationToken).ConfigureAwait(false);
213214
return requestParams;
214215
}
215216
}

src/client/Microsoft.Identity.Client/Extensibility/AbstractConfidentialClientAcquireTokenParameterBuilderExtension.cs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections.Generic;
66
using System.Linq;
77
using System.Runtime.CompilerServices;
8+
using System.Threading;
89
using System.Threading.Tasks;
910
using Microsoft.Identity.Client.OAuth2;
1011

@@ -29,12 +30,14 @@ public static AbstractAcquireTokenParameterBuilder<T> OnBeforeTokenRequest<T>(
2930
Func<OnBeforeTokenRequestData, Task> onBeforeTokenRequestHandler)
3031
where T : AbstractAcquireTokenParameterBuilder<T>
3132
{
32-
if (builder.CommonParameters.OnBeforeTokenRequestHandler != null && onBeforeTokenRequestHandler != null)
33+
if (builder.CommonParameters.OnBeforeTokenRequestHandler == null)
3334
{
34-
throw new InvalidOperationException("Cannot set OnBeforeTokenRequest handler twice.");
35+
builder.CommonParameters.OnBeforeTokenRequestHandler = new List<Func<OnBeforeTokenRequestData, Task>> { onBeforeTokenRequestHandler };
36+
}
37+
else
38+
{
39+
builder.CommonParameters.OnBeforeTokenRequestHandler.Add(onBeforeTokenRequestHandler);
3540
}
36-
37-
builder.CommonParameters.OnBeforeTokenRequestHandler = onBeforeTokenRequestHandler;
3841

3942
return builder;
4043
}
@@ -75,13 +78,18 @@ public static AbstractAcquireTokenParameterBuilder<T> WithAuthenticationExtensio
7578
MsalAuthenticationExtension authenticationExtension)
7679
where T : AbstractAcquireTokenParameterBuilder<T>
7780
{
78-
if (builder.CommonParameters.OnBeforeTokenRequestHandler != null && authenticationExtension.OnBeforeTokenRequestHandler != null)
81+
if (authenticationExtension.OnBeforeTokenRequestHandler != null)
7982
{
80-
throw new InvalidOperationException("Cannot set both an AuthenticationOperation and an OnBeforeTokenRequestHandler");
83+
if (builder.CommonParameters.OnBeforeTokenRequestHandler == null)
84+
{
85+
builder.CommonParameters.OnBeforeTokenRequestHandler = new List<Func<OnBeforeTokenRequestData, Task>> { authenticationExtension.OnBeforeTokenRequestHandler };
86+
}
87+
else
88+
{
89+
builder.CommonParameters.OnBeforeTokenRequestHandler.Add(authenticationExtension.OnBeforeTokenRequestHandler);
90+
}
8191
}
8292

83-
builder.CommonParameters.OnBeforeTokenRequestHandler = authenticationExtension.OnBeforeTokenRequestHandler;
84-
8593
if (authenticationExtension.AuthenticationOperation != null)
8694
builder.WithAuthenticationOperation(authenticationExtension.AuthenticationOperation);
8795

@@ -137,7 +145,7 @@ public static AbstractAcquireTokenParameterBuilder<T> WithAdditionalCacheParamet
137145
/// </remarks>
138146
internal static AbstractAcquireTokenParameterBuilder<T> WithAdditionalCacheKeyComponents<T>(
139147
this AbstractAcquireTokenParameterBuilder<T> builder,
140-
IDictionary<string, string> cacheKeyComponents)
148+
IDictionary<string, Func<CancellationToken, Task<string>>> cacheKeyComponents)
141149
where T : AbstractAcquireTokenParameterBuilder<T>
142150
{
143151
if (cacheKeyComponents == null || cacheKeyComponents.Count == 0)
@@ -148,7 +156,7 @@ internal static AbstractAcquireTokenParameterBuilder<T> WithAdditionalCacheKeyCo
148156

149157
if (builder.CommonParameters.CacheKeyComponents == null)
150158
{
151-
builder.CommonParameters.CacheKeyComponents = new SortedList<string, string>(cacheKeyComponents);
159+
builder.CommonParameters.CacheKeyComponents = new SortedList<string, Func<CancellationToken, Task<string>>>(cacheKeyComponents);
152160
}
153161
else
154162
{
@@ -187,9 +195,9 @@ public static AbstractAcquireTokenParameterBuilder<T> WithFmiPathForClientAssert
187195
builder.CommonParameters.ClientAssertionFmiPath = fmiPath;
188196

189197
// Add the fmi_path to the cache key so that it is used for cache lookups
190-
var cacheKey = new SortedList<string, string>
198+
var cacheKey = new SortedList<string, Func<CancellationToken, Task<string>>>
191199
{
192-
{ "credential_fmi_path", fmiPath }
200+
{ "credential_fmi_path", (CancellationToken ct) => Task.FromResult(fmiPath) }
193201
};
194202

195203
WithAdditionalCacheKeyComponents(builder, cacheKey);

src/client/Microsoft.Identity.Client/Extensibility/AcquireTokenForClientBuilderExtensions.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using System.ComponentModel;
77
using System.Diagnostics.CodeAnalysis;
88
using System.Text;
9+
using System.Threading;
10+
using System.Threading.Tasks;
911
using Microsoft.Identity.Client.Cache;
1012
using Microsoft.Identity.Client.OAuth2;
1113

@@ -40,5 +42,35 @@ public static AcquireTokenForClientParameterBuilder WithProofOfPosessionKeyId(
4042

4143
return builder;
4244
}
45+
46+
/// <summary>
47+
/// Add extra body parameters to the token request. These parameters are added to the cache key to associate these parameters with the acquired token.
48+
/// </summary>
49+
/// <param name="builder"></param>
50+
/// <param name="extrabodyparams">List of additional body parameters</param>
51+
/// <returns></returns>
52+
public static AcquireTokenForClientParameterBuilder WithExtraBodyParameters(
53+
this AcquireTokenForClientParameterBuilder builder,
54+
Dictionary<string, Func<CancellationToken, Task<string>>> extrabodyparams)
55+
{
56+
builder.ValidateUseOfExperimentalFeature();
57+
if (extrabodyparams == null || extrabodyparams.Count == 0)
58+
{
59+
return builder;
60+
}
61+
builder.OnBeforeTokenRequest(async (data) =>
62+
{
63+
foreach (var param in extrabodyparams)
64+
{
65+
if (param.Value != null)
66+
{
67+
data.BodyParameters.Add(param.Key, await param.Value(data.CancellationToken).ConfigureAwait(false));
68+
}
69+
}
70+
});
71+
72+
builder.WithAdditionalCacheKeyComponents(extrabodyparams);
73+
return builder;
74+
}
4375
}
4476
}

0 commit comments

Comments
 (0)