Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ internal static class IDWebErrorMessage
"StoreLocation must be one of 'CurrentUser', 'LocalMachine'. " +
"StoreName must be empty or one of '{0}'. ";

// Configuration Validation IDW10700+ = "IDW10700+:"
public const string MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. ";

// Obsolete messages IDW10800 = "IDW10800:"
public const string AadIssuerValidatorGetIssuerValidatorIsObsolete = "IDW10800: Use MicrosoftIdentityIssuerValidatorFactory.GetAadIssuerValidator. See https://aka.ms/ms-id-web/1.2.0. ";
public const string InitializeAsyncIsObsolete = "IDW10801: Use Initialize instead. See https://aka.ms/ms-id-web/1.9.0. ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ static Microsoft.Identity.Web.MergedOptions.ParseAuthorityIfNecessary(Microsoft.
static Microsoft.Identity.Web.MergedOptionsLogging.AuthorityIgnored(Microsoft.Extensions.Logging.ILogger! logger, string! authority, string! instance, string! tenantId) -> void
static Microsoft.Identity.Web.TokenAcquisition.MergeExtraQueryParameters(Microsoft.Identity.Web.MergedOptions! mergedOptions, Microsoft.Identity.Web.TokenAcquisitionOptions? tokenAcquisitionOptions) -> System.Collections.Generic.Dictionary<string!, (string! value, bool includeInCacheKey)>?
static readonly Microsoft.Identity.Web.LoggingEventId.AuthorityIgnored -> Microsoft.Extensions.Logging.EventId
const Microsoft.Identity.Web.IDWebErrorMessage.MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. " -> string!
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ static Microsoft.Identity.Web.MergedOptions.ParseAuthorityIfNecessary(Microsoft.
static Microsoft.Identity.Web.MergedOptionsLogging.AuthorityIgnored(Microsoft.Extensions.Logging.ILogger! logger, string! authority, string! instance, string! tenantId) -> void
static Microsoft.Identity.Web.TokenAcquisition.MergeExtraQueryParameters(Microsoft.Identity.Web.MergedOptions! mergedOptions, Microsoft.Identity.Web.TokenAcquisitionOptions? tokenAcquisitionOptions) -> System.Collections.Generic.Dictionary<string!, (string! value, bool includeInCacheKey)>?
static readonly Microsoft.Identity.Web.LoggingEventId.AuthorityIgnored -> Microsoft.Extensions.Logging.EventId
const Microsoft.Identity.Web.IDWebErrorMessage.MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. " -> string!
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ static Microsoft.Identity.Web.MergedOptions.ParseAuthorityIfNecessary(Microsoft.
static Microsoft.Identity.Web.MergedOptionsLogging.AuthorityIgnored(Microsoft.Extensions.Logging.ILogger! logger, string! authority, string! instance, string! tenantId) -> void
static Microsoft.Identity.Web.TokenAcquisition.MergeExtraQueryParameters(Microsoft.Identity.Web.MergedOptions! mergedOptions, Microsoft.Identity.Web.TokenAcquisitionOptions? tokenAcquisitionOptions) -> System.Collections.Generic.Dictionary<string!, (string! value, bool includeInCacheKey)>?
static readonly Microsoft.Identity.Web.LoggingEventId.AuthorityIgnored -> Microsoft.Extensions.Logging.EventId
const Microsoft.Identity.Web.IDWebErrorMessage.MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. " -> string!
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ static Microsoft.Identity.Web.MergedOptions.ParseAuthorityIfNecessary(Microsoft.
static Microsoft.Identity.Web.MergedOptionsLogging.AuthorityIgnored(Microsoft.Extensions.Logging.ILogger! logger, string! authority, string! instance, string! tenantId) -> void
static Microsoft.Identity.Web.TokenAcquisition.MergeExtraQueryParameters(Microsoft.Identity.Web.MergedOptions! mergedOptions, Microsoft.Identity.Web.TokenAcquisitionOptions? tokenAcquisitionOptions) -> System.Collections.Generic.Dictionary<string!, (string! value, bool includeInCacheKey)>?
static readonly Microsoft.Identity.Web.LoggingEventId.AuthorityIgnored -> Microsoft.Extensions.Logging.EventId
const Microsoft.Identity.Web.IDWebErrorMessage.MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. " -> string!
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ static Microsoft.Identity.Web.MergedOptions.ParseAuthorityIfNecessary(Microsoft.
static Microsoft.Identity.Web.MergedOptionsLogging.AuthorityIgnored(Microsoft.Extensions.Logging.ILogger! logger, string! authority, string! instance, string! tenantId) -> void
static Microsoft.Identity.Web.TokenAcquisition.MergeExtraQueryParameters(Microsoft.Identity.Web.MergedOptions! mergedOptions, Microsoft.Identity.Web.TokenAcquisitionOptions? tokenAcquisitionOptions) -> System.Collections.Generic.Dictionary<string!, (string! value, bool includeInCacheKey)>?
static readonly Microsoft.Identity.Web.LoggingEventId.AuthorityIgnored -> Microsoft.Extensions.Logging.EventId
const Microsoft.Identity.Web.IDWebErrorMessage.MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. " -> string!
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ static Microsoft.Identity.Web.MergedOptions.ParseAuthorityIfNecessary(Microsoft.
static Microsoft.Identity.Web.MergedOptionsLogging.AuthorityIgnored(Microsoft.Extensions.Logging.ILogger! logger, string! authority, string! instance, string! tenantId) -> void
static Microsoft.Identity.Web.TokenAcquisition.MergeExtraQueryParameters(Microsoft.Identity.Web.MergedOptions! mergedOptions, Microsoft.Identity.Web.TokenAcquisitionOptions? tokenAcquisitionOptions) -> System.Collections.Generic.Dictionary<string!, (string! value, bool includeInCacheKey)>?
static readonly Microsoft.Identity.Web.LoggingEventId.AuthorityIgnored -> Microsoft.Extensions.Logging.EventId
const Microsoft.Identity.Web.IDWebErrorMessage.MissingIdentityConfiguration = "IDW10708: The identity configuration is incomplete. Provide either 'Instance' and 'TenantId', or 'Authority', or enable 'ManagedIdentity' in the configuration. Check your configuration keys for typos (e.g., trailing spaces). See https://aka.ms/ms-id-web/configuration. " -> string!
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ public async Task<AuthenticationResult> GetAuthenticationResultForAppAsync(
}

// Apply tenant override only for AAD authorities and only if non-empty
if (!mergedOptions.Instance.Contains(Constants.CiamAuthoritySuffix
if (!string.IsNullOrEmpty(mergedOptions.Instance) &&
!mergedOptions.Instance.Contains(Constants.CiamAuthoritySuffix
#if NET6_0_OR_GREATER
, StringComparison.OrdinalIgnoreCase
#endif
Expand Down Expand Up @@ -938,6 +939,16 @@ private async Task<IConfidentialClientApplication> BuildConfidentialClientApplic
{
mergedOptions.PrepareAuthorityInstanceForMsal();

// Validate that we have enough configuration to build an authority
// When PreserveAuthority is true, we use Authority directly, so PreparedInstance is not required
// When IsB2C is true, we still need PreparedInstance
if (!mergedOptions.PreserveAuthority &&
string.IsNullOrEmpty(mergedOptions.PreparedInstance) &&
string.IsNullOrEmpty(mergedOptions.Authority))
{
throw new ArgumentException(IDWebErrorMessage.MissingIdentityConfiguration);
}

try
{
ConfidentialClientApplicationBuilder builder = ConfidentialClientApplicationBuilder
Expand Down
21 changes: 21 additions & 0 deletions tests/Microsoft.Identity.Web.Test/MergedOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,26 @@ public void PrepareAuthorityInstanceForMsal_DoesNotParseAuthority_WhenInstanceAn
Assert.Equal("organizations", options.TenantId); // TenantId remains unchanged
Assert.Equal("https://login.microsoftonline.us/", options.PreparedInstance); // PreparedInstance based on original Instance
}

[Fact]
public void PrepareAuthorityInstanceForMsal_LeavesNullPreparedInstance_WhenNoConfigurationProvided()
{
// This test verifies the scenario from issue #2921 where a misconfigured key
// (e.g., "ManagedIdentity " with trailing space instead of "ManagedIdentity")
// results in null Instance and null Authority, which should leave PreparedInstance as null

// Arrange
var options = new MergedOptions();
// Simulating the scenario where configuration keys have typos and don't bind correctly

// Act
options.PrepareAuthorityInstanceForMsal();

// Assert
Assert.Null(options.Instance);
Assert.Null(options.TenantId);
Assert.Null(options.Authority);
Assert.Null(options.PreparedInstance);
}
}
}
38 changes: 38 additions & 0 deletions tests/Microsoft.Identity.Web.Test/TokenAcquisitionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,43 @@ private TokenAcquirerFactory InitTokenAcquirerFactory()

return tokenAcquirerFactory;
}

/// <summary>
/// Tests that when identity configuration is missing (simulating a misconfigured key like "ManagedIdentity " with trailing space),
/// a meaningful ArgumentException is thrown instead of a NullReferenceException.
/// This addresses issue #2921.
/// </summary>
[Fact]
public async Task GetAuthenticationResultForAppAsync_ThrowsMeaningfulError_WhenConfigurationIsMissing()
{
// Arrange - Create a factory with missing identity configuration
TokenAcquirerFactoryTesting.ResetTokenAcquirerFactoryInTest();
TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.Configure<MicrosoftIdentityApplicationOptions>(options =>
{
// Intentionally NOT setting Instance, TenantId, or Authority
// This simulates the scenario where configuration keys have typos
// (e.g., "ManagedIdentity " instead of "ManagedIdentity")
options.ClientId = "test-client-id";
options.ClientCredentials = [new CredentialDescription()
{
SourceType = CredentialSource.ClientSecret,
ClientSecret = "someSecret"
}];
});

tokenAcquirerFactory.Services.AddSingleton<IMsalHttpClientFactory, MockHttpClientFactory>();

IServiceProvider serviceProvider = tokenAcquirerFactory.Build();
IAuthorizationHeaderProvider authorizationHeaderProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

// Act & Assert - Should throw ArgumentException with meaningful message
var exception = await Assert.ThrowsAsync<ArgumentException>(async () =>
await authorizationHeaderProvider.CreateAuthorizationHeaderForAppAsync(
"https://graph.microsoft.com/.default",
new AuthorizationHeaderProviderOptions()));

Assert.StartsWith(IDWebErrorMessage.MissingIdentityConfiguration, exception.Message, System.StringComparison.Ordinal);
}
}
}
Loading