diff --git a/Fhi.HelseId/src/Fhi.HelseIdSelvbetjening.CLI/Commands/Extensions/CommandHandlerExtensions.cs b/Fhi.HelseId/src/Fhi.HelseIdSelvbetjening.CLI/Commands/Extensions/CommandHandlerExtensions.cs index 508b35a..5439bf0 100644 --- a/Fhi.HelseId/src/Fhi.HelseIdSelvbetjening.CLI/Commands/Extensions/CommandHandlerExtensions.cs +++ b/Fhi.HelseId/src/Fhi.HelseIdSelvbetjening.CLI/Commands/Extensions/CommandHandlerExtensions.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using Fhi.HelseIdSelvbetjening.CLI.Services; using Microsoft.Extensions.Logging; @@ -25,7 +26,7 @@ public static string ResolveKeyValuePathOrString( if (!string.IsNullOrWhiteSpace(directValue)) { logger.LogInformation("{keyLabel} provided directly.", keyLabel); - return directValue; + return UnescapeJson(directValue.Trim()); } if (!string.IsNullOrWhiteSpace(filePath)) @@ -37,5 +38,21 @@ public static string ResolveKeyValuePathOrString( logger.LogWarning("{keyLabel} not provided.", keyLabel); return string.Empty; } + + /// + /// Unescapes JSON string escape sequences by deserializing the input as a JSON string value. + /// + /// + private static string UnescapeJson(string input) + { + try + { + return JsonSerializer.Deserialize($"\"{input}\"")!; + } + catch (JsonException) + { + return input; + } + } } } \ No newline at end of file diff --git a/Fhi.HelseId/tests/Fhi.HelseIdSelvbetjening.CLI.Tests/IntegrationTests/ReadClientSecretExpirationTests.cs b/Fhi.HelseId/tests/Fhi.HelseIdSelvbetjening.CLI.Tests/IntegrationTests/ReadClientSecretExpirationTests.cs index 7de7093..de7c6c0 100644 --- a/Fhi.HelseId/tests/Fhi.HelseIdSelvbetjening.CLI.Tests/IntegrationTests/ReadClientSecretExpirationTests.cs +++ b/Fhi.HelseId/tests/Fhi.HelseIdSelvbetjening.CLI.Tests/IntegrationTests/ReadClientSecretExpirationTests.cs @@ -11,10 +11,19 @@ namespace Fhi.HelseIdSelvbetjening.CLI.IntegrationTests { public class ReadClientSecretExpirationTests { + /// + /// Unicode escape sequence for the double quote character ("). + /// The first JWKs from HelseId contained unicode escaped quotes. + /// + private const string UnicodeEscapedQuote = "\\u0022"; + [TestCase("{\n \"kid\": \"test-kid\",\n \"kty\": \"RSA\",\n \"d\": \"test-d-value\",\n \"n\": \"test-n-value\",\n \"e\": \"AQAB\"\n}")] [TestCase("{\"d\":\"test-kid\",\"e\":\"AQAB\",\"kid\":\"test-kid\",\"kty\":\"RSA\",\"n\":\"test-n-value\"}")] [TestCase("{ \"kid\": \"test-kid\", \"kty\": \"RSA\", \"d\": \"test-data\", \"n\": \"test-modulus\", \"e\": \"AQAB\" }")] - // [TestCase(@"{""kid"":""test-with-special-chars-!@#$%^&*()"",""d"":""data-with-quotes-\""and\""-backslashes-\\"",""n"":""modulus"",""e"":""AQAB""}")] + [TestCase(@"{""kid"":""test-kid"",""kty"":""RSA"",""d"":""test-with-special-chars-!@#$%^&*()"",""n"":""test-n-value"",""e"":""AQAB""}")] + [TestCase(@"{""kid"":""test-kid"",""kty"":""RSA"",""d"":""data-with-quotes-\""and\""-backslashes-\\"",""n"":""test-n-value"",""e"":""AQAB""}")] + [TestCase("{\\\"kid\\\":\\\"test-kid\\\",\\\"kty\\\":\\\"RSA\\\",\\\"d\\\":\\\"test-d-value\\\",\\\"n\\\":\\\"test-n-value\\\",\\\"e\\\":\\\"AQAB\\\"}")] + [TestCase("{" + UnicodeEscapedQuote + "kid" + UnicodeEscapedQuote + ":" + UnicodeEscapedQuote + "test-kid" + UnicodeEscapedQuote + "," + UnicodeEscapedQuote + "kty" + UnicodeEscapedQuote + ":" + UnicodeEscapedQuote + "RSA" + UnicodeEscapedQuote + "," + UnicodeEscapedQuote + "d" + UnicodeEscapedQuote + ":" + UnicodeEscapedQuote + "test-d-value" + UnicodeEscapedQuote + "," + UnicodeEscapedQuote + "n" + UnicodeEscapedQuote + ":" + UnicodeEscapedQuote + "test-n-value" + UnicodeEscapedQuote + "," + UnicodeEscapedQuote + "e" + UnicodeEscapedQuote + ":" + UnicodeEscapedQuote + "AQAB" + UnicodeEscapedQuote + "}")] public async Task ReadClientSecretExpiration_ValidDirectJwkArgument_ExitCode0(string jwk) { var fakeLogProvider = new FakeLoggerProvider(); @@ -40,7 +49,7 @@ public async Task ReadClientSecretExpiration_ValidDirectJwkArgument_ExitCode0(st using (Assert.EnterMultipleScope()) { - Assert.That(exitCode, Is.EqualTo(0)); + Assert.That(exitCode, Is.Zero); Assert.That(fakeLogProvider.Collector?.LatestRecord.Message, Does.Contain(((DateTimeOffset)clientSecrets.FirstOrDefault()!.Expiration!).ToUnixTimeSeconds().ToString())); var logs = fakeLogProvider.Collector?.GetSnapshot().Select(x => x.Message).ToList(); Assert.That(logs!, Does.Contain("Kid: test-kid"));