Skip to content

Commit 697d10f

Browse files
authored
Add CAE claims support for FIC + Managed Identity (#3647)
* revoke * Make MSI client assertion HttpClient injection test internal * make it internal
1 parent 4cbb58a commit 697d10f

File tree

5 files changed

+349
-6
lines changed

5 files changed

+349
-6
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
#nullable enable
2+
Microsoft.Identity.Web.ManagedIdentityClientAssertion.ManagedIdentityClientAssertion(string? managedIdentityClientId, string? tokenExchangeUrl, Microsoft.Extensions.Logging.ILogger? logger, Microsoft.Identity.Client.IMsalHttpClientFactory? testHttpClientFactory) -> void
3+
Microsoft.Identity.Web.TestOnly.ManagedIdentityClientAssertionTestHook
4+
static Microsoft.Identity.Web.TestOnly.ManagedIdentityClientAssertionTestHook.HttpClientFactoryForTests.get -> Microsoft.Identity.Client.IMsalHttpClientFactory?
5+
static Microsoft.Identity.Web.TestOnly.ManagedIdentityClientAssertionTestHook.HttpClientFactoryForTests.set -> void

src/Microsoft.Identity.Web.Certificateless/ManagedIdentityClientAssertion.cs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.Identity.Client.AppConfig;
1010
using Microsoft.Identity.Client.Extensibility;
1111
using Microsoft.Identity.Web.Certificateless;
12+
using Microsoft.Identity.Web.TestOnly;
1213

1314
namespace Microsoft.Identity.Web
1415
{
@@ -17,7 +18,7 @@ namespace Microsoft.Identity.Web
1718
/// </summary>
1819
public class ManagedIdentityClientAssertion : ClientAssertionProviderBase
1920
{
20-
IManagedIdentityApplication _managedIdentityApplication;
21+
private IManagedIdentityApplication _managedIdentityApplication;
2122
private readonly string _tokenExchangeUrl;
2223
private readonly ILogger? _logger;
2324

@@ -49,7 +50,33 @@ public ManagedIdentityClientAssertion(string? managedIdentityClientId, string? t
4950
/// <param name="tokenExchangeUrl">Optional audience of the token to be requested from Managed Identity. Default value is "api://AzureADTokenExchange".
5051
/// This value is different on clouds other than Azure Public</param>
5152
/// <param name="logger">A logger</param>
52-
public ManagedIdentityClientAssertion(string? managedIdentityClientId, string? tokenExchangeUrl, ILogger? logger)
53+
public ManagedIdentityClientAssertion(
54+
string? managedIdentityClientId,
55+
string? tokenExchangeUrl,
56+
ILogger? logger)
57+
: this(
58+
managedIdentityClientId,
59+
tokenExchangeUrl,
60+
logger,
61+
ManagedIdentityClientAssertionTestHook.HttpClientFactoryForTests)
62+
{
63+
}
64+
65+
66+
/// <summary>
67+
/// Same as <see cref="ManagedIdentityClientAssertion(string?, string?, ILogger?)"/>,
68+
/// but allows injecting a custom MSAL HttpClient factory (used by tests).
69+
/// </summary>
70+
/// <param name="managedIdentityClientId">Optional ClientId of the Managed Identity</param>
71+
/// <param name="tokenExchangeUrl">Optional audience of the token to be requested from Managed Identity. Default value is "api://AzureADTokenExchange".
72+
/// This value is different on clouds other than Azure Public</param>
73+
/// <param name="logger">A logger.</param>
74+
/// <param name="testHttpClientFactory">Optional MSAL HttpClient factory.</param>
75+
internal ManagedIdentityClientAssertion(
76+
string? managedIdentityClientId,
77+
string? tokenExchangeUrl,
78+
ILogger? logger,
79+
IMsalHttpClientFactory? testHttpClientFactory)
5380
{
5481
_tokenExchangeUrl = tokenExchangeUrl ?? CertificatelessConstants.DefaultTokenExchangeUrl;
5582
_logger = logger;
@@ -61,6 +88,12 @@ public ManagedIdentityClientAssertion(string? managedIdentityClientId, string? t
6188
}
6289

6390
var builder = ManagedIdentityApplicationBuilder.Create(id);
91+
92+
if (testHttpClientFactory != null)
93+
{
94+
builder = builder.WithHttpClientFactory(testHttpClientFactory);
95+
}
96+
6497
if (_logger != null)
6598
{
6699
builder = builder.WithLogging(Log, ConvertMicrosoftExtensionsLogLevelToMsal(_logger), enablePiiLogging: false);
@@ -76,10 +109,24 @@ public ManagedIdentityClientAssertion(string? managedIdentityClientId, string? t
76109
/// acquired with managed identity (certificateless).
77110
/// </summary>
78111
/// <returns>The signed assertion.</returns>
79-
protected override async Task<ClientAssertion> GetClientAssertionAsync(AssertionRequestOptions? assertionRequestOptions)
112+
protected override async Task<ClientAssertion> GetClientAssertionAsync(
113+
AssertionRequestOptions? assertionRequestOptions)
80114
{
81-
var result = await _managedIdentityApplication
82-
.AcquireTokenForManagedIdentity(_tokenExchangeUrl)
115+
// Start the MI token request for the token-exchange audience
116+
var miBuilder = _managedIdentityApplication
117+
.AcquireTokenForManagedIdentity(_tokenExchangeUrl);
118+
119+
if (assertionRequestOptions is not null)
120+
{
121+
// Propagate claims into the MI token request.
122+
// This also forces MSAL to bypass the MI token cache when claims are present.
123+
if (!string.IsNullOrEmpty(assertionRequestOptions.Claims))
124+
{
125+
miBuilder.WithClaims(assertionRequestOptions.Claims);
126+
}
127+
}
128+
129+
var result = await miBuilder
83130
.ExecuteAsync(assertionRequestOptions?.CancellationToken ?? CancellationToken.None)
84131
.ConfigureAwait(false);
85132

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Identity.Client;
5+
6+
namespace Microsoft.Identity.Web.TestOnly
7+
{
8+
/// <summary>
9+
/// TEST-ONLY hook so unit tests can override the HttpClient factory used by
10+
/// ManagedIdentityClientAssertion.
11+
/// </summary>
12+
internal static class ManagedIdentityClientAssertionTestHook
13+
{
14+
/// <summary>
15+
/// Gets or sets the <see cref="IMsalHttpClientFactory"/> used by <c>ManagedIdentityClientAssertion</c> for unit testing purposes.
16+
/// </summary>
17+
internal static IMsalHttpClientFactory? HttpClientFactoryForTests { get; set; }
18+
}
19+
}

src/Microsoft.Identity.Web/Resource/MicrosoftIdentityIssuerValidatorFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class MicrosoftIdentityIssuerValidatorFactory
1717
/// Initializes a new instance of the <see cref="MicrosoftIdentityIssuerValidatorFactory"/> class.
1818
/// </summary>
1919
/// <param name="aadIssuerValidatorOptions">Options passed-in to create the AadIssuerValidator object.</param>
20-
/// <param name="httpClientFactory">HttpClientFactory.</param>
20+
/// <param name="httpClientFactory">HttpClientFactoryForTests.</param>
2121
public MicrosoftIdentityIssuerValidatorFactory(
2222
IOptions<AadIssuerValidatorOptions> aadIssuerValidatorOptions,
2323
IHttpClientFactory httpClientFactory)

0 commit comments

Comments
 (0)