Skip to content

Commit

Permalink
Cache context switches (#2724)
Browse files Browse the repository at this point in the history
* Cache context switches.

* Refactor switch reset in tests.

* Rename.

* Refactor to reset switches in one method.

* Fix tests.

* Fix tests.
  • Loading branch information
pmaytak authored Jul 17, 2024
1 parent 8c5e456 commit 7ef3263
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ internal static string GetStringClaimValueType(string str)

internal static string GetStringClaimValueType(string str, string claimType)
{
if (!string.IsNullOrEmpty(claimType) && !JsonSerializerPrimitives.TryAllStringClaimsAsDateTime() && JsonSerializerPrimitives.IsKnownToNotBeDateTime(claimType))
if (!string.IsNullOrEmpty(claimType) && !AppContextSwitches.TryAllStringClaimsAsDateTime && JsonSerializerPrimitives.IsKnownToNotBeDateTime(claimType))
return ClaimValueTypes.String;

if (DateTime.TryParse(str, out DateTime dateTimeValue))
Expand Down
38 changes: 37 additions & 1 deletion src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,42 @@ internal static class AppContextSwitches
/// </summary>
internal const string UseClaimsIdentityTypeSwitch = "Microsoft.IdentityModel.Tokens.UseClaimsIdentityType";

internal static bool UseClaimsIdentityType() => (AppContext.TryGetSwitch(UseClaimsIdentityTypeSwitch, out bool useClaimsIdentityType) && useClaimsIdentityType);
private static bool? _useClaimsIdentity;

internal static bool UseClaimsIdentityType => _useClaimsIdentity ??= (AppContext.TryGetSwitch(UseClaimsIdentityTypeSwitch, out bool useClaimsIdentityType) && useClaimsIdentityType);

/// <summary>
/// When validating the issuer signing key, specifies whether to fail if the 'tid' claim is missing.
/// </summary>
internal const string DoNotFailOnMissingTidSwitch = "Switch.Microsoft.IdentityModel.DontFailOnMissingTidValidateIssuerSigning";

private static bool? _doNotFailOnMissingTid;

internal static bool DontFailOnMissingTid => _doNotFailOnMissingTid ??= (AppContext.TryGetSwitch(DoNotFailOnMissingTidSwitch, out bool doNotFailOnMissingTid) && doNotFailOnMissingTid);

/// <summary>
/// When reading claims from the token, specifies whether to try to convert all string claims to DateTime.
/// Some claims are known not to be DateTime, so conversion is skipped.
/// </summary>
internal const string TryAllStringClaimsAsDateTimeSwitch = "Switch.Microsoft.IdentityModel.TryAllStringClaimsAsDateTime";

private static bool? _tryAllStringClaimsAsDateTime;

internal static bool TryAllStringClaimsAsDateTime => _tryAllStringClaimsAsDateTime ??= (AppContext.TryGetSwitch(TryAllStringClaimsAsDateTimeSwitch, out bool tryAsDateTime) && tryAsDateTime);

/// <summary>
/// Used for testing to reset all switches to its default value.
/// </summary>
internal static void ResetAllSwitches()
{
_useClaimsIdentity = null;
AppContext.SetSwitch(UseClaimsIdentityTypeSwitch, false);

_doNotFailOnMissingTid = null;
AppContext.SetSwitch(DoNotFailOnMissingTidSwitch, false);

_tryAllStringClaimsAsDateTime = null;
AppContext.SetSwitch(TryAllStringClaimsAsDateTimeSwitch, false);
}
}
}
6 changes: 3 additions & 3 deletions src/Microsoft.IdentityModel.Tokens/ClaimsIdentityFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ internal static class ClaimsIdentityFactory
{
internal static ClaimsIdentity Create(IEnumerable<Claim> claims)
{
if (AppContextSwitches.UseClaimsIdentityType())
if (AppContextSwitches.UseClaimsIdentityType)
return new ClaimsIdentity(claims);

return new CaseSensitiveClaimsIdentity(claims);
}

internal static ClaimsIdentity Create(IEnumerable<Claim> claims, string authenticationType)
{
if (AppContextSwitches.UseClaimsIdentityType())
if (AppContextSwitches.UseClaimsIdentityType)
return new ClaimsIdentity(claims, authenticationType);

return new CaseSensitiveClaimsIdentity(claims, authenticationType);
}

internal static ClaimsIdentity Create(string authenticationType, string nameType, string roleType, SecurityToken securityToken)
{
if (AppContextSwitches.UseClaimsIdentityType())
if (AppContextSwitches.UseClaimsIdentityType)
return new ClaimsIdentity(authenticationType: authenticationType, nameType: nameType, roleType: roleType);

return new CaseSensitiveClaimsIdentity(authenticationType: authenticationType, nameType: nameType, roleType: roleType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ internal static object CreateObjectFromJsonElement(JsonElement jsonElement, int

if (jsonElement.ValueKind == JsonValueKind.String)
{
if (!string.IsNullOrEmpty(claimType) && !TryAllStringClaimsAsDateTime() && IsKnownToNotBeDateTime(claimType))
if (!string.IsNullOrEmpty(claimType) && !AppContextSwitches.TryAllStringClaimsAsDateTime && IsKnownToNotBeDateTime(claimType))
return jsonElement.GetString();

if (DateTime.TryParse(jsonElement.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime dateTime))
Expand Down Expand Up @@ -705,13 +705,6 @@ internal static string ReadStringOrNumberAsString(ref Utf8JsonReader reader, str
return retVal;
}

internal const string TryToCreateDateTimeClaimsSwitch = "Switch.Microsoft.IdentityModel.TryAllStringClaimsAsDateTime";

public static bool TryAllStringClaimsAsDateTime()
{
return (AppContext.TryGetSwitch(TryToCreateDateTimeClaimsSwitch, out bool tryAsDateTime) && tryAsDateTime);
}

/// <summary>
/// This is a non-exhaustive list of claim types that are not expected to be DateTime values
/// sourced from expected Entra V1 and V2 claims, OpenID Connect claims, and a selection of
Expand Down Expand Up @@ -833,7 +826,7 @@ internal static object ReadStringAsObject(ref Utf8JsonReader reader, string prop

string originalString = reader.GetString();

if (!TryAllStringClaimsAsDateTime() && IsKnownToNotBeDateTime(propertyName))
if (!AppContextSwitches.TryAllStringClaimsAsDateTime && IsKnownToNotBeDateTime(propertyName))
{
reader.Read();
return originalString;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ public static void EnableAadSigningKeyIssuerValidation(this TokenValidationParam
};
}

internal const string DontFailOnMissingTidSwitch = "Switch.Microsoft.IdentityModel.DontFailOnMissingTidValidateIssuerSigning";

private static bool DontFailOnMissingTid()
{
return (AppContext.TryGetSwitch(DontFailOnMissingTidSwitch, out bool dontFailOnMissingTid) && dontFailOnMissingTid);
}

/// <summary>
/// Validates the issuer signing key.
/// </summary>
Expand Down Expand Up @@ -81,7 +74,7 @@ internal static bool ValidateIssuerSigningKey(SecurityKey securityKey, SecurityT
var tenantIdFromToken = GetTid(securityToken);
if (string.IsNullOrEmpty(tenantIdFromToken))
{
if (DontFailOnMissingTid())
if (AppContextSwitches.DontFailOnMissingTid)
return true;

throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidIssuerException(LogMessages.IDX40009));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public void CreateClaimsIdentity_ReturnsCaseSensitveClaimsIdentity_ByDefault()
actualClaimsIdentity = handler.CreateClaimsIdentityInternal(jsonWebToken, tokenValidationParameters, Default.Issuer);
Assert.IsType<CaseSensitiveClaimsIdentity>(actualClaimsIdentity);
Assert.NotNull(((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken);

AppContextSwitches.ResetAllSwitches();
}

[Fact]
Expand All @@ -54,7 +56,7 @@ public void CreateClaimsIdentity_ReturnsClaimsIdentity_WithAppContextSwitch()
handler.MapInboundClaims = true;
Assert.IsType<ClaimsIdentity>(handler.CreateClaimsIdentityInternal(jsonWebToken, tokenValidationParameters, Default.Issuer));

AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, false);
AppContextSwitches.ResetAllSwitches();
}

private class DerivedJsonWebTokenHandler : JsonWebTokenHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void Create_FromTokenValidationParameters_ReturnsCorrectClaimsIdentity(bo
Assert.Equal(jsonWebToken, ((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken);
}

AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, false);
AppContextSwitches.ResetAllSwitches();
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public void ValidateIssuerSigningKeyTests(AadSigningKeyIssuerTheoryData theoryDa
}
finally
{
theoryData.TearDownAction?.Invoke();
AppContextSwitches.ResetAllSwitches();
}

TestUtilities.AssertFailIfErrors(context);
Expand Down Expand Up @@ -345,8 +345,7 @@ public static TheoryData<AadSigningKeyIssuerTheoryData> ValidateIssuerSigningKey
SecurityKey = KeyingMaterial.JsonWebKeyP256,
SecurityToken = new JwtSecurityToken(),
OpenIdConnectConfiguration = mockConfiguration,
SetupAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, true),
TearDownAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, false)
SetupAction = () => AppContext.SetSwitch(AppContextSwitches.DoNotFailOnMissingTidSwitch, true),
});

theoryData.Add(new AadSigningKeyIssuerTheoryData
Expand All @@ -356,8 +355,7 @@ public static TheoryData<AadSigningKeyIssuerTheoryData> ValidateIssuerSigningKey
SecurityToken = new JwtSecurityToken(),
OpenIdConnectConfiguration = mockConfiguration,
ExpectedException = ExpectedException.SecurityTokenInvalidIssuerException("IDX40009"),
SetupAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, false),
TearDownAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, isEnabled: false)
SetupAction = () => AppContext.SetSwitch(AppContextSwitches.DoNotFailOnMissingTidSwitch, false),
});

theoryData.Add(new AadSigningKeyIssuerTheoryData
Expand All @@ -366,8 +364,7 @@ public static TheoryData<AadSigningKeyIssuerTheoryData> ValidateIssuerSigningKey
SecurityKey = KeyingMaterial.JsonWebKeyP256,
SecurityToken = new JwtSecurityToken(),
OpenIdConnectConfiguration = mockConfiguration,
SetupAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, true),
TearDownAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, false)
SetupAction = () => AppContext.SetSwitch(AppContextSwitches.DoNotFailOnMissingTidSwitch, true),
});

theoryData.Add(new AadSigningKeyIssuerTheoryData
Expand All @@ -377,8 +374,7 @@ public static TheoryData<AadSigningKeyIssuerTheoryData> ValidateIssuerSigningKey
SecurityToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor(Default.SymmetricSigningCredentials, [issClaim]))),
OpenIdConnectConfiguration = mockConfiguration,
ExpectedException = ExpectedException.SecurityTokenInvalidIssuerException("IDX40009"),
SetupAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, false),
TearDownAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, isEnabled: false)
SetupAction = () => AppContext.SetSwitch(AppContextSwitches.DoNotFailOnMissingTidSwitch, false),
});

theoryData.Add(new AadSigningKeyIssuerTheoryData
Expand All @@ -387,8 +383,7 @@ public static TheoryData<AadSigningKeyIssuerTheoryData> ValidateIssuerSigningKey
SecurityKey = KeyingMaterial.JsonWebKeyP256,
SecurityToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor(Default.SymmetricSigningCredentials, [issClaim]))),
OpenIdConnectConfiguration = mockConfiguration,
SetupAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, true),
TearDownAction = () => AppContext.SetSwitch(AadTokenValidationParametersExtension.DontFailOnMissingTidSwitch, false)
SetupAction = () => AppContext.SetSwitch(AppContextSwitches.DoNotFailOnMissingTidSwitch, true),
});

theoryData.Add(new AadSigningKeyIssuerTheoryData
Expand Down Expand Up @@ -454,8 +449,6 @@ public class AadSigningKeyIssuerTheoryData : TheoryDataBase
public bool SetDelegateWithoutConfig { get; set; } = false;

public Action SetupAction { get; set; }

public Action TearDownAction { get; set; }
}
}
}
Expand Down

0 comments on commit 7ef3263

Please sign in to comment.