diff --git a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs
index d1f6dbcc06..77061bf75a 100644
--- a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs
+++ b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs
@@ -365,7 +365,10 @@ public TimeSpan ClockSkew
/// This is a shallow Clone.
public virtual TokenValidationParameters Clone()
{
- return new TokenValidationParameters(this);
+ return new(this)
+ {
+ IsClone = true
+ };
}
///
@@ -451,6 +454,17 @@ public virtual ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken,
///
public IssuerSigningKeyValidatorUsingConfiguration IssuerSigningKeyValidatorUsingConfiguration { get; set; }
+ ///
+ /// Gets a that is unique to this instance.
+ /// Calling will result in a new instance of this IDictionary.
+ ///
+ public IDictionary InstancePropertyBag { get; } = new Dictionary();
+
+ ///
+ /// Gets a value indicating if was called to obtain this instance.
+ ///
+ public bool IsClone { get; protected set; } = false;
+
///
/// Gets or sets the that is to be used for signature validation.
///
@@ -565,7 +579,7 @@ public string NameClaimType
///
/// Gets or sets the that contains a collection of custom key/value pairs. This allows addition of parameters that could be used in custom token validation scenarios.
///
- public IDictionary PropertyBag { get; set; }
+ public IDictionary PropertyBag { get; set; }
///
/// Gets or sets a boolean to control if configuration required to be refreshed before token validation.
diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationParametersTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationParametersTests.cs
index 98971edfd4..2ce625a6ff 100644
--- a/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationParametersTests.cs
+++ b/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationParametersTests.cs
@@ -10,6 +10,7 @@
using Microsoft.IdentityModel.Protocols.WsFederation;
using Microsoft.IdentityModel.TestUtils;
using Xunit;
+using Xunit.Sdk;
namespace Microsoft.IdentityModel.Tokens.Tests
{
@@ -21,8 +22,8 @@ public void Publics()
TokenValidationParameters validationParameters = new TokenValidationParameters();
Type type = typeof(TokenValidationParameters);
PropertyInfo[] properties = type.GetProperties();
- if (properties.Length != 54)
- Assert.True(false, "Number of properties has changed from 54 to: " + properties.Length + ", adjust tests");
+ if (properties.Length != 56)
+ Assert.True(false, "Number of properties has changed from 56 to: " + properties.Length + ", adjust tests");
TokenValidationParameters actorValidationParameters = new TokenValidationParameters();
SecurityKey issuerSigningKey = KeyingMaterial.DefaultX509Key_2048_Public;
@@ -125,13 +126,27 @@ public void Publics()
var compareContext = new CompareContext();
IdentityComparer.AreEqual(validationParametersInline, validationParametersSets, compareContext);
- IdentityComparer.AreEqual(validationParametersInline.Clone() as TokenValidationParameters, validationParametersInline, compareContext);
+
+ // only exlude 'IsClone' when comparing Clone vs. Original.
+ var instanceContext = new CompareContext();
+ instanceContext.PropertiesToIgnoreWhenComparing.Add(typeof(TokenValidationParameters), new List { "IsClone" });
+ TokenValidationParameters validationParametersInLineClone = validationParametersInline.Clone();
+ IdentityComparer.AreEqual(validationParametersInLineClone, validationParametersInline, instanceContext);
+ if (!validationParametersInLineClone.IsClone)
+ instanceContext.AddDiff("!validationParametersInLineClone.IsClone)");
string id = Guid.NewGuid().ToString();
DerivedTokenValidationParameters derivedValidationParameters = new DerivedTokenValidationParameters(id, validationParametersInline);
DerivedTokenValidationParameters derivedValidationParametersCloned = derivedValidationParameters.Clone() as DerivedTokenValidationParameters;
- IdentityComparer.AreEqual(derivedValidationParameters, derivedValidationParametersCloned, compareContext);
+ IdentityComparer.AreEqual(derivedValidationParameters, derivedValidationParametersCloned, instanceContext);
IdentityComparer.AreEqual(derivedValidationParameters.InternalString, derivedValidationParametersCloned.InternalString, compareContext);
+ if (!derivedValidationParametersCloned.IsClone)
+ instanceContext.AddDiff("!derivedValidationParametersCloned.IsClone)");
+
+ TokenValidationParameters tokenValidationParametersClone = validationParametersInline.Clone();
+ IdentityComparer.AreEqual(tokenValidationParametersClone, tokenValidationParametersClone, instanceContext);
+
+ compareContext.Merge(instanceContext);
TestUtilities.AssertFailIfErrors(compareContext);
}
@@ -142,8 +157,8 @@ public void GetSets()
TokenValidationParameters validationParameters = new TokenValidationParameters();
Type type = typeof(TokenValidationParameters);
PropertyInfo[] properties = type.GetProperties();
- if (properties.Length != 54)
- Assert.True(false, "Number of public fields has changed from 54 to: " + properties.Length + ", adjust tests");
+ if (properties.Length != 56)
+ Assert.True(false, "Number of public fields has changed from 56 to: " + properties.Length + ", adjust tests");
GetSetContext context =
new GetSetContext
@@ -185,6 +200,31 @@ public void GetSets()
Assert.Null(validationParameters.SignatureValidator);
}
+ [Fact]
+ public void Clone()
+ {
+ object obj = new object();
+ var compareContext = new CompareContext();
+
+ TokenValidationParameters validationParameters = new TokenValidationParameters();
+ validationParameters.PropertyBag = new Dictionary { { "object", obj } };
+ validationParameters.InstancePropertyBag["object"] = obj;
+
+ compareContext.PropertiesToIgnoreWhenComparing.Add(typeof(TokenValidationParameters), new List { "InstancePropertyBag", "IsClone" });
+ TokenValidationParameters validationParametersClone = validationParameters.Clone();
+ IdentityComparer.AreEqual(validationParametersClone, validationParameters, compareContext);
+ if (validationParameters.IsClone)
+ compareContext.AddDiff("if (validationParameters.IsClone), IsCone should be false");
+
+ if (!validationParametersClone.IsClone)
+ compareContext.AddDiff("if (!validationParametersClone.IsClone), IsCone should be true");
+
+ if (validationParametersClone.InstancePropertyBag.Count != 0)
+ compareContext.AddDiff("validationParametersClone.InstancePropertyBag.Count != 0), should be empty.");
+
+ TestUtilities.AssertFailIfErrors(compareContext);
+ }
+
class DerivedTokenValidationParameters : TokenValidationParameters
{
string _internalString;
@@ -204,7 +244,9 @@ protected DerivedTokenValidationParameters(DerivedTokenValidationParameters othe
public override TokenValidationParameters Clone()
{
- return new DerivedTokenValidationParameters(this);
+ DerivedTokenValidationParameters derivedTokenValidationParameters = new DerivedTokenValidationParameters(this);
+ derivedTokenValidationParameters.IsClone = true;
+ return derivedTokenValidationParameters;
}
}
}