Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ internal static byte[] WriteJweHeader(
// is treated as opt-in. When the library is at the point where it is able to make breaking changes
// (such as the next major version update) we should consider whether or not this app-compat switch
// needs to be maintained.
if (AppContext.TryGetSwitch(AppCompatSwitches.UseRfcDefinitionOfEpkAndKid, out bool isEnabled) && isEnabled)
if (AppContextSwitches.UseRfcDefinitionOfEpkAndKid)
{
if (encryptingCredentials.KeyExchangePublicKey.KeyId != null)
writer.WriteString(JwtHeaderUtf8Bytes.Kid, encryptingCredentials.KeyExchangePublicKey.KeyId);
Expand Down Expand Up @@ -1382,7 +1382,7 @@ internal IEnumerable<SecurityKey> GetContentEncryptionKeys(JsonWebToken jwtToken
// is treated as opt-in. When the library is at the point where it is able to make breaking changes
// (such as the next major version update) we should consider whether or not this app-compat switch
// needs to be maintained.
if (AppContext.TryGetSwitch(AppCompatSwitches.UseRfcDefinitionOfEpkAndKid, out bool isEnabled) && isEnabled)
if (AppContextSwitches.UseRfcDefinitionOfEpkAndKid)
{
// on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Epk, out string epk);
Expand Down
8 changes: 1 addition & 7 deletions src/Microsoft.IdentityModel.Tokens/AppCompatSwitches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ namespace Microsoft.IdentityModel.Tokens;
/// Identifiers used for switching between different app compat behaviors within the Microsoft.IdentityModel libraries.
/// </summary>
/// <remarks>
/// The Microsoft.IdentityModel libraries use <see cref="System.AppContext" /> to turn on or off certain API behavioral
/// changes that might have an effect on application compatibility. This class defines the set of switches that are
/// available to modify library behavior. Application compatibility is favored as the default - so if your application
/// needs to rely on the new behavior, you will need to enable the switch manually. Setting a switch's value can be
/// done programmatically through the <see cref="System.AppContext.SetSwitch" /> method, or through other means such as
/// setting it through MSBuild, app configuration, or registry settings. These alternate methods are described in the
/// <see cref="System.AppContext.SetSwitch" /> documentation.
/// Use <see cref="AppContextSwitches"/> instead.
/// </remarks>
public static class AppCompatSwitches
{
Expand Down
38 changes: 34 additions & 4 deletions src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,27 @@
namespace Microsoft.IdentityModel.Tokens
{
/// <summary>
/// AppContext switches for Microsoft.IdentityModel.Tokens and referencing packages.
/// Identifiers used for switching between different app compatibility behaviors within the Microsoft.IdentityModel packages.
/// </summary>
/// <remarks>
/// The Microsoft.IdentityModel libraries use <see cref="System.AppContext" /> to turn on or off certain API behavioral
/// changes that might have an effect on application compatibility. This class defines the set of switches that are
/// available to modify library behavior. Application compatibility is favored as the default - so if your application
/// needs to rely on the new behavior, you will need to enable the switch manually. Setting a switch's value can be
/// done programmatically through the <see cref="System.AppContext.SetSwitch" /> method, or through other means such as
/// setting it through MSBuild, app configuration, or registry settings. These alternate methods are described in the
/// <see cref="System.AppContext.SetSwitch" /> documentation.
/// </remarks>
internal static class AppContextSwitches
{
/// <summary>
/// Enables a fallback to the previous behavior of using <see cref="ClaimsIdentity"/> instead of <see cref="CaseSensitiveClaimsIdentity"/> globally.
/// </summary>
internal const string UseClaimsIdentityTypeSwitch = "Microsoft.IdentityModel.Tokens.UseClaimsIdentityType";

private static bool? _useClaimsIdentity;
private static bool? _useClaimsIdentityType;

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

/// <summary>
/// When validating the issuer signing key, specifies whether to fail if the 'tid' claim is missing.
Expand All @@ -39,19 +48,40 @@ internal static class AppContextSwitches

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

/// <summary>
/// Uses <see cref="EncryptingCredentials.KeyExchangePublicKey"/> for the token's `kid` header parameter. When using
/// ECDH-based key wrap algorithms the public key portion of <see cref="EncryptingCredentials.Key" /> is also written
/// to the token's `epk` header parameter.
/// </summary>
/// <remarks>
/// Enabling this switch improves the library's conformance to RFC 7518 with regards to how the header values for
/// `kid` and `epk` are set in ECDH key wrap scenarios. The previous behavior erroneously used key ID of
/// <see cref="EncryptingCredentials.Key"/> as the `kid` parameter, and did not automatically set `epk` as the spec
/// defines. This switch enables the intended behavior where <see cref="EncryptingCredentials.KeyExchangePublicKey"/>
/// is used for `kid` and the public portion of <see cref="EncryptingCredentials.Key"/> is used for `epk`.
/// </remarks>
internal const string UseRfcDefinitionOfEpkAndKidSwitch = "Switch.Microsoft.IdentityModel.UseRfcDefinitionOfEpkAndKid";

private static bool? _useRfcDefinitionOfEpkAndKid;

internal static bool UseRfcDefinitionOfEpkAndKid => _useRfcDefinitionOfEpkAndKid ??= (AppContext.TryGetSwitch(UseRfcDefinitionOfEpkAndKidSwitch, out bool isEnabled) && isEnabled);

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

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

_tryAllStringClaimsAsDateTime = null;
AppContext.SetSwitch(TryAllStringClaimsAsDateTimeSwitch, false);

_useRfcDefinitionOfEpkAndKid = null;
AppContext.SetSwitch(UseRfcDefinitionOfEpkAndKidSwitch, false);
}
}
}
2 changes: 1 addition & 1 deletion src/System.IdentityModel.Tokens.Jwt/JwtHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public JwtHeader(EncryptingCredentials encryptingCredentials, IDictionary<string
// is treated as opt-in. When the library is at the point where it is able to make breaking changes
// (such as the next major version update) we should consider whether or not this app-compat switch
// needs to be maintained.
if (AppContext.TryGetSwitch(AppCompatSwitches.UseRfcDefinitionOfEpkAndKid, out bool isEnabled) && isEnabled)
if (AppContextSwitches.UseRfcDefinitionOfEpkAndKid)
{
if (!string.IsNullOrEmpty(encryptingCredentials.KeyExchangePublicKey.KeyId))
Kid = encryptingCredentials.KeyExchangePublicKey.KeyId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1865,7 +1865,7 @@ internal IEnumerable<SecurityKey> GetContentEncryptionKeys(JwtSecurityToken jwtT
// is treated as opt-in. When the library is at the point where it is able to make breaking changes
// (such as the next major version update) we should consider whether or not this app-compat switch
// needs to be maintained.
if (AppContext.TryGetSwitch(AppCompatSwitches.UseRfcDefinitionOfEpkAndKid, out bool isEnabled) && isEnabled)
if (AppContextSwitches.UseRfcDefinitionOfEpkAndKid)
{
//// on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C
string epk = jwtToken.Header.GetStandardClaim(JwtHeaderParameterNames.Epk);
Expand Down
Loading