From d7ce42dacc226c74056a6c0883f9b3e2be7828d7 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Tue, 30 Jun 2015 12:08:20 -0700 Subject: [PATCH] Handle null in ticket serializer --- .../Serializer/TicketSerializer.cs | 76 +++++++++++-------- .../Encoder/TicketSerializerTests.cs | 57 ++++++++++++++ 2 files changed, 103 insertions(+), 30 deletions(-) create mode 100644 test/Microsoft.AspNet.Authentication.Test/DataHandler/Encoder/TicketSerializerTests.cs diff --git a/src/Microsoft.AspNet.Authentication/DataHandler/Serializer/TicketSerializer.cs b/src/Microsoft.AspNet.Authentication/DataHandler/Serializer/TicketSerializer.cs index 71c8b58565..327d333e1f 100644 --- a/src/Microsoft.AspNet.Authentication/DataHandler/Serializer/TicketSerializer.cs +++ b/src/Microsoft.AspNet.Authentication/DataHandler/Serializer/TicketSerializer.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Authentication.DataHandler.Serializer { public class TicketSerializer : IDataSerializer { - private const int FormatVersion = 2; + private const int FormatVersion = 3; public virtual byte[] Serialize(AuthenticationTicket model) { @@ -41,21 +41,29 @@ namespace Microsoft.AspNet.Authentication.DataHandler.Serializer writer.Write(FormatVersion); writer.Write(model.AuthenticationScheme); var principal = model.Principal; - writer.Write(principal.Identities.Count()); - foreach (var identity in principal.Identities) + if (principal == null) { - var authenticationType = string.IsNullOrWhiteSpace(identity.AuthenticationType) ? string.Empty : identity.AuthenticationType; - writer.Write(authenticationType); - WriteWithDefault(writer, identity.NameClaimType, DefaultValues.NameClaimType); - WriteWithDefault(writer, identity.RoleClaimType, DefaultValues.RoleClaimType); - writer.Write(identity.Claims.Count()); - foreach (var claim in identity.Claims) + // Use -1 to signal null + writer.Write(-1); + } + else + { + writer.Write(principal.Identities.Count()); + foreach (var identity in principal.Identities) { - WriteWithDefault(writer, claim.Type, identity.NameClaimType); - writer.Write(claim.Value); - WriteWithDefault(writer, claim.ValueType, DefaultValues.StringValueType); - WriteWithDefault(writer, claim.Issuer, DefaultValues.LocalAuthority); - WriteWithDefault(writer, claim.OriginalIssuer, claim.Issuer); + var authenticationType = string.IsNullOrWhiteSpace(identity.AuthenticationType) ? string.Empty : identity.AuthenticationType; + writer.Write(authenticationType); + WriteWithDefault(writer, identity.NameClaimType, DefaultValues.NameClaimType); + WriteWithDefault(writer, identity.RoleClaimType, DefaultValues.RoleClaimType); + writer.Write(identity.Claims.Count()); + foreach (var claim in identity.Claims) + { + WriteWithDefault(writer, claim.Type, identity.NameClaimType); + writer.Write(claim.Value); + WriteWithDefault(writer, claim.ValueType, DefaultValues.StringValueType); + WriteWithDefault(writer, claim.Issuer, DefaultValues.LocalAuthority); + WriteWithDefault(writer, claim.OriginalIssuer, claim.Issuer); + } } } PropertiesSerializer.Write(writer, model.Properties); @@ -69,27 +77,35 @@ namespace Microsoft.AspNet.Authentication.DataHandler.Serializer } string authenticationScheme = reader.ReadString(); int identityCount = reader.ReadInt32(); - var identities = new ClaimsIdentity[identityCount]; - for (int i = 0; i != identityCount; ++i) + ClaimsPrincipal principal = null; + + // Negative values are used to signify null + if (identityCount >= 0) { - string authenticationType = reader.ReadString(); - string nameClaimType = ReadWithDefault(reader, DefaultValues.NameClaimType); - string roleClaimType = ReadWithDefault(reader, DefaultValues.RoleClaimType); - int count = reader.ReadInt32(); - var claims = new Claim[count]; - for (int index = 0; index != count; ++index) + var identities = new ClaimsIdentity[identityCount]; + for (int i = 0; i != identityCount; ++i) { - string type = ReadWithDefault(reader, nameClaimType); - string value = reader.ReadString(); - string valueType = ReadWithDefault(reader, DefaultValues.StringValueType); - string issuer = ReadWithDefault(reader, DefaultValues.LocalAuthority); - string originalIssuer = ReadWithDefault(reader, issuer); - claims[index] = new Claim(type, value, valueType, issuer, originalIssuer); + string authenticationType = reader.ReadString(); + string nameClaimType = ReadWithDefault(reader, DefaultValues.NameClaimType); + string roleClaimType = ReadWithDefault(reader, DefaultValues.RoleClaimType); + int count = reader.ReadInt32(); + var claims = new Claim[count]; + for (int index = 0; index != count; ++index) + { + string type = ReadWithDefault(reader, nameClaimType); + string value = reader.ReadString(); + string valueType = ReadWithDefault(reader, DefaultValues.StringValueType); + string issuer = ReadWithDefault(reader, DefaultValues.LocalAuthority); + string originalIssuer = ReadWithDefault(reader, issuer); + claims[index] = new Claim(type, value, valueType, issuer, originalIssuer); + } + identities[i] = new ClaimsIdentity(claims, authenticationType, nameClaimType, roleClaimType); } - identities[i] = new ClaimsIdentity(claims, authenticationType, nameClaimType, roleClaimType); + principal = new ClaimsPrincipal(identities); } + var properties = PropertiesSerializer.Read(reader); - return new AuthenticationTicket(new ClaimsPrincipal(identities), properties, authenticationScheme); + return new AuthenticationTicket(principal, properties, authenticationScheme); } private static void WriteWithDefault(BinaryWriter writer, string value, string defaultValue) diff --git a/test/Microsoft.AspNet.Authentication.Test/DataHandler/Encoder/TicketSerializerTests.cs b/test/Microsoft.AspNet.Authentication.Test/DataHandler/Encoder/TicketSerializerTests.cs new file mode 100644 index 0000000000..dbdfbb40d1 --- /dev/null +++ b/test/Microsoft.AspNet.Authentication.Test/DataHandler/Encoder/TicketSerializerTests.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNet.Authentication.DataHandler.Serializer; +using Microsoft.AspNet.Http.Authentication; +using Shouldly; +using Xunit; + +namespace Microsoft.AspNet.Authentication.DataHandler.Encoder +{ + public class TicketSerializerTests + { + [Fact] + public void CanRoundTripNullPrincipal() + { + var properties = new AuthenticationProperties(); + properties.RedirectUri = "bye"; + var ticket = new AuthenticationTicket(properties, "Hello"); + + using (var stream = new MemoryStream()) + using (var writer = new BinaryWriter(stream)) + using (var reader = new BinaryReader(stream)) + { + TicketSerializer.Write(writer, ticket); + stream.Position = 0; + var readTicket = TicketSerializer.Read(reader); + readTicket.Principal.ShouldBe(null); + readTicket.Properties.RedirectUri.ShouldBe("bye"); + readTicket.AuthenticationScheme.ShouldBe("Hello"); + } + } + + [Fact] + public void CanRoundTripEmptyPrincipal() + { + var properties = new AuthenticationProperties(); + properties.RedirectUri = "bye"; + var ticket = new AuthenticationTicket(new ClaimsPrincipal(), properties, "Hello"); + + using (var stream = new MemoryStream()) + using (var writer = new BinaryWriter(stream)) + using (var reader = new BinaryReader(stream)) + { + TicketSerializer.Write(writer, ticket); + stream.Position = 0; + var readTicket = TicketSerializer.Read(reader); + readTicket.Principal.Identities.Count().ShouldBe(0); + readTicket.Properties.RedirectUri.ShouldBe("bye"); + readTicket.AuthenticationScheme.ShouldBe("Hello"); + } + } + + } +}