From 3f504620646bff24e22a41ee636baecb47b6937b Mon Sep 17 00:00:00 2001 From: id4s Date: Tue, 27 Feb 2024 13:26:16 -0800 Subject: [PATCH] Adjust uppercase json serialization tests --- build/common.props | 2 +- buildPack.bat | 2 + buildTestPack.bat | 2 +- .../Json/JsonSerializerPrimitives.cs | 2 +- .../OpenIdConfigData.cs | 7 +- .../OpenIdConnectSerializationTests.cs | 18 +++-- ...l.Protocols.SignedHttpRequest.Tests.csproj | 1 + .../PopKeyResolvingTests.cs | 1 + .../BaseConfigurationComparerTests.cs | 1 + .../Json}/DataSets.cs | 51 ++++++------ .../Json/JsonData.cs | 17 ++-- .../Json/JsonUtilities.cs | 80 ++++++++++++++++++- .../Json/JsonWebKeySetSerializationTests.cs | 13 +-- .../JwtHeaderTests.cs | 5 +- 14 files changed, 144 insertions(+), 58 deletions(-) create mode 100644 buildPack.bat rename test/{Microsoft.IdentityModel.TestUtils => Microsoft.IdentityModel.Tokens.Tests/Json}/DataSets.cs (98%) diff --git a/build/common.props b/build/common.props index 1d7bf34b98..7f22eb0398 100644 --- a/build/common.props +++ b/build/common.props @@ -32,7 +32,7 @@ - 7.4.0 + 7.4.1 preview-$([System.DateTime]::Now.AddYears(-2019).Year)$([System.DateTime]::Now.ToString("MMddHHmmss")) diff --git a/buildPack.bat b/buildPack.bat new file mode 100644 index 0000000000..7e782b647f --- /dev/null +++ b/buildPack.bat @@ -0,0 +1,2 @@ +dotnet build /r Product.proj +dotnet pack --no-restore -o artifacts --no-build Product.proj diff --git a/buildTestPack.bat b/buildTestPack.bat index 47e4eb48c4..40e59fda52 100644 --- a/buildTestPack.bat +++ b/buildTestPack.bat @@ -1,3 +1,3 @@ dotnet build /r Product.proj dotnet test --no-restore --no-build Product.proj -dotnet pack --no-restore --no-build Product.proj +dotnet pack --no-restore -o artifacts --no-build Product.proj diff --git a/src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs b/src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs index 98b3e08b19..cd99a503ca 100644 --- a/src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs +++ b/src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs @@ -635,7 +635,7 @@ internal static string ReadString(ref Utf8JsonReader reader, string propertyName if (!IsReaderAtTokenType(ref reader, JsonTokenType.String, false)) throw LogHelper.LogExceptionMessage( - CreateJsonReaderExceptionInvalidType(ref reader, "JsonTokenType.StartArray", className, propertyName)); + CreateJsonReaderExceptionInvalidType(ref reader, "JsonTokenType.String", className, propertyName)); string retval = reader.GetString(); diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs index 10fca44a9e..f887eccadd 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs @@ -172,7 +172,7 @@ public static OpenIdConnectConfiguration FullyPopulatedWithKeys #endregion #region GOOGLE 2/2/2024 https://accounts.google.com/.well-known/openid-configuration - public static string AccountsGoogleCom => + public static string AccountsGoogleComJson => $$""" { "issuer": "https://accounts.google.com", @@ -225,7 +225,7 @@ public static OpenIdConnectConfiguration AccountsGoogleComConfig #endregion #region AADCommonV1 2/2/2024 https://login.microsoftonline.com/common/.well-known/openid-configuration - public static string AADCommonV1 => + public static string AADCommonV1Json => """ { "token_endpoint": "https://login.microsoftonline.com/common/oauth2/token", @@ -294,7 +294,7 @@ public static OpenIdConnectConfiguration AADCommonV1Config #endregion #region AADCommonV2 2/2/2024 https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration - public static string AADCommonV2 => + public static string AADCommonV2Json => """ { "token_endpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/token", @@ -322,6 +322,7 @@ public static OpenIdConnectConfiguration AADCommonV1Config "rbac_url": "https://pas.windows.net" } """; + public static OpenIdConnectConfiguration AADCommonV2Config { get diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectSerializationTests.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectSerializationTests.cs index 63f6a3312b..9d28137c02 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectSerializationTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectSerializationTests.cs @@ -41,22 +41,24 @@ public static TheoryData DesrializeTheoryData { TheoryData theoryData = new TheoryData(); - theoryData.Add(new OpenIdConnectTheoryData("AADCommonV1Config") + // the reason to replace AdditionalData with upper case is because the test deserializes uppercase and lowercase. + // we wanted to leave the data sets in original form from discovery to be used in other tests. + theoryData.Add(new OpenIdConnectTheoryData("AADCommonV1") { - CompareTo = OpenIdConfigData.AADCommonV1Config, - Json = OpenIdConfigData.AADCommonV1 + CompareTo = JsonUtilities.SetAdditionalDataKeysToUpperCase(OpenIdConfigData.AADCommonV1Config), + Json = JsonUtilities.SetAdditionalDataKeysToUpperCase(OpenIdConfigData.AADCommonV1Json, OpenIdConfigData.AADCommonV1Config) }); - theoryData.Add(new OpenIdConnectTheoryData("AADCommonV2Config") + theoryData.Add(new OpenIdConnectTheoryData("AADCommonV2") { - CompareTo = OpenIdConfigData.AADCommonV2Config, - Json = OpenIdConfigData.AADCommonV2 + CompareTo = JsonUtilities.SetAdditionalDataKeysToUpperCase(OpenIdConfigData.AADCommonV2Config), + Json = JsonUtilities.SetAdditionalDataKeysToUpperCase(OpenIdConfigData.AADCommonV2Json, OpenIdConfigData.AADCommonV2Config) }); theoryData.Add(new OpenIdConnectTheoryData("AccountsGoogleCom") { - CompareTo = OpenIdConfigData.AccountsGoogleComConfig, - Json = OpenIdConfigData.AccountsGoogleCom + CompareTo = JsonUtilities.SetAdditionalDataKeysToUpperCase(OpenIdConfigData.AccountsGoogleComConfig), + Json = JsonUtilities.SetAdditionalDataKeysToUpperCase(OpenIdConfigData.AccountsGoogleComJson, OpenIdConfigData.AccountsGoogleComConfig) }); theoryData.Add(new OpenIdConnectTheoryData("FrontChannelFalse") diff --git a/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests.csproj b/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests.csproj index e64fada49d..b752b4c1d3 100644 --- a/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests.csproj +++ b/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests.csproj @@ -16,6 +16,7 @@ + diff --git a/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/PopKeyResolvingTests.cs b/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/PopKeyResolvingTests.cs index 8b3e1549aa..f5f446358b 100644 --- a/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/PopKeyResolvingTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.SignedHttpRequest.Tests/PopKeyResolvingTests.cs @@ -8,6 +8,7 @@ using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.TestUtils; using Microsoft.IdentityModel.Tokens; +using Microsoft.IdentityModel.Tokens.Json.Tests; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Xunit; diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/BaseConfigurationComparerTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/BaseConfigurationComparerTests.cs index d909a872ec..5139df5dae 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/BaseConfigurationComparerTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/BaseConfigurationComparerTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens.Json.Tests; using Xunit; namespace Microsoft.IdentityModel.Tokens.Tests diff --git a/test/Microsoft.IdentityModel.TestUtils/DataSets.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Json/DataSets.cs similarity index 98% rename from test/Microsoft.IdentityModel.TestUtils/DataSets.cs rename to test/Microsoft.IdentityModel.Tokens.Tests/Json/DataSets.cs index 2b4863ffc8..54a3ad905c 100644 --- a/test/Microsoft.IdentityModel.TestUtils/DataSets.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Json/DataSets.cs @@ -2,12 +2,11 @@ // Licensed under the MIT License. using System.Collections.Generic; -using Microsoft.IdentityModel.Tokens; /// /// Data sets for testing /// -namespace Microsoft.IdentityModel.TestUtils +namespace Microsoft.IdentityModel.Tokens.Json.Tests { public class DataSets { @@ -360,7 +359,7 @@ public static JsonWebKey JsonWebKeyBadX509Data public static string JsonWebKeySetUseNoKtyString = @"{ ""keys"":[" + JsonWebKeyNoKtyString + "]}"; #region GOOGLE 2/2/2024 https://www.googleapis.com/oauth2/v3/certs - public static string AccountsGoogle = + public static string AccountsGoogleJson = """ { "keys": [ @@ -430,7 +429,7 @@ public static JsonWebKeySet AccountsGoogleKeySet #endregion #region AADCommonV1 2/2/2024 https://login.microsoftonline.com/common/discovery/keys - public static string AADCommonKeySetString_V1 = + public static string AADCommonV1KeySetJson = """ { "keys": [ @@ -471,7 +470,7 @@ public static JsonWebKeySet AccountsGoogleKeySet } """; - public static JsonWebKey AADCommonKey1_V1 + public static JsonWebKey AADCommonV1Key1 { get { @@ -489,7 +488,7 @@ public static JsonWebKey AADCommonKey1_V1 } } - public static JsonWebKey AADCommonKey2_V1 + public static JsonWebKey AADCommonV1Key2 { get { @@ -507,7 +506,7 @@ public static JsonWebKey AADCommonKey2_V1 } } - public static JsonWebKey AADCommonKey3_V1 + public static JsonWebKey AADCommonV1Key3 { get { @@ -525,7 +524,7 @@ public static JsonWebKey AADCommonKey3_V1 } } - public static JsonWebKeySet AADCommonKeySet_V1 + public static JsonWebKeySet AADCommonV1KeySet { get { @@ -533,21 +532,21 @@ public static JsonWebKeySet AADCommonKeySet_V1 { Keys = new List { - AADCommonKey1_V1, - AADCommonKey2_V1, - AADCommonKey3_V1 + AADCommonV1Key1, + AADCommonV1Key2, + AADCommonV1Key3 } }; } } - #endregion #region AADCommonV2 2/2/2024 https://login.microsoftonline.com/common/discovery/v2.0/keys - public static string AADCommonKeySetString_V2 = + public static string AADCommonV2KeySetJson = """ - { - "keys": [ + { + "keys": + [ { "kty": "RSA", "use": "sig", @@ -612,7 +611,7 @@ public static JsonWebKeySet AADCommonKeySet_V1 } """; - public static JsonWebKey AADCommonKey1_V2 + public static JsonWebKey AADCommonV2Key1 { get { @@ -631,7 +630,7 @@ public static JsonWebKey AADCommonKey1_V2 } } - public static JsonWebKey AADCommonKey2_V2 + public static JsonWebKey AADCommonV2Key2 { get { @@ -650,7 +649,7 @@ public static JsonWebKey AADCommonKey2_V2 } } - public static JsonWebKey AADCommonKey3_V2 + public static JsonWebKey AADCommonV2Key3 { get { @@ -669,7 +668,7 @@ public static JsonWebKey AADCommonKey3_V2 } } - public static JsonWebKey AADCommonKey4_V2 + public static JsonWebKey AADCommonV2Key4 { get { @@ -688,7 +687,7 @@ public static JsonWebKey AADCommonKey4_V2 } } - public static JsonWebKey AADCommonKey5_V2 + public static JsonWebKey AADCommonV2Key5 { get { @@ -707,7 +706,7 @@ public static JsonWebKey AADCommonKey5_V2 } } - public static JsonWebKeySet AADCommonKeySet_V2 + public static JsonWebKeySet AADCommonV2KeySet { get { @@ -715,11 +714,11 @@ public static JsonWebKeySet AADCommonKeySet_V2 { Keys = new List { - AADCommonKey1_V2, - AADCommonKey2_V2, - AADCommonKey3_V2, - AADCommonKey4_V2, - AADCommonKey5_V2 + AADCommonV2Key1, + AADCommonV2Key2, + AADCommonV2Key3, + AADCommonV2Key4, + AADCommonV2Key5 } }; } diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonData.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonData.cs index 6519ef2f0f..7c2c11767f 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonData.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonData.cs @@ -11,13 +11,14 @@ namespace Microsoft.IdentityModel.Tokens.Json.Tests public static class JsonData { // Create a unique string for each property, to avoid collisions - public static string ArrayProperty = Guid.NewGuid().ToString(); - public static string ObjectProperty = Guid.NewGuid().ToString(); - public static string FalseProperty = Guid.NewGuid().ToString(); - public static string TrueProperty = Guid.NewGuid().ToString(); - public static string StringProperty = Guid.NewGuid().ToString(); - public static string StringValue = Guid.NewGuid().ToString(); - public static string NullProperty = Guid.NewGuid().ToString(); + // Moved these to UpperInvariant so test that perform uppercase to lowercase will work. + public static string ArrayProperty = Guid.NewGuid().ToString().ToUpperInvariant(); + public static string ObjectProperty = Guid.NewGuid().ToString().ToUpperInvariant(); + public static string FalseProperty = Guid.NewGuid().ToString().ToUpperInvariant(); + public static string TrueProperty = Guid.NewGuid().ToString().ToUpperInvariant(); + public static string StringProperty = Guid.NewGuid().ToString().ToUpperInvariant(); + public static string StringValue = Guid.NewGuid().ToString().ToUpperInvariant(); + public static string NullProperty = Guid.NewGuid().ToString().ToUpperInvariant(); // Json strings are name:value (claim) pairs inside an object // The naming here is: @@ -47,7 +48,7 @@ public static class JsonData public static string ObjectValue = $$""" - {"object":["ObjectValue1","ObjectValue2"]} + {"OBJECT":["ObjectValue1","ObjectValue2"]} """; public static string ObjectClaim = diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonUtilities.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonUtilities.cs index 95026a58b8..dfbc058216 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonUtilities.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonUtilities.cs @@ -6,6 +6,7 @@ using System.IO; using System.Text; using System.Text.Json; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Newtonsoft.Json.Linq; namespace Microsoft.IdentityModel.Tokens.Json.Tests @@ -212,7 +213,7 @@ public static string SetPropertiesToUpperCase(string json) string propertyName = reader.GetString(); if (propertyName != null) { - json = json.Replace(propertyName + ":", propertyName.ToUpperInvariant() + ":"); + json = json.Replace("\"" + propertyName + "\":", "\"" + propertyName.ToUpperInvariant() + "\":"); } } } @@ -220,5 +221,82 @@ public static string SetPropertiesToUpperCase(string json) return json; } + /// + /// json is used in a test to create the OpenIdConnectConfiguration, all values found in the json that match keys in AdditionalData are set to upper case. + /// + /// + /// + /// + public static string SetAdditionalDataKeysToUpperCase(string json, OpenIdConnectConfiguration configuration) + { + foreach (string key in configuration.AdditionalData.Keys) + json = json.Replace("\"" + key + "\":", "\"" + key.ToUpperInvariant() + "\":"); + + return json; + } + + public static OpenIdConnectConfiguration SetAdditionalDataKeysToUpperCase(OpenIdConnectConfiguration configuration) + { + SetAdditionalDataKeysToUpperCase(configuration.AdditionalData); + return configuration; + } + + public static JsonWebKeySet SetAdditionalDataKeysToUpperCase(JsonWebKeySet jsonWebKeySet) + { + SetAdditionalDataKeysToUpperCase(jsonWebKeySet.AdditionalData); + foreach (JsonWebKey jsonWebKey in jsonWebKeySet.Keys) + SetAdditionalDataKeysToUpperCase(jsonWebKey); + + return jsonWebKeySet; + } + + public static JsonWebKey SetAdditionalDataKeysToUpperCase(JsonWebKey jsonWebKey) + { + SetAdditionalDataKeysToUpperCase(jsonWebKey.AdditionalData); + return jsonWebKey; + } + + /// + /// json is used to create the JsonWebKeySet, all values found in the json that match keys in AdditionalData are set to upper case. + /// + /// + /// + /// + public static string SetAdditionalDataKeysToUpperCase(string json, JsonWebKeySet jsonWebKeySet) + { + foreach (string key in jsonWebKeySet.AdditionalData.Keys) + json = json.Replace("\"" + key + "\":", "\"" + key.ToUpperInvariant() + "\":"); + + foreach (JsonWebKey jsonWebKey in jsonWebKeySet.Keys) + json = SetAdditionalDataKeysToUpperCase(json, jsonWebKey); + + return json; + } + + /// + /// json is used to create the JsonWebKey, all values found in the json that match keys in AdditionalData are set to upper case. + /// + /// + /// + /// + public static string SetAdditionalDataKeysToUpperCase(string json, JsonWebKey jsonWebKey) + { + foreach (string key in jsonWebKey.AdditionalData.Keys) + json = json.Replace("\"" + key + "\":", "\"" + key.ToUpperInvariant() + "\":"); + + return json; + } + + public static void SetAdditionalDataKeysToUpperCase(IDictionary additionalData) + { + List keys = [.. additionalData.Keys]; + + for (int i = 0; i < keys.Count; i++) + { + string key = keys[i]; + additionalData[key.ToUpperInvariant()] = additionalData[key]; + additionalData.Remove(key); + } + } } } diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonWebKeySetSerializationTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonWebKeySetSerializationTests.cs index 5f12b18abe..b008b0cf98 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonWebKeySetSerializationTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Json/JsonWebKeySetSerializationTests.cs @@ -119,19 +119,22 @@ public static TheoryData JsonWebKeySetTheoryData theoryData.Add(new JsonWebKeySetTheoryData("AADCommonV1") { - Json = DataSets.AADCommonKeySetString_V1, - JsonWebKeySet = DataSets.AADCommonKeySet_V1 + Json = DataSets.AADCommonV1KeySetJson, + JsonWebKeySet = DataSets.AADCommonV1KeySet }); + // the reason to replace "issuer" with "ISSUER" is because the test deserializes uppercase and lowercase. + // since "issuer" is not a property of JsonWebKeySet the value ends up in the AdditionalData dictionary, which is case sensitive. + // we wanted to leave the data sets as they were obtained from metadata so they can be used in other tests. theoryData.Add(new JsonWebKeySetTheoryData("AADCommonV2") { - Json = DataSets.AADCommonKeySetString_V2, - JsonWebKeySet = DataSets.AADCommonKeySet_V2 + Json = JsonUtilities.SetAdditionalDataKeysToUpperCase(DataSets.AADCommonV2KeySetJson, DataSets.AADCommonV2KeySet), + JsonWebKeySet = JsonUtilities.SetAdditionalDataKeysToUpperCase(DataSets.AADCommonV2KeySet) }); theoryData.Add(new JsonWebKeySetTheoryData("AccountsGoogleCom") { - Json = DataSets.AccountsGoogle, + Json = DataSets.AccountsGoogleJson, JsonWebKeySet = DataSets.AccountsGoogleKeySet }); diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtHeaderTests.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtHeaderTests.cs index 9fff93db1a..c9109ad326 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtHeaderTests.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtHeaderTests.cs @@ -8,10 +8,9 @@ using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.TestUtils; using Microsoft.IdentityModel.Tokens; +using Microsoft.IdentityModel.Tokens.Json.Tests; using Xunit; -#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant - namespace System.IdentityModel.Tokens.Jwt.Tests { /// @@ -248,5 +247,3 @@ public class JwtHeaderTheoryData : TheoryDataBase public SigningCredentials SigningCredentials { get; set; } } } - -#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant