From ebcc58b93a4cf5995a3e3aaf11a22d2f18bb9b56 Mon Sep 17 00:00:00 2001 From: kellyyangsong <69649063+kellyyangsong@users.noreply.github.com> Date: Fri, 13 Dec 2024 23:23:48 -0800 Subject: [PATCH] Respect TVP.RequireAudience when set to false (#3055) * Fix AudienceValidationTheoryData to include testId * respect TVP.RequireAudience if false, unit test * add more details to TVP.RequireAudience flag * add test cases * specify TVP.RequireAudiences is used for SAML or JWT tokens --- .../InternalAPI.Unshipped.txt | 1 + .../LogMessages.cs | 1 + .../TokenValidationParameters.cs | 6 +- .../Validators.cs | 6 + .../Validation/ValidatorsTests.cs | 122 +++++++++--------- 5 files changed, 73 insertions(+), 63 deletions(-) diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index c05846e38a..6e9eef5fa4 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -8,6 +8,7 @@ const Microsoft.IdentityModel.Tokens.LogMessages.IDX10273 = "IDX10273: Algorithm const Microsoft.IdentityModel.Tokens.LogMessages.IDX10274 = "IDX10274: IssuerSigningKeyValidationDelegate threw an exception, see inner exception." -> string const Microsoft.IdentityModel.Tokens.LogMessages.IDX10275 = "IDX10275: TokenTypeValidationDelegate threw an exception, see inner exception." -> string const Microsoft.IdentityModel.Tokens.LogMessages.IDX10276 = "IDX10276: TokenReplayValidationDelegate threw an exception, see inner exception." -> string +const Microsoft.IdentityModel.Tokens.LogMessages.IDX10277 = "IDX10277: RequireAudience property on ValidationParameters is set to false. Exiting without validating the audience." -> string Microsoft.IdentityModel.Tokens.AlgorithmValidationError Microsoft.IdentityModel.Tokens.AlgorithmValidationError.AlgorithmValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidAlgorithm, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.AlgorithmValidationError.InvalidAlgorithm.get -> string diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index 0d10c18695..a07f46494d 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -95,6 +95,7 @@ internal static class LogMessages public const string IDX10274 = "IDX10274: IssuerSigningKeyValidationDelegate threw an exception, see inner exception."; public const string IDX10275 = "IDX10275: TokenTypeValidationDelegate threw an exception, see inner exception."; public const string IDX10276 = "IDX10276: TokenReplayValidationDelegate threw an exception, see inner exception."; + public const string IDX10277 = "IDX10277: RequireAudience property on ValidationParameters is set to false. Exiting without validating the audience."; // 10500 - SignatureValidation public const string IDX10500 = "IDX10500: Signature validation failed. No security keys were provided to validate the signature."; diff --git a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs index 7ea251d8dc..5ba076d00b 100644 --- a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs +++ b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs @@ -459,9 +459,13 @@ public string NameClaimType public bool RefreshBeforeValidation { get; set; } /// - /// Gets or sets a value indicating whether SAML tokens must have at least one AudienceRestriction. + /// Gets or sets a value indicating whether SAML or JWT tokens must have at least one AudienceRestriction. /// The default is true. /// + /// + /// If set to false and the Audience is null, Audience validation will be skipped. + /// If set to false and the Audience is not null, the Audience will still be validated. + /// [DefaultValue(true)] public bool RequireAudience { get; set; } diff --git a/src/Microsoft.IdentityModel.Tokens/Validators.cs b/src/Microsoft.IdentityModel.Tokens/Validators.cs index 49946550cd..a75bd5bfa4 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validators.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validators.cs @@ -87,6 +87,12 @@ public static void ValidateAudience(IEnumerable audiences, SecurityToken return; } + if (!validationParameters.RequireAudience && !audiences.Any()) + { + LogHelper.LogWarning(LogMessages.IDX10277); + return; + } + if (audiences == null) throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidAudienceException(LogMessages.IDX10207) { InvalidAudience = null }); diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs index 788a662384..9d3ab30aad 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs @@ -28,91 +28,105 @@ public void ValidateAudienceParameters(AudienceValidationTheoryData theoryData) TestUtilities.AssertFailIfErrors(context); } + public static TheoryData ValidateAudienceParametersTheoryData { get { return new TheoryData { - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenValidationParametersNull") { Audiences = new List { "audience1" }, ExpectedException = ExpectedException.ArgumentNullException("IDX10000:"), - TestId = "TokenValidationParametersNull", TokenValidationParameters = null }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("AudiencesEmptyString") { Audiences = new List { "" }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "AudiencesEmptyString", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = "audience"} }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("AudiencesWhiteSpace") { Audiences = new List { " " }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "AudiencesWhiteSpace", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = "audience"} }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("AudiencesNull") { Audiences = null, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10207:"), - TestId = "AudiencesNull" }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("AudiencesEmptyList") { Audiences = new List{ }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10206:"), - TestId = "AudiencesEmptyList", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = "audience"} }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidateAudienceFalseAudiencesEmptyList") { Audiences = new List{ }, - TestId = "ValidateAudienceFalseAudiencesEmptyList", TokenValidationParameters = new TokenValidationParameters{ ValidateAudience = false } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidateAudienceFalseAudiencesNull") { Audiences = null, - TestId = "ValidateAudienceFalseAudiencesNull", TokenValidationParameters = new TokenValidationParameters{ ValidateAudience = false } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudienceEmptyString") { Audiences = new List { "audience1" }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10208:"), - TestId = "ValidAudienceEmptyString", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = "" } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudienceWhiteSpace") { Audiences = new List { "audience1" }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10208:"), - TestId = "ValidAudienceWhiteSpace", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = " " } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudiencesEmptyString") { Audiences = new List { "audience1" }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudiencesEmptyString", TokenValidationParameters = new TokenValidationParameters{ ValidAudiences = new List{ "" } } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudiencesWhiteSpace") { Audiences = new List { "audience1" }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudiencesWhiteSpace", TokenValidationParameters = new TokenValidationParameters{ ValidAudiences = new List{ " " } } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidateAudienceTrueValidAudienceAndValidAudiencesNull") { Audiences = new List { "audience1" }, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10208:"), - TestId = "ValidateAudienceTrueValidAudienceAndValidAudiencesNull" + }, + new AudienceValidationTheoryData("AudiencesEmpty_RequireAudienceFalse_NoException") + { + Audiences = new List { }, + TokenValidationParameters = new TokenValidationParameters{ + RequireAudience = false + // default value of TVP.RequireAudience is true. + } + }, + new AudienceValidationTheoryData("ValidAudience_RequireAudienceFalse_NoException") + { + Audiences = new List { "audience" }, + TokenValidationParameters = new TokenValidationParameters{ + ValidAudience = "audience", + RequireAudience = false + } + }, + new AudienceValidationTheoryData("InvalidAudience_RequireAudienceFalse_ExceptionThrown") + { + Audiences = new List { "audience1" }, + ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), + TokenValidationParameters = new TokenValidationParameters{ + ValidAudience = "audience", + RequireAudience = false + } } }; } @@ -149,131 +163,112 @@ public static TheoryData ValidateAudienceTheoryDat return new TheoryData { - new AudienceValidationTheoryData + new AudienceValidationTheoryData("SameLengthMatched") { Audiences = audiences1, - TestId = "SameLengthMatched", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("SameLengthNotMatched") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "SameLengthNotMatched", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience2 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("NoMatchTVPValidateFalse") { Audiences = audiences1, - TestId = "NoMatchTVPValidateFalse", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience2, ValidateAudience = false } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("AudiencesValidAudienceWithSlashNotMatched") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "AudiencesValidAudienceWithSlashNotMatched", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience2 + "/" } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("AudiencesWithSlashValidAudienceSameLengthNotMatched") { Audiences = audiences2WithSlash, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "AudiencesWithSlashValidAudienceSameLengthNotMatched", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudienceWithSlashTVPFalse") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudienceWithSlashTVPFalse", TokenValidationParameters = new TokenValidationParameters{ IgnoreTrailingSlashWhenValidatingAudience = false, ValidAudience = audience1 + "/" } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudienceWithSlashTVPTrue") { Audiences = audiences1, - TestId = "ValidAudienceWithSlashTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 + "/" } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudiencesWithSlashTVPFalse") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudiencesWithSlashTVPFalse", TokenValidationParameters = new TokenValidationParameters{ IgnoreTrailingSlashWhenValidatingAudience = false, ValidAudiences = audiences1WithSlash } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudiencesWithSlashTVPTrue") { Audiences = audiences1, - TestId = "ValidAudiencesWithSlashTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudiences = audiences1WithSlash } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudienceWithExtraChar") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudienceWithExtraChar", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 + "A" } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudienceWithDoubleSlashTVPTrue") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudienceWithDoubleSlashTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 + "//" } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("ValidAudiencesWithDoubleSlashTVPTrue") { Audiences = audiences1, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "ValidAudiencesWithDoubleSlashTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudiences = audiences1WithTwoSlashes } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudienceWithSlashTVPFalse") { Audiences = audiences1WithSlash, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "TokenAudienceWithSlashTVPFalse", TokenValidationParameters = new TokenValidationParameters{ IgnoreTrailingSlashWhenValidatingAudience = false, ValidAudience = audience1 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudienceWithSlashTVPTrue") { Audiences = audiences1WithSlash, - TestId = "TokenAudienceWithSlashTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudienceWithSlashNotEqual") { Audiences = audiences2WithSlash, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "TokenAudienceWithSlashNotEqual", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 }, }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudiencesWithSlashTVPFalse") { Audiences = audiences1WithSlash, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "TokenAudiencesWithSlashTVPFalse", TokenValidationParameters = new TokenValidationParameters{ IgnoreTrailingSlashWhenValidatingAudience = false, ValidAudience = audience1 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudiencesWithSlashTVPTrue") { Audiences = audiences1WithSlash, - TestId = "TokenAudiencesWithSlashTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudiencesWithSlashValidAudiencesNotMatchedTVPTrue") { Audiences = audiences1WithSlash, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "TokenAudiencesWithSlashValidAudiencesNotMatchedTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudiences = audiences2 } }, - new AudienceValidationTheoryData + new AudienceValidationTheoryData("TokenAudienceWithTwoSlashesTVPTrue") { Audiences = audiences1WithTwoSlashes, ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"), - TestId = "TokenAudienceWithTwoSlashesTVPTrue", TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 } } }; @@ -500,6 +495,9 @@ public bool TryFind(string securityToken) public class AudienceValidationTheoryData : TheoryDataBase { + public AudienceValidationTheoryData(string testId) : base(testId) + { } + public List Audiences { get; set; } public SecurityToken SecurityToken { get; set; }