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; }