Skip to content

Commit 6db71d7

Browse files
authored
Merge branch 'master' into trwalke/ExtraParameteAttributes
2 parents 7af25dc + 4b75729 commit 6db71d7

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

src/Microsoft.Identity.Web.AgentIdentities/AgentUserIdentityMsalAddIn.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal static Task OnBeforeUserFicForAgentUserIdentityAsync(
4444
string authenticationScheme = authenticationSchemeInformationProvider.GetEffectiveAuthenticationScheme(options.AuthenticationOptionsName);
4545
ITokenAcquirer tokenAcquirer = tokenAcquirerFactory.GetTokenAcquirer(authenticationScheme);
4646
ITokenAcquirer agentApplicationTokenAcquirer = tokenAcquirerFactory.GetTokenAcquirer();
47-
AcquireTokenResult aaFic = await agentApplicationTokenAcquirer.GetFicTokenAsync(new() { FmiPath = agentIdentity }); // Uses the regular client credentials
47+
AcquireTokenResult aaFic = await agentApplicationTokenAcquirer.GetFicTokenAsync(new() { Tenant = options.Tenant, FmiPath = agentIdentity }); // Uses the regular client credentials
4848
string? clientAssertion = aaFic.AccessToken;
4949

5050
// Get the FIC token for the agent identity.
@@ -54,9 +54,9 @@ internal static Task OnBeforeUserFicForAgentUserIdentityAsync(
5454
ClientId = agentIdentity,
5555
Instance = microsoftIdentityApplicationOptions.Instance,
5656
Authority = microsoftIdentityApplicationOptions.Authority,
57-
TenantId = microsoftIdentityApplicationOptions.TenantId
57+
TenantId = options.Tenant ?? microsoftIdentityApplicationOptions.TenantId
5858
});
59-
AcquireTokenResult aidFic = await agentIdentityTokenAcquirer.GetFicTokenAsync(clientAssertion: clientAssertion); // Uses the agent identity
59+
AcquireTokenResult aidFic = await agentIdentityTokenAcquirer.GetFicTokenAsync(options: new() { Tenant = options.Tenant }, clientAssertion: clientAssertion); // Uses the agent identity
6060
string? userFicAssertion = aidFic.AccessToken;
6161

6262
// Already in the request:

src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ public async Task<AuthenticationResult> GetAuthenticationResultForUserAsync(
267267
// If the user is not null and has claims xms-username and xms-password, perform ROPC for CCA
268268
authenticationResult = await TryGetAuthenticationResultForConfidentialClientUsingRopcAsync(
269269
application,
270+
tenantId,
270271
scopes,
271272
user,
272273
mergedOptions,
@@ -338,7 +339,13 @@ public async Task<AuthenticationResult> GetAuthenticationResultForUserAsync(
338339
}
339340

340341
// This method mutate the user claims to include claims uid and utid to perform the silent flow for subsequent calls.
341-
private async Task<AuthenticationResult?> TryGetAuthenticationResultForConfidentialClientUsingRopcAsync(IConfidentialClientApplication application, IEnumerable<string> scopes, ClaimsPrincipal? user, MergedOptions mergedOptions, TokenAcquisitionOptions? tokenAcquisitionOptions)
342+
private async Task<AuthenticationResult?> TryGetAuthenticationResultForConfidentialClientUsingRopcAsync(
343+
IConfidentialClientApplication application,
344+
string? tenantId,
345+
IEnumerable<string> scopes,
346+
ClaimsPrincipal? user,
347+
MergedOptions mergedOptions,
348+
TokenAcquisitionOptions? tokenAcquisitionOptions)
342349
{
343350
string? username = null;
344351
string? password = null;
@@ -426,6 +433,11 @@ public async Task<AuthenticationResult> GetAuthenticationResultForUserAsync(
426433
{
427434
builder.WithSignedHttpRequestProofOfPossession(tokenAcquisitionOptions.PoPConfiguration);
428435
}
436+
437+
if (!string.IsNullOrEmpty(tenantId))
438+
{
439+
builder.WithTenantId(tenantId);
440+
}
429441
}
430442

431443
var authenticationResult = await builder.ExecuteAsync().ConfigureAwait(false);

tests/E2E Tests/AgentApplications/AgentUserIdentityTestscs.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,62 @@ public async Task AgentUserIdentityGetsTokenForGraphAsync()
6464
#endif
6565
}
6666

67+
[Fact]
68+
public async Task AgentUserIdentityGetsTokenForGraphWithTenantOverrideAsync()
69+
{
70+
string instance = "https://login.microsoftonline.com/";
71+
string tenantId = "31a58c3b-ae9c-4448-9e8f-e9e143e800df"; // Replace with your tenant ID
72+
string agentApplication = "d15884b6-a447-4dd5-a5a5-a668c49f6300"; // Replace with the actual agent application client ID
73+
string agentIdentity = "d84da24a-2ea2-42b8-b5ab-8637ec208024"; // Replace with the actual agent identity
74+
string userUpn = "aui1@msidlabtoint.onmicrosoft.com"; // Replace with the actual user upn.
75+
76+
IServiceCollection services = new ServiceCollection();
77+
78+
// Configure the information about the agent application
79+
services.Configure<MicrosoftIdentityApplicationOptions>(
80+
options =>
81+
{
82+
options.Instance = instance;
83+
options.TenantId = "common"; // Replace with your tenant ID
84+
options.ClientId = agentApplication; // Agent application.
85+
options.ClientCredentials = [
86+
CertificateDescription.FromStoreWithDistinguishedName(
87+
"CN=LabAuth.MSIDLab.com", StoreLocation.LocalMachine, StoreName.My)
88+
];
89+
});
90+
IServiceProvider serviceProvider = services.ConfigureServicesForAgentIdentitiesTests();
91+
92+
// Get an authorization header and handle the call to the downstream API yourself
93+
IAuthorizationHeaderProvider authorizationHeaderProvider = serviceProvider.GetService<IAuthorizationHeaderProvider>()!;
94+
AuthorizationHeaderProviderOptions options = new AuthorizationHeaderProviderOptions().WithAgentUserIdentity(
95+
agentApplicationId: agentIdentity,
96+
username: userUpn
97+
);
98+
options.AcquireTokenOptions.Tenant = tenantId;
99+
100+
string authorizationHeaderWithUserToken = await authorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(
101+
scopes: ["https://graph.microsoft.com/.default"],
102+
options);
103+
Assert.NotNull(authorizationHeaderWithUserToken);
104+
105+
// If you want to call Microsoft Graph, just inject and use the Microsoft Graph SDK with the agent identity.
106+
GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>();
107+
var me = await graphServiceClient.Me.GetAsync(r => r.Options.WithAuthenticationOptions(options =>
108+
{
109+
options.WithAgentUserIdentity(agentIdentity, userUpn);
110+
options.AcquireTokenOptions.Tenant = tenantId;
111+
}));
112+
Assert.NotNull(me);
113+
114+
#if DOWNSTREAM
115+
// If you want to call downstream APIs letting IdWeb handle authentication.
116+
IDownstreamApi downstream = serviceProvider.GetService<IDownstreamApi>()!;
117+
string? response = await downstream.GetForAppAsync<string>("api", options => options.WithAgentIdentity("your-agent-identity-here"));
118+
response = await downstream.GetForUserAsync<string>("api", options => options.WithAgentIdentity("your-agent-identity-here"));
119+
#endif
120+
}
121+
122+
67123
[Fact]
68124
public async Task AgentUserIdentityGetsTokenForGraphWithCacheAsync()
69125
{

0 commit comments

Comments
 (0)