diff --git a/benchmark/Microsoft.IdentityModel.Benchmarks/ValidatorBenchmarks.cs b/benchmark/Microsoft.IdentityModel.Benchmarks/ValidatorBenchmarks.cs
new file mode 100644
index 0000000000..8a77031c81
--- /dev/null
+++ b/benchmark/Microsoft.IdentityModel.Benchmarks/ValidatorBenchmarks.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using BenchmarkDotNet.Attributes;
+using Microsoft.IdentityModel.Tokens;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.IdentityModel.Benchmarks
+{
+ ///
+ /// Benchmarks for validator methods to measure performance of different implementations
+ ///
+ public class ValidatorBenchmarks
+ {
+ private List _audiences;
+ private TokenValidationParameters _parametersWithList;
+ private TokenValidationParameters _parametersWithEnumerable;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _audiences = ["audience1"];
+ var validAudiences = new List { "invalid1", "invalid2", "audience1" }; // Make sure audience is last to maximize iteration
+
+ _parametersWithList = new TokenValidationParameters
+ {
+ ValidAudiences = validAudiences
+ };
+
+ _parametersWithEnumerable = new TokenValidationParameters
+ {
+ ValidAudiences = validAudiences.Select(x => x) // Force enumerable by using LINQ
+ };
+ }
+
+ [Benchmark(Baseline = true)]
+ public void ValidateAudience_WithList()
+ {
+ Validators.ValidateAudience(_audiences, null, _parametersWithList);
+ }
+
+ [Benchmark]
+ public void ValidateAudience_WithEnumerable()
+ {
+ Validators.ValidateAudience(_audiences, null, _parametersWithEnumerable);
+ }
+ }
+}
diff --git a/src/Microsoft.IdentityModel.Tokens/Validators.cs b/src/Microsoft.IdentityModel.Tokens/Validators.cs
index 033afa3aea..6537571426 100644
--- a/src/Microsoft.IdentityModel.Tokens/Validators.cs
+++ b/src/Microsoft.IdentityModel.Tokens/Validators.cs
@@ -143,10 +143,10 @@ private static bool AudienceIsValid(IEnumerable audiences, TokenValidati
if (string.IsNullOrWhiteSpace(tokenAudience))
continue;
- foreach (string validAudience in validationParametersAudiences)
+ bool TryMatchAudience(string validAudience)
{
if (string.IsNullOrWhiteSpace(validAudience))
- continue;
+ return false;
if (AudiencesMatch(validationParameters, tokenAudience, validAudience))
{
@@ -155,6 +155,25 @@ private static bool AudienceIsValid(IEnumerable audiences, TokenValidati
return true;
}
+
+ return false;
+ }
+
+ if (validationParametersAudiences is IList audienceList)
+ {
+ for (int i = 0; i < audienceList.Count; i++)
+ {
+ if (TryMatchAudience(audienceList[i]))
+ return true;
+ }
+ }
+ else
+ {
+ foreach (string validAudience in validationParametersAudiences)
+ {
+ if (TryMatchAudience(validAudience))
+ return true;
+ }
}
}
diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Microsoft.IdentityModel.Tokens.Tests.csproj b/test/Microsoft.IdentityModel.Tokens.Tests/Microsoft.IdentityModel.Tokens.Tests.csproj
index 339a012f98..ae85d7c4b5 100644
--- a/test/Microsoft.IdentityModel.Tokens.Tests/Microsoft.IdentityModel.Tokens.Tests.csproj
+++ b/test/Microsoft.IdentityModel.Tokens.Tests/Microsoft.IdentityModel.Tokens.Tests.csproj
@@ -22,7 +22,7 @@
-
+
diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs
index 9d3ab30aad..2e90c50ee4 100644
--- a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs
+++ b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs
@@ -270,6 +270,23 @@ public static TheoryData ValidateAudienceTheoryDat
Audiences = audiences1WithTwoSlashes,
ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"),
TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 }
+ },
+ new AudienceValidationTheoryData("ValidAudiencesList_OptimizedPath")
+ {
+ Audiences = new List { "audience1" },
+ TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidAudiences = new List { "invalidAudience", "audience1" } // Using List to test IList optimization
+ }
+ },
+ new AudienceValidationTheoryData("ValidAudiencesList_EmptyList_OptimizedPath")
+ {
+ Audiences = new List { "audience1" },
+ ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"),
+ TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidAudiences = new List() // Empty list should still return false through optimized path
+ }
}
};
}