From 40fcbce8e182c11f941b89a601c140578234d05f Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Sat, 29 Aug 2026 16:46:38 +1000 Subject: [PATCH] Always write an object for ClaimsPrincipal An empty ClaimsPrincipal returned without writing any token, which left the writer in Property state after the caller had written the member name. That threw JsonWriterException for a following member, silently emitted null in trailing position, and produced empty output at the root. The object is now always written. WriteMember drops the empty Identities collection, so an empty principal renders as {}. --- ...s.ClaimsPrincipalWithIdentity.verified.txt | 15 +++++++++++ ...imsTests.EmptyClaimsPrincipal.verified.txt | 4 +++ src/Verify.Tests/Serialization/ClaimsTests.cs | 25 +++++++++++++++++++ .../Converters/ClaimsPrincipalConverter.cs | 9 +++---- 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/Verify.Tests/Serialization/ClaimsTests.ClaimsPrincipalWithIdentity.verified.txt create mode 100644 src/Verify.Tests/Serialization/ClaimsTests.EmptyClaimsPrincipal.verified.txt create mode 100644 src/Verify.Tests/Serialization/ClaimsTests.cs diff --git a/src/Verify.Tests/Serialization/ClaimsTests.ClaimsPrincipalWithIdentity.verified.txt b/src/Verify.Tests/Serialization/ClaimsTests.ClaimsPrincipalWithIdentity.verified.txt new file mode 100644 index 0000000000..4ec91e065b --- /dev/null +++ b/src/Verify.Tests/Serialization/ClaimsTests.ClaimsPrincipalWithIdentity.verified.txt @@ -0,0 +1,15 @@ +{ + Principal: { + Identities: [ + { + Claims: [ + { + TheClaimType: TheClaimValue + } + ], + AuthenticationType: TheAuthenticationType + } + ] + }, + Name: TheValue +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/ClaimsTests.EmptyClaimsPrincipal.verified.txt b/src/Verify.Tests/Serialization/ClaimsTests.EmptyClaimsPrincipal.verified.txt new file mode 100644 index 0000000000..2bc3348825 --- /dev/null +++ b/src/Verify.Tests/Serialization/ClaimsTests.EmptyClaimsPrincipal.verified.txt @@ -0,0 +1,4 @@ +{ + Principal: {}, + Name: TheValue +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/ClaimsTests.cs b/src/Verify.Tests/Serialization/ClaimsTests.cs new file mode 100644 index 0000000000..cd68d7f8af --- /dev/null +++ b/src/Verify.Tests/Serialization/ClaimsTests.cs @@ -0,0 +1,25 @@ +public class ClaimsTests +{ + [Fact] + public Task EmptyClaimsPrincipal() => + // An empty principal still writes an object. Writing no token would leave the + // writer mid-property and corrupt every member written after it. + Verify( + new + { + Principal = new ClaimsPrincipal(), + Name = "TheValue" + }); + + [Fact] + public Task ClaimsPrincipalWithIdentity() => + Verify( + new + { + Principal = new ClaimsPrincipal( + new ClaimsIdentity( + [new Claim("TheClaimType", "TheClaimValue")], + "TheAuthenticationType")), + Name = "TheValue" + }); +} diff --git a/src/Verify/Serialization/Converters/ClaimsPrincipalConverter.cs b/src/Verify/Serialization/Converters/ClaimsPrincipalConverter.cs index fa5e9586ec..8d3aafd334 100644 --- a/src/Verify/Serialization/Converters/ClaimsPrincipalConverter.cs +++ b/src/Verify/Serialization/Converters/ClaimsPrincipalConverter.cs @@ -5,11 +5,10 @@ class ClaimsPrincipalConverter : { public override void Write(VerifyJsonWriter writer, ClaimsPrincipal principal) { - if (!principal.Identities.Any()) - { - return; - } - + // The object is always written, even with no identities. Writing no token at all + // leaves the writer in Property state after the caller has written the member + // name, which corrupts every subsequent write. WriteMember drops the empty + // Identities collection, so an empty principal renders as {}. writer.WriteStartObject(); writer.WriteMember(principal, principal.Identities, "Identities"); writer.WriteEndObject();