From e94fddc64b5eb95609128f9fb37d8c61d09f9f7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Sep 2025 21:16:43 +0000 Subject: [PATCH 1/8] Initial plan From 01a7ffd41e757bd34221382040eafcff9e9e32e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Sep 2025 21:39:20 +0000 Subject: [PATCH 2/8] Add telemetry domain extraction feature with AppContext switch Co-authored-by: westin-m <127992899+westin-m@users.noreply.github.com> --- .../AppContextSwitches.cs | 11 ++ .../Telemetry/TelemetryClient.cs | 42 ++++- .../TelemetryClientDomainExtractionTests.cs | 171 ++++++++++++++++++ 3 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs diff --git a/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs b/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs index 7f32a2fb85..97dc7fcceb 100644 --- a/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs +++ b/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs @@ -98,6 +98,14 @@ internal static class AppContextSwitches private static bool? _useCapitalizedXMLTypeAttr; internal static bool UseCapitalizedXMLTypeAttr => _useCapitalizedXMLTypeAttr ??= (AppContext.TryGetSwitch(UseCapitalizedXMLTypeAttrSwitch, out bool useCapitalizedXMLTypeAttr) && useCapitalizedXMLTypeAttr); + /// + /// When enabled, telemetry will use the full metadata address instead of just the domain name for IdentityModelConfiguration metrics. + /// By default (when disabled), only the domain name is used for successful operations to reduce OpenTelemetry cardinality. + /// + internal const string UseFullMetadataAddressForTelemetrySwitch = "Switch.Microsoft.IdentityModel.UseFullMetadataAddressForTelemetry"; + private static bool? _useFullMetadataAddressForTelemetry; + internal static bool UseFullMetadataAddressForTelemetry => _useFullMetadataAddressForTelemetry ??= (AppContext.TryGetSwitch(UseFullMetadataAddressForTelemetrySwitch, out bool useFullMetadataAddressForTelemetry) && useFullMetadataAddressForTelemetry); + /// /// Used for testing to reset all switches to its default value. /// @@ -123,6 +131,9 @@ internal static void ResetAllSwitches() _useCapitalizedXMLTypeAttr = null; AppContext.SetSwitch(UseCapitalizedXMLTypeAttrSwitch, false); + + _useFullMetadataAddressForTelemetry = null; + AppContext.SetSwitch(UseFullMetadataAddressForTelemetrySwitch, false); } } } diff --git a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs index 2a56774454..2af7f87e72 100644 --- a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs +++ b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs @@ -22,12 +22,44 @@ internal class TelemetryClient : ITelemetryClient AppContextSwitches.UpdateConfigAsBlocking.ToString() ); + /// + /// Extracts the domain name from a metadata address for telemetry purposes. + /// Returns the full address if domain extraction fails or if the UseFullMetadataAddressForTelemetry switch is enabled. + /// In error cases, always returns the full address for better debugging. + /// + /// The full metadata address + /// True if this is a successful operation, false for error cases + /// Domain name for success cases (when switch is disabled), full address otherwise + private static string GetMetadataAddressForTelemetry(string metadataAddress, bool isSuccessCase = true) + { + // Always use full address for error cases or when the switch is enabled + if (!isSuccessCase || AppContextSwitches.UseFullMetadataAddressForTelemetry || string.IsNullOrEmpty(metadataAddress)) + return metadataAddress; + + try + { + var uri = new Uri(metadataAddress, UriKind.Absolute); + + // Extract domain, removing 'www.' prefix if present + string host = uri.Host; + if (host.StartsWith("www.", StringComparison.OrdinalIgnoreCase)) + host = host.Substring(4); + + return host; + } + catch (UriFormatException) + { + // If parsing fails, return the original address + return metadataAddress; + } + } + public void IncrementConfigurationRefreshRequestCounter(string metadataAddress, string operationStatus, string configurationSource) { var tagList = new TagList() { { TelemetryConstants.IdentityModelVersionTag, ClientVer }, - { TelemetryConstants.MetadataAddressTag, metadataAddress }, + { TelemetryConstants.MetadataAddressTag, GetMetadataAddressForTelemetry(metadataAddress, isSuccessCase: true) }, { TelemetryConstants.OperationStatusTag, operationStatus }, { TelemetryConstants.ConfigurationSourceTag, configurationSource }, _blockingTagValue @@ -41,7 +73,7 @@ public void IncrementConfigurationRefreshRequestCounter(string metadataAddress, var tagList = new TagList() { { TelemetryConstants.IdentityModelVersionTag, ClientVer }, - { TelemetryConstants.MetadataAddressTag, metadataAddress }, + { TelemetryConstants.MetadataAddressTag, GetMetadataAddressForTelemetry(metadataAddress, isSuccessCase: false) }, { TelemetryConstants.OperationStatusTag, operationStatus }, { TelemetryConstants.ConfigurationSourceTag, configurationSource }, { TelemetryConstants.ExceptionTypeTag, exception.GetType().ToString() }, @@ -56,7 +88,7 @@ public void LogConfigurationRetrievalDuration(string metadataAddress, string con var tagList = new TagList() { { TelemetryConstants.IdentityModelVersionTag, ClientVer }, - { TelemetryConstants.MetadataAddressTag, metadataAddress }, + { TelemetryConstants.MetadataAddressTag, GetMetadataAddressForTelemetry(metadataAddress, isSuccessCase: true) }, { TelemetryConstants.ConfigurationSourceTag, configurationSource }, }; @@ -69,7 +101,7 @@ public void LogConfigurationRetrievalDuration(string metadataAddress, string con var tagList = new TagList() { { TelemetryConstants.IdentityModelVersionTag, ClientVer }, - { TelemetryConstants.MetadataAddressTag, metadataAddress }, + { TelemetryConstants.MetadataAddressTag, GetMetadataAddressForTelemetry(metadataAddress, isSuccessCase: false) }, { TelemetryConstants.ConfigurationSourceTag, configurationSource }, { TelemetryConstants.ExceptionTypeTag, exception.GetType().ToString() }, _blockingTagValue @@ -87,7 +119,7 @@ public void LogBackgroundConfigurationRefreshFailure( var tagList = new TagList() { { TelemetryConstants.IdentityModelVersionTag, ClientVer }, - { TelemetryConstants.MetadataAddressTag, metadataAddress }, + { TelemetryConstants.MetadataAddressTag, GetMetadataAddressForTelemetry(metadataAddress, isSuccessCase: false) }, { TelemetryConstants.ConfigurationSourceTag, configurationSource }, { TelemetryConstants.ExceptionTypeTag, exception.GetType().ToString() }, _blockingTagValue diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs new file mode 100644 index 0000000000..16a3138add --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Diagnostics; +using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens; +using Xunit; + +namespace Microsoft.IdentityModel.Telemetry.Tests +{ + public class TelemetryClientDomainExtractionTests + { + [Fact] + public void DebugMethodCall() + { + // Debug what's happening with reflection + var telemetryClientType = typeof(TelemetryClient); + var methods = telemetryClientType.GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + + var foundMethods = new List(); + foreach (var m in methods) + { + foundMethods.Add($"{m.Name}({string.Join(", ", m.GetParameters().Select(p => p.ParameterType.Name))})"); + } + + // This should help us see what methods are available + Assert.True(foundMethods.Count > 0, $"Available methods: {string.Join(", ", foundMethods)}"); + + var method = telemetryClientType.GetMethod("GetMetadataAddressForTelemetry", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + + Assert.NotNull(method); // This should pass if the method exists + + // Test the method directly + var testUrl = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; + var result = (string)method.Invoke(null, new object[] { testUrl, true }); + + // For now, let's just ensure it doesn't throw and see what we get + Assert.NotNull(result); + } + + [Theory] + [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")] + [InlineData("https://accounts.google.com/.well-known/openid-configuration")] + [InlineData("https://login.windows.net/common/.well-known/openid-configuration")] + public void GetMetadataAddressForTelemetry_ErrorCase_ReturnsFullAddress(string fullAddress) + { + // Arrange + var telemetryClient = new TelemetryClient(); + + // Act - using reflection to call the private method with isSuccessCase = false + var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + var result = (string)method.Invoke(null, new object[] { fullAddress, false }); + + // Assert + Assert.Equal(fullAddress, result); + } + + [Theory] + [InlineData("invalid-url")] + [InlineData("")] + [InlineData(null)] + public void GetMetadataAddressForTelemetry_InvalidUrl_ReturnsOriginalString(string invalidUrl) + { + // Arrange + var telemetryClient = new TelemetryClient(); + + // Act - using reflection to call the private method + var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + var result = (string)method.Invoke(null, new object[] { invalidUrl, true }); + + // Assert + Assert.Equal(invalidUrl, result); + } + + [Fact] + public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddress() + { + // Arrange + var fullAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; + var telemetryClient = new TelemetryClient(); + + try + { + // Enable the switch to use full metadata address + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); + + // Act - using reflection to call the private method + var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + var result = (string)method.Invoke(null, new object[] { fullAddress, true }); + + // Assert + Assert.Equal(fullAddress, result); + } + finally + { + // Cleanup + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); + } + } + + [Fact] + public void TelemetryClient_Methods_DoNotThrow() + { + // This test ensures that the modified telemetry methods don't break existing functionality + // We cannot easily verify the exact values sent to the telemetry system without complex setup, + // but we can ensure the methods don't throw exceptions when called with valid parameters. + + // Arrange + var telemetryClient = new TelemetryClient(); + var testAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; + var testDuration = TimeSpan.FromMilliseconds(100); + var testException = new InvalidOperationException("Test exception"); + + // Act & Assert - these should not throw + var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); + var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); + var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); + var ex4 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "ConfigurationRetrievalFailed", "Retriever", testException)); + var ex5 = Record.Exception(() => telemetryClient.LogBackgroundConfigurationRefreshFailure(testAddress, "Retriever", testException)); + + Assert.Null(ex1); + Assert.Null(ex2); + Assert.Null(ex3); + Assert.Null(ex4); + Assert.Null(ex5); + } + + [Fact] + public void TelemetryClient_WithAppContextSwitch_DoesNotThrow() + { + // Test that telemetry methods work correctly when the backward compatibility switch is enabled + + try + { + // Enable the switch to use full metadata address + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); + + // Arrange + var telemetryClient = new TelemetryClient(); + var testAddress = "https://accounts.google.com/.well-known/openid-configuration"; + var testDuration = TimeSpan.FromMilliseconds(150); + var testException = new InvalidOperationException("Test exception"); + + // Act & Assert - these should not throw even with the switch enabled + var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); + var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); + var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); + var ex4 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "ConfigurationRetrievalFailed", "Retriever", testException)); + var ex5 = Record.Exception(() => telemetryClient.LogBackgroundConfigurationRefreshFailure(testAddress, "Retriever", testException)); + + Assert.Null(ex1); + Assert.Null(ex2); + Assert.Null(ex3); + Assert.Null(ex4); + Assert.Null(ex5); + } + finally + { + // Cleanup + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); + } + } + } +} \ No newline at end of file From 8d873974c83d237ec7b8392b572484b808fe9d9e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Sep 2025 21:48:32 +0000 Subject: [PATCH 3/8] Complete telemetry domain extraction feature implementation with tests Co-authored-by: westin-m <127992899+westin-m@users.noreply.github.com> --- .../TelemetryClientDomainExtractionTests.cs | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs index 16a3138add..a740063e39 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs @@ -13,33 +13,42 @@ namespace Microsoft.IdentityModel.Telemetry.Tests { public class TelemetryClientDomainExtractionTests { + [Theory] + [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] + [InlineData("https://www.login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] + [InlineData("https://accounts.google.com/.well-known/openid-configuration", "accounts.google.com")] + [InlineData("https://login.windows.net/common/.well-known/openid-configuration", "login.windows.net")] + [InlineData("http://localhost:8080/.well-known/openid-configuration", "localhost")] + [InlineData("https://example.com/path/to/config", "example.com")] + [InlineData("https://subdomain.example.org/config.json", "subdomain.example.org")] + public void GetMetadataAddressForTelemetry_SuccessCase_ReturnsExpectedDomain(string fullAddress, string expectedDomain) + { + // Act - using reflection to call the private method + var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + var result = (string)method.Invoke(null, new object[] { fullAddress, true }); + + // Assert + Assert.Equal(expectedDomain, result); + } + [Fact] - public void DebugMethodCall() + public void DebugAppContextSwitch() { - // Debug what's happening with reflection - var telemetryClientType = typeof(TelemetryClient); - var methods = telemetryClientType.GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - - var foundMethods = new List(); - foreach (var m in methods) - { - foundMethods.Add($"{m.Name}({string.Join(", ", m.GetParameters().Select(p => p.ParameterType.Name))})"); - } - - // This should help us see what methods are available - Assert.True(foundMethods.Count > 0, $"Available methods: {string.Join(", ", foundMethods)}"); + // Check if the AppContext switch is causing issues + var switchValue = AppContextSwitches.UseFullMetadataAddressForTelemetry; + // Test a simple call + var telemetryClientType = typeof(TelemetryClient); var method = telemetryClientType.GetMethod("GetMetadataAddressForTelemetry", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - Assert.NotNull(method); // This should pass if the method exists - - // Test the method directly var testUrl = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; var result = (string)method.Invoke(null, new object[] { testUrl, true }); - // For now, let's just ensure it doesn't throw and see what we get - Assert.NotNull(result); + // The switch should be false by default, so we should get the host name + Assert.False(switchValue, $"Switch value: {switchValue}"); + Assert.Equal("login.microsoftonline.com", result); } [Theory] @@ -87,6 +96,9 @@ public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddre try { + // Reset switches first to clear any cached values + AppContextSwitches.ResetAllSwitches(); + // Enable the switch to use full metadata address AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); @@ -101,7 +113,7 @@ public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddre finally { // Cleanup - AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); + AppContextSwitches.ResetAllSwitches(); } } From 4827171925327d9bf3e2a9ad5ca959665ad1e426 Mon Sep 17 00:00:00 2001 From: Westin Musser <127992899+westin-m@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:27:40 -0700 Subject: [PATCH 4/8] internal method, no reflection in tests --- .../Telemetry/TelemetryClient.cs | 2 +- .../TelemetryClientDomainExtractionTests.cs | 69 ++++++------------- 2 files changed, 23 insertions(+), 48 deletions(-) diff --git a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs index 2af7f87e72..fd6d17bc5d 100644 --- a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs +++ b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs @@ -30,7 +30,7 @@ internal class TelemetryClient : ITelemetryClient /// The full metadata address /// True if this is a successful operation, false for error cases /// Domain name for success cases (when switch is disabled), full address otherwise - private static string GetMetadataAddressForTelemetry(string metadataAddress, bool isSuccessCase = true) + internal static string GetMetadataAddressForTelemetry(string metadataAddress, bool isSuccessCase = true) { // Always use full address for error cases or when the switch is enabled if (!isSuccessCase || AppContextSwitches.UseFullMetadataAddressForTelemetry || string.IsNullOrEmpty(metadataAddress)) diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs index a740063e39..f6098dbb5e 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs @@ -2,10 +2,6 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; -using System.Linq; -using System.Diagnostics; -using Microsoft.IdentityModel.TestUtils; using Microsoft.IdentityModel.Tokens; using Xunit; @@ -17,16 +13,14 @@ public class TelemetryClientDomainExtractionTests [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] [InlineData("https://www.login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] [InlineData("https://accounts.google.com/.well-known/openid-configuration", "accounts.google.com")] - [InlineData("https://login.windows.net/common/.well-known/openid-configuration", "login.windows.net")] + [InlineData("https://login.windows.net/common/.well-known/openid-configuration", "login.windows.net")] [InlineData("http://localhost:8080/.well-known/openid-configuration", "localhost")] [InlineData("https://example.com/path/to/config", "example.com")] [InlineData("https://subdomain.example.org/config.json", "subdomain.example.org")] public void GetMetadataAddressForTelemetry_SuccessCase_ReturnsExpectedDomain(string fullAddress, string expectedDomain) { - // Act - using reflection to call the private method - var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - var result = (string)method.Invoke(null, new object[] { fullAddress, true }); + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, true); // Assert Assert.Equal(expectedDomain, result); @@ -37,15 +31,10 @@ public void DebugAppContextSwitch() { // Check if the AppContext switch is causing issues var switchValue = AppContextSwitches.UseFullMetadataAddressForTelemetry; - - // Test a simple call - var telemetryClientType = typeof(TelemetryClient); - var method = telemetryClientType.GetMethod("GetMetadataAddressForTelemetry", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - + var testUrl = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; - var result = (string)method.Invoke(null, new object[] { testUrl, true }); - + var result = TelemetryClient.GetMetadataAddressForTelemetry(testUrl); + // The switch should be false by default, so we should get the host name Assert.False(switchValue, $"Switch value: {switchValue}"); Assert.Equal("login.microsoftonline.com", result); @@ -57,13 +46,8 @@ public void DebugAppContextSwitch() [InlineData("https://login.windows.net/common/.well-known/openid-configuration")] public void GetMetadataAddressForTelemetry_ErrorCase_ReturnsFullAddress(string fullAddress) { - // Arrange - var telemetryClient = new TelemetryClient(); - - // Act - using reflection to call the private method with isSuccessCase = false - var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - var result = (string)method.Invoke(null, new object[] { fullAddress, false }); + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, false); // Assert Assert.Equal(fullAddress, result); @@ -75,13 +59,8 @@ public void GetMetadataAddressForTelemetry_ErrorCase_ReturnsFullAddress(string f [InlineData(null)] public void GetMetadataAddressForTelemetry_InvalidUrl_ReturnsOriginalString(string invalidUrl) { - // Arrange - var telemetryClient = new TelemetryClient(); - - // Act - using reflection to call the private method - var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - var result = (string)method.Invoke(null, new object[] { invalidUrl, true }); + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(invalidUrl, true); // Assert Assert.Equal(invalidUrl, result); @@ -92,20 +71,17 @@ public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddre { // Arrange var fullAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; - var telemetryClient = new TelemetryClient(); - + try { // Reset switches first to clear any cached values AppContextSwitches.ResetAllSwitches(); - + // Enable the switch to use full metadata address AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); - - // Act - using reflection to call the private method - var method = typeof(TelemetryClient).GetMethod("GetMetadataAddressForTelemetry", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); - var result = (string)method.Invoke(null, new object[] { fullAddress, true }); + + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, true); // Assert Assert.Equal(fullAddress, result); @@ -123,20 +99,20 @@ public void TelemetryClient_Methods_DoNotThrow() // This test ensures that the modified telemetry methods don't break existing functionality // We cannot easily verify the exact values sent to the telemetry system without complex setup, // but we can ensure the methods don't throw exceptions when called with valid parameters. - + // Arrange var telemetryClient = new TelemetryClient(); var testAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; var testDuration = TimeSpan.FromMilliseconds(100); var testException = new InvalidOperationException("Test exception"); - + // Act & Assert - these should not throw var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); var ex4 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "ConfigurationRetrievalFailed", "Retriever", testException)); var ex5 = Record.Exception(() => telemetryClient.LogBackgroundConfigurationRefreshFailure(testAddress, "Retriever", testException)); - + Assert.Null(ex1); Assert.Null(ex2); Assert.Null(ex3); @@ -148,25 +124,24 @@ public void TelemetryClient_Methods_DoNotThrow() public void TelemetryClient_WithAppContextSwitch_DoesNotThrow() { // Test that telemetry methods work correctly when the backward compatibility switch is enabled - try { // Enable the switch to use full metadata address AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); - + // Arrange var telemetryClient = new TelemetryClient(); var testAddress = "https://accounts.google.com/.well-known/openid-configuration"; var testDuration = TimeSpan.FromMilliseconds(150); var testException = new InvalidOperationException("Test exception"); - + // Act & Assert - these should not throw even with the switch enabled var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); var ex4 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "ConfigurationRetrievalFailed", "Retriever", testException)); var ex5 = Record.Exception(() => telemetryClient.LogBackgroundConfigurationRefreshFailure(testAddress, "Retriever", testException)); - + Assert.Null(ex1); Assert.Null(ex2); Assert.Null(ex3); @@ -180,4 +155,4 @@ public void TelemetryClient_WithAppContextSwitch_DoesNotThrow() } } } -} \ No newline at end of file +} From e36a9b9953b5104f04bb96d83080632d689af502 Mon Sep 17 00:00:00 2001 From: Westin Musser <127992899+westin-m@users.noreply.github.com> Date: Tue, 30 Sep 2025 11:12:05 -0700 Subject: [PATCH 5/8] remove unnecessary operation --- .../Telemetry/TelemetryClient.cs | 8 +------- .../Telemetry/TelemetryClientDomainExtractionTests.cs | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs index fd6d17bc5d..3c3019e725 100644 --- a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs +++ b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs @@ -39,13 +39,7 @@ internal static string GetMetadataAddressForTelemetry(string metadataAddress, bo try { var uri = new Uri(metadataAddress, UriKind.Absolute); - - // Extract domain, removing 'www.' prefix if present - string host = uri.Host; - if (host.StartsWith("www.", StringComparison.OrdinalIgnoreCase)) - host = host.Substring(4); - - return host; + return uri.Host; } catch (UriFormatException) { diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs index f6098dbb5e..2c6c63811f 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs @@ -11,7 +11,7 @@ public class TelemetryClientDomainExtractionTests { [Theory] [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] - [InlineData("https://www.login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] + [InlineData("https://www.login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "www.login.microsoftonline.com")] [InlineData("https://accounts.google.com/.well-known/openid-configuration", "accounts.google.com")] [InlineData("https://login.windows.net/common/.well-known/openid-configuration", "login.windows.net")] [InlineData("http://localhost:8080/.well-known/openid-configuration", "localhost")] From eee75f3e26972b710f29ffec793c7c354dbfb45b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:56:08 +0000 Subject: [PATCH 6/8] Fix AppContext switch test interference with ResetAppContextSwitches attribute Co-authored-by: westin-m <127992899+westin-m@users.noreply.github.com> --- .../Telemetry/TelemetryClientDomainExtractionTests.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs index 2c6c63811f..0b8468660f 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs @@ -2,11 +2,13 @@ // Licensed under the MIT License. using System; +using Microsoft.IdentityModel.TestUtils; using Microsoft.IdentityModel.Tokens; using Xunit; namespace Microsoft.IdentityModel.Telemetry.Tests { + [ResetAppContextSwitches] public class TelemetryClientDomainExtractionTests { [Theory] @@ -74,9 +76,6 @@ public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddre try { - // Reset switches first to clear any cached values - AppContextSwitches.ResetAllSwitches(); - // Enable the switch to use full metadata address AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); @@ -88,8 +87,8 @@ public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddre } finally { - // Cleanup - AppContextSwitches.ResetAllSwitches(); + // Cleanup is handled by ResetAppContextSwitches attribute + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); } } From 27828deabee1765a4dc1aa456345abd26f3cf806 Mon Sep 17 00:00:00 2001 From: Westin Musser <127992899+westin-m@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:09:23 -0700 Subject: [PATCH 7/8] avoid tast failures causes by app context switch interference --- .../ClaimsIdentityFactoryTests.cs | 10 +- .../TelemetryClientDomainExtractionTests.cs | 220 +++++++++--------- 2 files changed, 113 insertions(+), 117 deletions(-) diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs index f1878a638b..1a1cf0da39 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs @@ -9,14 +9,10 @@ namespace Microsoft.IdentityModel.Tokens.Tests { - [Collection(nameof(ClaimsIdentityFactoryTests))] + [ResetAppContextSwitches] + [Collection("AppContextSwitches")] public class ClaimsIdentityFactoryTests { - public ClaimsIdentityFactoryTests() - { - AppContextSwitches.ResetAllSwitches(); - } - [Theory] [InlineData(true)] [InlineData(false)] @@ -47,7 +43,7 @@ public void Create_FromTokenValidationParameters_ReturnsCorrectClaimsIdentity(bo Assert.Equal(jsonWebToken, ((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); } - AppContextSwitches.ResetAllSwitches(); + AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, false); } [Theory] diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs index 0b8468660f..4cba8625b5 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Telemetry/TelemetryClientDomainExtractionTests.cs @@ -6,106 +6,136 @@ using Microsoft.IdentityModel.Tokens; using Xunit; -namespace Microsoft.IdentityModel.Telemetry.Tests +namespace Microsoft.IdentityModel.Telemetry.Tests; + +[ResetAppContextSwitches] +[Collection("AppContextSwitches")] +public class TelemetryClientDomainExtractionTests { - [ResetAppContextSwitches] - public class TelemetryClientDomainExtractionTests + [Theory] + [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] + [InlineData("https://www.login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "www.login.microsoftonline.com")] + [InlineData("https://accounts.google.com/.well-known/openid-configuration", "accounts.google.com")] + [InlineData("https://login.windows.net/common/.well-known/openid-configuration", "login.windows.net")] + [InlineData("http://localhost:8080/.well-known/openid-configuration", "localhost")] + [InlineData("https://example.com/path/to/config", "example.com")] + [InlineData("https://subdomain.example.org/config.json", "subdomain.example.org")] + public void GetMetadataAddressForTelemetry_SuccessCase_ReturnsExpectedDomain(string fullAddress, string expectedDomain) { - [Theory] - [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "login.microsoftonline.com")] - [InlineData("https://www.login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", "www.login.microsoftonline.com")] - [InlineData("https://accounts.google.com/.well-known/openid-configuration", "accounts.google.com")] - [InlineData("https://login.windows.net/common/.well-known/openid-configuration", "login.windows.net")] - [InlineData("http://localhost:8080/.well-known/openid-configuration", "localhost")] - [InlineData("https://example.com/path/to/config", "example.com")] - [InlineData("https://subdomain.example.org/config.json", "subdomain.example.org")] - public void GetMetadataAddressForTelemetry_SuccessCase_ReturnsExpectedDomain(string fullAddress, string expectedDomain) - { - // Act - var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, true); + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, true); - // Assert - Assert.Equal(expectedDomain, result); - } + // Assert + Assert.Equal(expectedDomain, result); + } - [Fact] - public void DebugAppContextSwitch() - { - // Check if the AppContext switch is causing issues - var switchValue = AppContextSwitches.UseFullMetadataAddressForTelemetry; + [Fact] + public void DebugAppContextSwitch() + { + // Check if the AppContext switch is causing issues + var switchValue = AppContextSwitches.UseFullMetadataAddressForTelemetry; - var testUrl = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; - var result = TelemetryClient.GetMetadataAddressForTelemetry(testUrl); + var testUrl = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; + var result = TelemetryClient.GetMetadataAddressForTelemetry(testUrl); - // The switch should be false by default, so we should get the host name - Assert.False(switchValue, $"Switch value: {switchValue}"); - Assert.Equal("login.microsoftonline.com", result); - } + // The switch should be false by default, so we should get the host name + Assert.False(switchValue, $"Switch value: {switchValue}"); + Assert.Equal("login.microsoftonline.com", result); + } - [Theory] - [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")] - [InlineData("https://accounts.google.com/.well-known/openid-configuration")] - [InlineData("https://login.windows.net/common/.well-known/openid-configuration")] - public void GetMetadataAddressForTelemetry_ErrorCase_ReturnsFullAddress(string fullAddress) - { - // Act - var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, false); + [Theory] + [InlineData("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")] + [InlineData("https://accounts.google.com/.well-known/openid-configuration")] + [InlineData("https://login.windows.net/common/.well-known/openid-configuration")] + public void GetMetadataAddressForTelemetry_ErrorCase_ReturnsFullAddress(string fullAddress) + { + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, false); - // Assert - Assert.Equal(fullAddress, result); - } + // Assert + Assert.Equal(fullAddress, result); + } - [Theory] - [InlineData("invalid-url")] - [InlineData("")] - [InlineData(null)] - public void GetMetadataAddressForTelemetry_InvalidUrl_ReturnsOriginalString(string invalidUrl) + [Theory] + [InlineData("invalid-url")] + [InlineData("")] + [InlineData(null)] + public void GetMetadataAddressForTelemetry_InvalidUrl_ReturnsOriginalString(string invalidUrl) + { + // Act + var result = TelemetryClient.GetMetadataAddressForTelemetry(invalidUrl, true); + + // Assert + Assert.Equal(invalidUrl, result); + } + + [Fact] + public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddress() + { + // Arrange + var fullAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; + + try { + // Enable the switch to use full metadata address + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); + // Act - var result = TelemetryClient.GetMetadataAddressForTelemetry(invalidUrl, true); + var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, true); // Assert - Assert.Equal(invalidUrl, result); + Assert.Equal(fullAddress, result); } - - [Fact] - public void GetMetadataAddressForTelemetry_WithAppContextSwitch_ReturnsFullAddress() + finally { - // Arrange - var fullAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; - - try - { - // Enable the switch to use full metadata address - AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); - - // Act - var result = TelemetryClient.GetMetadataAddressForTelemetry(fullAddress, true); - - // Assert - Assert.Equal(fullAddress, result); - } - finally - { - // Cleanup is handled by ResetAppContextSwitches attribute - AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); - } + // Cleanup is handled by ResetAppContextSwitches attribute + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); } + } + + [Fact] + public void TelemetryClient_Methods_DoNotThrow() + { + // This test ensures that the modified telemetry methods don't break existing functionality + // We cannot easily verify the exact values sent to the telemetry system without complex setup, + // but we can ensure the methods don't throw exceptions when called with valid parameters. + + // Arrange + var telemetryClient = new TelemetryClient(); + var testAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; + var testDuration = TimeSpan.FromMilliseconds(100); + var testException = new InvalidOperationException("Test exception"); + + // Act & Assert - these should not throw + var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); + var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); + var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); + var ex4 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "ConfigurationRetrievalFailed", "Retriever", testException)); + var ex5 = Record.Exception(() => telemetryClient.LogBackgroundConfigurationRefreshFailure(testAddress, "Retriever", testException)); + + Assert.Null(ex1); + Assert.Null(ex2); + Assert.Null(ex3); + Assert.Null(ex4); + Assert.Null(ex5); + } - [Fact] - public void TelemetryClient_Methods_DoNotThrow() + [Fact] + public void TelemetryClient_WithAppContextSwitch_DoesNotThrow() + { + // Test that telemetry methods work correctly when the backward compatibility switch is enabled + try { - // This test ensures that the modified telemetry methods don't break existing functionality - // We cannot easily verify the exact values sent to the telemetry system without complex setup, - // but we can ensure the methods don't throw exceptions when called with valid parameters. + // Enable the switch to use full metadata address + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); // Arrange var telemetryClient = new TelemetryClient(); - var testAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; - var testDuration = TimeSpan.FromMilliseconds(100); + var testAddress = "https://accounts.google.com/.well-known/openid-configuration"; + var testDuration = TimeSpan.FromMilliseconds(150); var testException = new InvalidOperationException("Test exception"); - // Act & Assert - these should not throw + // Act & Assert - these should not throw even with the switch enabled var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); @@ -118,40 +148,10 @@ public void TelemetryClient_Methods_DoNotThrow() Assert.Null(ex4); Assert.Null(ex5); } - - [Fact] - public void TelemetryClient_WithAppContextSwitch_DoesNotThrow() + finally { - // Test that telemetry methods work correctly when the backward compatibility switch is enabled - try - { - // Enable the switch to use full metadata address - AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, true); - - // Arrange - var telemetryClient = new TelemetryClient(); - var testAddress = "https://accounts.google.com/.well-known/openid-configuration"; - var testDuration = TimeSpan.FromMilliseconds(150); - var testException = new InvalidOperationException("Test exception"); - - // Act & Assert - these should not throw even with the switch enabled - var ex1 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration)); - var ex2 = Record.Exception(() => telemetryClient.LogConfigurationRetrievalDuration(testAddress, "Retriever", testDuration, testException)); - var ex3 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "FirstRefresh", "Retriever")); - var ex4 = Record.Exception(() => telemetryClient.IncrementConfigurationRefreshRequestCounter(testAddress, "ConfigurationRetrievalFailed", "Retriever", testException)); - var ex5 = Record.Exception(() => telemetryClient.LogBackgroundConfigurationRefreshFailure(testAddress, "Retriever", testException)); - - Assert.Null(ex1); - Assert.Null(ex2); - Assert.Null(ex3); - Assert.Null(ex4); - Assert.Null(ex5); - } - finally - { - // Cleanup - AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); - } + // Cleanup + AppContext.SetSwitch(AppContextSwitches.UseFullMetadataAddressForTelemetrySwitch, false); } } } From 6c190a8aafb858a6a4653eb493ab4c69388d0ada Mon Sep 17 00:00:00 2001 From: Westin Musser <127992899+westin-m@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:46:21 -0700 Subject: [PATCH 8/8] pr feedback --- .../Telemetry/TelemetryClient.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs index 3c3019e725..73ad2100a1 100644 --- a/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs +++ b/src/Microsoft.IdentityModel.Tokens/Telemetry/TelemetryClient.cs @@ -36,16 +36,11 @@ internal static string GetMetadataAddressForTelemetry(string metadataAddress, bo if (!isSuccessCase || AppContextSwitches.UseFullMetadataAddressForTelemetry || string.IsNullOrEmpty(metadataAddress)) return metadataAddress; - try - { - var uri = new Uri(metadataAddress, UriKind.Absolute); - return uri.Host; - } - catch (UriFormatException) - { - // If parsing fails, return the original address - return metadataAddress; - } + + if (Uri.TryCreate(metadataAddress, UriKind.Absolute, out Uri result)) + return result.Host; + + return metadataAddress; } public void IncrementConfigurationRefreshRequestCounter(string metadataAddress, string operationStatus, string configurationSource)