Skip to content

Commit d050622

Browse files
Copilotjmprieur
andauthored
Fix ForAgentIdentity hardcoded 'AzureAd' ConfigurationSection to respect AuthenticationOptionsName (#3635)
* Initial plan * Fix ForAgentIdentity to use AuthenticationOptionsName instead of hardcoded "AzureAd" Co-authored-by: jmprieur <[email protected]> * Fix ForAgentIdentity to use AuthenticationOptionsName instead of hardcoded "AzureAd" Co-authored-by: jmprieur <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jmprieur <[email protected]> Co-authored-by: Jean-Marc Prieur <[email protected]>
1 parent 648a505 commit d050622

File tree

2 files changed

+149
-3
lines changed

2 files changed

+149
-3
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,16 +117,17 @@ internal static AcquireTokenOptions ForAgentIdentity(this AcquireTokenOptions op
117117
// Until it makes it way through Abstractions
118118
options.ExtraParameters[Constants.FmiPathForClientAssertion] = agentApplicationId;
119119

120-
// TODO: do we want to expose a mechanism to override the MicrosoftIdentityOptions instead of leveraging
121-
// the default configuration section / named options?.
120+
// Use the developer's AuthenticationOptionsName if set, otherwise default to "AzureAd"
121+
string configurationSection = options.AuthenticationOptionsName ?? "AzureAd";
122+
122123
options.ExtraParameters[Constants.MicrosoftIdentityOptionsParameter] = new MicrosoftEntraApplicationOptions
123124
{
124125
ClientId = agentApplicationId, // Agent identity Client ID.
125126
ClientCredentials = [ new CredentialDescription() {
126127
SourceType = CredentialSource.CustomSignedAssertion,
127128
CustomSignedAssertionProviderName = "OidcIdpSignedAssertion",
128129
CustomSignedAssertionProviderData = new Dictionary<string, object> {
129-
{ "ConfigurationSection", "AzureAd" }, // Use the default configuration section name
130+
{ "ConfigurationSection", configurationSection }, // Use the developer's choice or default to "AzureAd"
130131
{ "RequiresSignedAssertionFmiPath", true }, // The OidcIdpSignedAssertionProvider will require the fmiPath to be provided in the assertionRequestOptions.
131132
}
132133
}]
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Collections.Generic;
5+
using Microsoft.Identity.Abstractions;
6+
using Xunit;
7+
8+
namespace Microsoft.Identity.Web.Test
9+
{
10+
/// <summary>
11+
/// Tests for the AgentIdentityExtension class (ForAgentIdentity and WithAgentIdentity methods).
12+
/// </summary>
13+
public class AgentIdentitiesExtensionTests
14+
{
15+
private const string TestAgentApplicationId = "test-agent-app-id";
16+
17+
[Fact]
18+
public void WithAgentIdentity_WithDefaultAuthenticationOptionsName_UsesAzureAdConfigurationSection()
19+
{
20+
// Arrange
21+
var options = new AuthorizationHeaderProviderOptions();
22+
23+
// Act
24+
options.WithAgentIdentity(TestAgentApplicationId);
25+
26+
// Assert
27+
Assert.NotNull(options.AcquireTokenOptions);
28+
Assert.NotNull(options.AcquireTokenOptions.ExtraParameters);
29+
Assert.True(options.AcquireTokenOptions.ExtraParameters.ContainsKey(Constants.MicrosoftIdentityOptionsParameter));
30+
31+
var microsoftIdentityOptions = options.AcquireTokenOptions.ExtraParameters[Constants.MicrosoftIdentityOptionsParameter] as MicrosoftEntraApplicationOptions;
32+
Assert.NotNull(microsoftIdentityOptions);
33+
Assert.Equal(TestAgentApplicationId, microsoftIdentityOptions.ClientId);
34+
35+
// Verify the ConfigurationSection is set to "AzureAd" when AuthenticationOptionsName is not set
36+
var clientCredential = Assert.Single(microsoftIdentityOptions.ClientCredentials!);
37+
Assert.Equal(CredentialSource.CustomSignedAssertion, clientCredential.SourceType);
38+
Assert.Equal("OidcIdpSignedAssertion", clientCredential.CustomSignedAssertionProviderName);
39+
Assert.NotNull(clientCredential.CustomSignedAssertionProviderData);
40+
Assert.True(clientCredential.CustomSignedAssertionProviderData.TryGetValue("ConfigurationSection", out var configSection));
41+
Assert.Equal("AzureAd", configSection);
42+
}
43+
44+
[Fact]
45+
public void WithAgentIdentity_WithCustomAuthenticationOptionsName_UsesCustomConfigurationSection()
46+
{
47+
// Arrange
48+
var options = new AuthorizationHeaderProviderOptions
49+
{
50+
AcquireTokenOptions = new AcquireTokenOptions
51+
{
52+
AuthenticationOptionsName = "MyEntraId"
53+
}
54+
};
55+
56+
// Act
57+
options.WithAgentIdentity(TestAgentApplicationId);
58+
59+
// Assert
60+
Assert.NotNull(options.AcquireTokenOptions);
61+
Assert.NotNull(options.AcquireTokenOptions.ExtraParameters);
62+
Assert.True(options.AcquireTokenOptions.ExtraParameters.ContainsKey(Constants.MicrosoftIdentityOptionsParameter));
63+
64+
var microsoftIdentityOptions = options.AcquireTokenOptions.ExtraParameters[Constants.MicrosoftIdentityOptionsParameter] as MicrosoftEntraApplicationOptions;
65+
Assert.NotNull(microsoftIdentityOptions);
66+
67+
// Verify the ConfigurationSection respects the custom AuthenticationOptionsName
68+
var clientCredential = Assert.Single(microsoftIdentityOptions.ClientCredentials!);
69+
Assert.NotNull(clientCredential.CustomSignedAssertionProviderData);
70+
Assert.True(clientCredential.CustomSignedAssertionProviderData.TryGetValue("ConfigurationSection", out var configSection));
71+
Assert.Equal("MyEntraId", configSection);
72+
}
73+
74+
[Theory]
75+
[InlineData("EntraId")]
76+
[InlineData("CustomSection")]
77+
[InlineData("AzureAD_Prod")]
78+
public void WithAgentIdentity_WithVariousCustomAuthenticationOptionsNames_UsesCorrectConfigurationSection(string authenticationOptionsName)
79+
{
80+
// Arrange
81+
var options = new AuthorizationHeaderProviderOptions
82+
{
83+
AcquireTokenOptions = new AcquireTokenOptions
84+
{
85+
AuthenticationOptionsName = authenticationOptionsName
86+
}
87+
};
88+
89+
// Act
90+
options.WithAgentIdentity(TestAgentApplicationId);
91+
92+
// Assert
93+
var microsoftIdentityOptions = options.AcquireTokenOptions.ExtraParameters![Constants.MicrosoftIdentityOptionsParameter] as MicrosoftEntraApplicationOptions;
94+
Assert.NotNull(microsoftIdentityOptions);
95+
96+
var clientCredential = Assert.Single(microsoftIdentityOptions.ClientCredentials!);
97+
Assert.True(clientCredential.CustomSignedAssertionProviderData!.TryGetValue("ConfigurationSection", out var configSection));
98+
Assert.Equal(authenticationOptionsName, configSection);
99+
}
100+
101+
[Fact]
102+
public void WithAgentIdentity_WithNullOptions_CreatesNewOptionsAndUsesAzureAdDefault()
103+
{
104+
// Arrange
105+
AuthorizationHeaderProviderOptions? options = null;
106+
107+
// Act
108+
var result = options!.WithAgentIdentity(TestAgentApplicationId);
109+
110+
// Assert
111+
Assert.NotNull(result);
112+
Assert.NotNull(result.AcquireTokenOptions);
113+
Assert.NotNull(result.AcquireTokenOptions.ExtraParameters);
114+
115+
var microsoftIdentityOptions = result.AcquireTokenOptions.ExtraParameters[Constants.MicrosoftIdentityOptionsParameter] as MicrosoftEntraApplicationOptions;
116+
Assert.NotNull(microsoftIdentityOptions);
117+
118+
var clientCredential = Assert.Single(microsoftIdentityOptions.ClientCredentials!);
119+
Assert.True(clientCredential.CustomSignedAssertionProviderData!.TryGetValue("ConfigurationSection", out var configSection));
120+
Assert.Equal("AzureAd", configSection);
121+
}
122+
123+
[Fact]
124+
public void WithAgentIdentity_AlwaysSetsRequiresSignedAssertionFmiPath()
125+
{
126+
// Arrange
127+
var options = new AuthorizationHeaderProviderOptions
128+
{
129+
AcquireTokenOptions = new AcquireTokenOptions
130+
{
131+
AuthenticationOptionsName = "CustomSection"
132+
}
133+
};
134+
135+
// Act
136+
options.WithAgentIdentity(TestAgentApplicationId);
137+
138+
// Assert
139+
var microsoftIdentityOptions = options.AcquireTokenOptions.ExtraParameters![Constants.MicrosoftIdentityOptionsParameter] as MicrosoftEntraApplicationOptions;
140+
var clientCredential = Assert.Single(microsoftIdentityOptions!.ClientCredentials!);
141+
Assert.True(clientCredential.CustomSignedAssertionProviderData!.TryGetValue("RequiresSignedAssertionFmiPath", out var fmiPathRequired));
142+
Assert.Equal(true, fmiPathRequired);
143+
}
144+
}
145+
}

0 commit comments

Comments
 (0)