diff --git a/Security.sln b/Security.sln
index 157849c911..b9e6ac5672 100644
--- a/Security.sln
+++ b/Security.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26403.7
+VisualStudioVersion = 15.0.26510.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D2B6A51-2F9F-44F5-8131-EA5CAC053652}"
EndProject
@@ -46,10 +46,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authen
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtBearerSample", "samples\JwtBearerSample\JwtBearerSample.csproj", "{D399B84F-591B-4E98-92BA-B0F63E7B6957}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Owin.Security.Interop", "src\Microsoft.Owin.Security.Interop\Microsoft.Owin.Security.Interop.csproj", "{A7922DD8-09F1-43E4-938B-CC523EA08898}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Owin.Security.Interop.Test", "test\Microsoft.Owin.Security.Interop.Test\Microsoft.Owin.Security.Interop.Test.csproj", "{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnect.AzureAdSample", "samples\OpenIdConnect.AzureAdSample\OpenIdConnect.AzureAdSample.csproj", "{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test", "test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj", "{51563775-C659-4907-9BAF-9995BAB87D01}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{86BD08B1-F978-4F58-9982-2A017807F01C}"
+ ProjectSection(SolutionItems) = preProject
+ build\common.props = build\common.props
+ build\dependencies.props = build\dependencies.props
+ build\Key.snk = build\Key.snk
+ build\repo.props = build\repo.props
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -360,6 +372,38 @@ Global
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x64.Build.0 = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.ActiveCfg = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.Build.0 = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x64.Build.0 = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.Build.0 = Debug|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x64.ActiveCfg = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x64.Build.0 = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.ActiveCfg = Release|Any CPU
+ {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.Build.0 = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x64.Build.0 = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.Build.0 = Debug|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x64.ActiveCfg = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x64.Build.0 = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.ActiveCfg = Release|Any CPU
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.Build.0 = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -416,6 +460,8 @@ Global
{1790E052-646F-4529-B90E-6FEA95520D69} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
{2755BFE5-7421-4A31-A644-F817DF5CAA98} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{D399B84F-591B-4E98-92BA-B0F63E7B6957} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+ {A7922DD8-09F1-43E4-938B-CC523EA08898} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+ {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{51563775-C659-4907-9BAF-9995BAB87D01} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
EndGlobalSection
diff --git a/build/common.props b/build/common.props
index 3f55ba5b33..dc4ad9a786 100644
--- a/build/common.props
+++ b/build/common.props
@@ -16,8 +16,8 @@
-
-
+
+
diff --git a/build/dependencies.props b/build/dependencies.props
index 74d501f7cd..f7e538a504 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -1,11 +1,13 @@
2.0.0-*
+ 4.4.0-*
3.13.8
2.1.3
2.1.0-*
10.0.1
- $(BundledNETStandardPackageVersion)
+ 2.0.0-*
+ 3.0.1
15.3.0-*
2.3.0-beta2-*
diff --git a/build/repo.props b/build/repo.props
index 396aed1f53..d4bab3eebd 100644
--- a/build/repo.props
+++ b/build/repo.props
@@ -1,4 +1,5 @@
+
diff --git a/samples/CookieSample/CookieSample.csproj b/samples/CookieSample/CookieSample.csproj
index 27fa4ca17b..d251b844e1 100644
--- a/samples/CookieSample/CookieSample.csproj
+++ b/samples/CookieSample/CookieSample.csproj
@@ -1,9 +1,9 @@
-
+
- netcoreapp2.0
+ net461;netcoreapp2.0
@@ -19,4 +19,8 @@
+
+
+
+
diff --git a/samples/CookieSessionSample/CookieSessionSample.csproj b/samples/CookieSessionSample/CookieSessionSample.csproj
index 2a838df7e4..a2d0490f1a 100644
--- a/samples/CookieSessionSample/CookieSessionSample.csproj
+++ b/samples/CookieSessionSample/CookieSessionSample.csproj
@@ -1,9 +1,9 @@
-
+
- netcoreapp2.0
+ net461;netcoreapp2.0
@@ -19,4 +19,8 @@
+
+
+
+
diff --git a/samples/JwtBearerSample/JwtBearerSample.csproj b/samples/JwtBearerSample/JwtBearerSample.csproj
index 86b04d587c..c2f73fd961 100644
--- a/samples/JwtBearerSample/JwtBearerSample.csproj
+++ b/samples/JwtBearerSample/JwtBearerSample.csproj
@@ -1,9 +1,9 @@
-
+
- netcoreapp2.0
+ net461;netcoreapp2.0
aspnet5-JwtBearerSample-20151210102827
@@ -20,4 +20,8 @@
+
+
+
+
diff --git a/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj b/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj
index 78ba03c2af..7857249087 100644
--- a/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj
+++ b/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj
@@ -3,7 +3,7 @@
- netcoreapp2.0
+ net461;netcoreapp2.0
aspnet5-OpenIdConnectSample-20151210110318
@@ -23,4 +23,8 @@
+
+
+
+
diff --git a/samples/OpenIdConnectSample/OpenIdConnectSample.csproj b/samples/OpenIdConnectSample/OpenIdConnectSample.csproj
index 875762d126..03384f567e 100644
--- a/samples/OpenIdConnectSample/OpenIdConnectSample.csproj
+++ b/samples/OpenIdConnectSample/OpenIdConnectSample.csproj
@@ -3,7 +3,7 @@
- netcoreapp2.0
+ net461;netcoreapp2.0
aspnet5-OpenIdConnectSample-20151210110318
@@ -33,4 +33,8 @@
+
+
+
+
diff --git a/samples/SocialSample/SocialSample.csproj b/samples/SocialSample/SocialSample.csproj
index 723d74de32..999dc91a6f 100644
--- a/samples/SocialSample/SocialSample.csproj
+++ b/samples/SocialSample/SocialSample.csproj
@@ -3,7 +3,7 @@
- netcoreapp2.0
+ net461;netcoreapp2.0
aspnet5-SocialSample-20151210111056
@@ -35,4 +35,8 @@
+
+
+
+
diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj b/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj
index a5728fbabc..41c4ff7905 100644
--- a/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj
@@ -4,7 +4,7 @@
ASP.NET Core middleware that enables an application to use cookie based authentication.
- netcoreapp2.0
+ netstandard2.0
$(DefineConstants);SECURITY
$(NoWarn);CS1591
true
diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj b/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj
index 19ec83413c..e39b31e904 100644
--- a/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj
@@ -4,7 +4,7 @@
ASP.NET Core middleware that enables an application to support Facebook's OAuth 2.0 authentication workflow.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj b/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj
index e403fe4a95..c4f1e7ad8f 100644
--- a/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj
@@ -4,7 +4,7 @@
ASP.NET Core contains middleware to support Google's OpenId and OAuth 2.0 authentication workflows.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj
index c2b99e47db..5b25e00e86 100644
--- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj
@@ -2,7 +2,7 @@
ASP.NET Core middleware that enables an application to receive an OpenID Connect bearer token.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj
index 4d91e0da1e..1a954c850a 100644
--- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj
@@ -4,7 +4,7 @@
ASP.NET Core middleware that enables an application to support the Microsoft Account authentication workflow.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj b/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj
index 8e33372c1f..508c815fe8 100644
--- a/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj
@@ -4,7 +4,7 @@
ASP.NET Core middleware that enables an application to support any standard OAuth 2.0 authentication workflow.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj
index b3829b59dc..0ce2fe34e0 100644
--- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj
@@ -2,7 +2,7 @@
ASP.NET Core middleware that enables an application to support the OpenID Connect authentication workflow.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj b/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj
index 5dd58d680c..b78de6597f 100644
--- a/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj
+++ b/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj
@@ -4,7 +4,7 @@
ASP.NET Core middleware that enables an application to support Twitter's OAuth 1.0 authentication workflow.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
diff --git a/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj b/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj
index 54b560702a..cbdb05b58a 100644
--- a/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj
+++ b/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj
@@ -4,7 +4,7 @@
ASP.NET Core common types used by the various authentication middleware components.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authentication;security
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj b/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj
index b39a7bf3dd..93673ef007 100644
--- a/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj
+++ b/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj
@@ -7,7 +7,7 @@
Commonly used types:
Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute
Microsoft.AspNetCore.Authorization.AuthorizeAttribute
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore;authorization
diff --git a/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj b/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj
index 31ce5b761a..5dc2cd9281 100644
--- a/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj
+++ b/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj
@@ -4,7 +4,7 @@
ASP.NET Core cookie policy classes to control the behavior of cookies.
- netcoreapp2.0
+ netstandard2.0
$(NoWarn);CS1591
true
aspnetcore
diff --git a/src/Microsoft.Owin.Security.Interop/AspNetTicketDataFormat.cs b/src/Microsoft.Owin.Security.Interop/AspNetTicketDataFormat.cs
new file mode 100644
index 0000000000..f1a07c5bf7
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/AspNetTicketDataFormat.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.Owin.Security.DataHandler;
+using Microsoft.Owin.Security.DataHandler.Encoder;
+using Microsoft.Owin.Security.DataProtection;
+
+namespace Microsoft.Owin.Security.Interop
+{
+ public class AspNetTicketDataFormat : SecureDataFormat
+ {
+ public AspNetTicketDataFormat(IDataProtector protector)
+ : base(AspNetTicketSerializer.Default, protector, TextEncodings.Base64Url)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Owin.Security.Interop/AspNetTicketSerializer.cs b/src/Microsoft.Owin.Security.Interop/AspNetTicketSerializer.cs
new file mode 100644
index 0000000000..6a1019fbc8
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/AspNetTicketSerializer.cs
@@ -0,0 +1,220 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.Owin.Security.DataHandler.Serializer;
+
+namespace Microsoft.Owin.Security.Interop
+{
+ // This MUST be kept in sync with Microsoft.AspNetCore.Authentication.DataHandler.TicketSerializer
+ public class AspNetTicketSerializer : IDataSerializer
+ {
+ private const string DefaultStringPlaceholder = "\0";
+ private const int FormatVersion = 5;
+
+ public static AspNetTicketSerializer Default { get; } = new AspNetTicketSerializer();
+
+ public virtual byte[] Serialize(AuthenticationTicket ticket)
+ {
+ using (var memory = new MemoryStream())
+ {
+ using (var writer = new BinaryWriter(memory))
+ {
+ Write(writer, ticket);
+ }
+ return memory.ToArray();
+ }
+ }
+
+ public virtual AuthenticationTicket Deserialize(byte[] data)
+ {
+ using (var memory = new MemoryStream(data))
+ {
+ using (var reader = new BinaryReader(memory))
+ {
+ return Read(reader);
+ }
+ }
+ }
+
+ public virtual void Write(BinaryWriter writer, AuthenticationTicket ticket)
+ {
+ writer.Write(FormatVersion);
+ writer.Write(ticket.Identity.AuthenticationType);
+
+ var identity = ticket.Identity;
+ if (identity == null)
+ {
+ throw new ArgumentNullException("ticket.Identity");
+ }
+
+ // There is always a single identity
+ writer.Write(1);
+ WriteIdentity(writer, identity);
+ PropertiesSerializer.Write(writer, ticket.Properties);
+ }
+
+ protected virtual void WriteIdentity(BinaryWriter writer, ClaimsIdentity identity)
+ {
+ var authenticationType = identity.AuthenticationType ?? string.Empty;
+
+ writer.Write(authenticationType);
+ WriteWithDefault(writer, identity.NameClaimType, ClaimsIdentity.DefaultNameClaimType);
+ WriteWithDefault(writer, identity.RoleClaimType, ClaimsIdentity.DefaultRoleClaimType);
+
+ // Write the number of claims contained in the identity.
+ writer.Write(identity.Claims.Count());
+
+ foreach (var claim in identity.Claims)
+ {
+ WriteClaim(writer, claim);
+ }
+
+ var bootstrap = identity.BootstrapContext as string;
+ if (!string.IsNullOrEmpty(bootstrap))
+ {
+ writer.Write(true);
+ writer.Write(bootstrap);
+ }
+ else
+ {
+ writer.Write(false);
+ }
+
+ if (identity.Actor != null)
+ {
+ writer.Write(true);
+ WriteIdentity(writer, identity.Actor);
+ }
+ else
+ {
+ writer.Write(false);
+ }
+ }
+
+ protected virtual void WriteClaim(BinaryWriter writer, Claim claim)
+ {
+ WriteWithDefault(writer, claim.Type, claim.Subject?.NameClaimType ?? ClaimsIdentity.DefaultNameClaimType);
+ writer.Write(claim.Value);
+ WriteWithDefault(writer, claim.ValueType, ClaimValueTypes.String);
+ WriteWithDefault(writer, claim.Issuer, ClaimsIdentity.DefaultIssuer);
+ WriteWithDefault(writer, claim.OriginalIssuer, claim.Issuer);
+
+ // Write the number of properties contained in the claim.
+ writer.Write(claim.Properties.Count);
+
+ foreach (var property in claim.Properties)
+ {
+ writer.Write(property.Key ?? string.Empty);
+ writer.Write(property.Value ?? string.Empty);
+ }
+ }
+
+ public virtual AuthenticationTicket Read(BinaryReader reader)
+ {
+ if (reader.ReadInt32() != FormatVersion)
+ {
+ return null;
+ }
+
+ var scheme = reader.ReadString();
+
+ // Any identities after the first will be ignored.
+ var count = reader.ReadInt32();
+ if (count < 0)
+ {
+ return null;
+ }
+
+ var identity = ReadIdentity(reader);
+ var properties = PropertiesSerializer.Read(reader);
+
+ return new AuthenticationTicket(identity, properties);
+ }
+
+ protected virtual ClaimsIdentity ReadIdentity(BinaryReader reader)
+ {
+ var authenticationType = reader.ReadString();
+ var nameClaimType = ReadWithDefault(reader, ClaimsIdentity.DefaultNameClaimType);
+ var roleClaimType = ReadWithDefault(reader, ClaimsIdentity.DefaultRoleClaimType);
+
+ // Read the number of claims contained
+ // in the serialized identity.
+ var count = reader.ReadInt32();
+
+ var identity = new ClaimsIdentity(authenticationType, nameClaimType, roleClaimType);
+
+ for (int index = 0; index != count; ++index)
+ {
+ var claim = ReadClaim(reader, identity);
+
+ identity.AddClaim(claim);
+ }
+
+ // Determine whether the identity
+ // has a bootstrap context attached.
+ if (reader.ReadBoolean())
+ {
+ identity.BootstrapContext = reader.ReadString();
+ }
+
+ // Determine whether the identity
+ // has an actor identity attached.
+ if (reader.ReadBoolean())
+ {
+ identity.Actor = ReadIdentity(reader);
+ }
+
+ return identity;
+ }
+
+ protected virtual Claim ReadClaim(BinaryReader reader, ClaimsIdentity identity)
+ {
+ var type = ReadWithDefault(reader, identity.NameClaimType);
+ var value = reader.ReadString();
+ var valueType = ReadWithDefault(reader, ClaimValueTypes.String);
+ var issuer = ReadWithDefault(reader, ClaimsIdentity.DefaultIssuer);
+ var originalIssuer = ReadWithDefault(reader, issuer);
+
+ var claim = new Claim(type, value, valueType, issuer, originalIssuer, identity);
+
+ // Read the number of properties stored in the claim.
+ var count = reader.ReadInt32();
+
+ for (var index = 0; index != count; ++index)
+ {
+ var key = reader.ReadString();
+ var propertyValue = reader.ReadString();
+
+ claim.Properties.Add(key, propertyValue);
+ }
+
+ return claim;
+ }
+
+ private static void WriteWithDefault(BinaryWriter writer, string value, string defaultValue)
+ {
+ if (string.Equals(value, defaultValue, StringComparison.Ordinal))
+ {
+ writer.Write(DefaultStringPlaceholder);
+ }
+ else
+ {
+ writer.Write(value);
+ }
+ }
+
+ private static string ReadWithDefault(BinaryReader reader, string defaultValue)
+ {
+ var value = reader.ReadString();
+ if (string.Equals(value, DefaultStringPlaceholder, StringComparison.Ordinal))
+ {
+ return defaultValue;
+ }
+ return value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs b/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs
new file mode 100644
index 0000000000..b323258d9b
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs
@@ -0,0 +1,281 @@
+// 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;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Microsoft.Owin.Infrastructure;
+
+namespace Microsoft.Owin.Security.Interop
+{
+ // This MUST be kept in sync with Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager
+ ///
+ /// This handles cookies that are limited by per cookie length. It breaks down long cookies for responses, and reassembles them
+ /// from requests.
+ ///
+ public class ChunkingCookieManager : ICookieManager
+ {
+ private const string ChunkKeySuffix = "C";
+ private const string ChunkCountPrefix = "chunks-";
+
+ public ChunkingCookieManager()
+ {
+ // Lowest common denominator. Safari has the lowest known limit (4093), and we leave little extra just in case.
+ // See http://browsercookielimits.x64.me/.
+ // Leave at least 20 in case CookiePolicy tries to add 'secure' and/or 'httponly'.
+ ChunkSize = 4070;
+ ThrowForPartialCookies = true;
+ }
+
+ ///
+ /// The maximum size of cookie to send back to the client. If a cookie exceeds this size it will be broken down into multiple
+ /// cookies. Set this value to null to disable this behavior. The default is 4090 characters, which is supported by all
+ /// common browsers.
+ ///
+ /// Note that browsers may also have limits on the total size of all cookies per domain, and on the number of cookies per domain.
+ ///
+ public int? ChunkSize { get; set; }
+
+ ///
+ /// Throw if not all chunks of a cookie are available on a request for re-assembly.
+ ///
+ public bool ThrowForPartialCookies { get; set; }
+
+ // Parse the "chunks-XX" to determine how many chunks there should be.
+ private static int ParseChunksCount(string value)
+ {
+ if (value != null && value.StartsWith(ChunkCountPrefix, StringComparison.Ordinal))
+ {
+ var chunksCountString = value.Substring(ChunkCountPrefix.Length);
+ int chunksCount;
+ if (int.TryParse(chunksCountString, NumberStyles.None, CultureInfo.InvariantCulture, out chunksCount))
+ {
+ return chunksCount;
+ }
+ }
+ return 0;
+ }
+
+ ///
+ /// Get the reassembled cookie. Non chunked cookies are returned normally.
+ /// Cookies with missing chunks just have their "chunks-XX" header returned.
+ ///
+ ///
+ ///
+ /// The reassembled cookie, if any, or null.
+ public string GetRequestCookie(IOwinContext context, string key)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ if (key == null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ var requestCookies = context.Request.Cookies;
+ var value = requestCookies[key];
+ var chunksCount = ParseChunksCount(value);
+ if (chunksCount > 0)
+ {
+ var chunks = new string[chunksCount];
+ for (var chunkId = 1; chunkId <= chunksCount; chunkId++)
+ {
+ var chunk = requestCookies[key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture)];
+ if (string.IsNullOrEmpty(chunk))
+ {
+ if (ThrowForPartialCookies)
+ {
+ var totalSize = 0;
+ for (int i = 0; i < chunkId - 1; i++)
+ {
+ totalSize += chunks[i].Length;
+ }
+ throw new FormatException(
+ string.Format(CultureInfo.CurrentCulture,
+ "The chunked cookie is incomplete. Only {0} of the expected {1} chunks were found, totaling {2} characters. A client size limit may have been exceeded.",
+ chunkId - 1, chunksCount, totalSize));
+ }
+ // Missing chunk, abort by returning the original cookie value. It may have been a false positive?
+ return value;
+ }
+
+ chunks[chunkId - 1] = chunk;
+ }
+
+ return string.Join(string.Empty, chunks);
+ }
+ return value;
+ }
+
+ ///
+ /// Appends a new response cookie to the Set-Cookie header. If the cookie is larger than the given size limit
+ /// then it will be broken down into multiple cookies as follows:
+ /// Set-Cookie: CookieName=chunks-3; path=/
+ /// Set-Cookie: CookieNameC1=Segment1; path=/
+ /// Set-Cookie: CookieNameC2=Segment2; path=/
+ /// Set-Cookie: CookieNameC3=Segment3; path=/
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ if (key == null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ var domainHasValue = !string.IsNullOrEmpty(options.Domain);
+ var pathHasValue = !string.IsNullOrEmpty(options.Path);
+ var expiresHasValue = options.Expires.HasValue;
+
+ var templateLength = key.Length + "=".Length
+ + (domainHasValue ? "; domain=".Length + options.Domain.Length : 0)
+ + (pathHasValue ? "; path=".Length + options.Path.Length : 0)
+ + (expiresHasValue ? "; expires=ddd, dd-MMM-yyyy HH:mm:ss GMT".Length : 0)
+ + (options.Secure ? "; secure".Length : 0)
+ + (options.HttpOnly ? "; HttpOnly".Length : 0);
+
+ // Normal cookie
+ var responseCookies = context.Response.Cookies;
+ if (!ChunkSize.HasValue || ChunkSize.Value > templateLength + value.Length)
+ {
+ responseCookies.Append(key, value, options);
+ }
+ else if (ChunkSize.Value < templateLength + 10)
+ {
+ // 10 is the minimum data we want to put in an individual cookie, including the cookie chunk identifier "CXX".
+ // No room for data, we can't chunk the options and name
+ throw new InvalidOperationException("The cookie key and options are larger than ChunksSize, leaving no room for data.");
+ }
+ else
+ {
+ // Break the cookie down into multiple cookies.
+ // Key = CookieName, value = "Segment1Segment2Segment2"
+ // Set-Cookie: CookieName=chunks-3; path=/
+ // Set-Cookie: CookieNameC1="Segment1"; path=/
+ // Set-Cookie: CookieNameC2="Segment2"; path=/
+ // Set-Cookie: CookieNameC3="Segment3"; path=/
+ var dataSizePerCookie = ChunkSize.Value - templateLength - 3; // Budget 3 chars for the chunkid.
+ var cookieChunkCount = (int)Math.Ceiling(value.Length * 1.0 / dataSizePerCookie);
+
+ responseCookies.Append(key, ChunkCountPrefix + cookieChunkCount.ToString(CultureInfo.InvariantCulture), options);
+
+ var offset = 0;
+ for (var chunkId = 1; chunkId <= cookieChunkCount; chunkId++)
+ {
+ var remainingLength = value.Length - offset;
+ var length = Math.Min(dataSizePerCookie, remainingLength);
+ var segment = value.Substring(offset, length);
+ offset += length;
+
+ responseCookies.Append(key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture), segment, options);
+ }
+ }
+ }
+
+ ///
+ /// Deletes the cookie with the given key by setting an expired state. If a matching chunked cookie exists on
+ /// the request, delete each chunk.
+ ///
+ ///
+ ///
+ ///
+ public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ if (key == null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ var keys = new List();
+ keys.Add(key + "=");
+
+ var requestCookie = context.Request.Cookies[key];
+ var chunks = ParseChunksCount(requestCookie);
+ if (chunks > 0)
+ {
+ for (int i = 1; i <= chunks + 1; i++)
+ {
+ var subkey = key + ChunkKeySuffix + i.ToString(CultureInfo.InvariantCulture);
+ keys.Add(subkey + "=");
+ }
+ }
+
+ var domainHasValue = !string.IsNullOrEmpty(options.Domain);
+ var pathHasValue = !string.IsNullOrEmpty(options.Path);
+
+ Func rejectPredicate;
+ Func predicate = value => keys.Any(k => value.StartsWith(k, StringComparison.OrdinalIgnoreCase));
+ if (domainHasValue)
+ {
+ rejectPredicate = value => predicate(value) && value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
+ }
+ else if (pathHasValue)
+ {
+ rejectPredicate = value => predicate(value) && value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
+ }
+ else
+ {
+ rejectPredicate = value => predicate(value);
+ }
+
+ var responseHeaders = context.Response.Headers;
+ string[] existingValues;
+ if (responseHeaders.TryGetValue(Constants.Headers.SetCookie, out existingValues) && existingValues != null)
+ {
+ responseHeaders.SetValues(Constants.Headers.SetCookie, existingValues.Where(value => !rejectPredicate(value)).ToArray());
+ }
+
+ AppendResponseCookie(
+ context,
+ key,
+ string.Empty,
+ new CookieOptions()
+ {
+ Path = options.Path,
+ Domain = options.Domain,
+ Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+ });
+
+ for (int i = 1; i <= chunks; i++)
+ {
+ AppendResponseCookie(
+ context,
+ key + "C" + i.ToString(CultureInfo.InvariantCulture),
+ string.Empty,
+ new CookieOptions()
+ {
+ Path = options.Path,
+ Domain = options.Domain,
+ Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+ });
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Owin.Security.Interop/Constants.cs b/src/Microsoft.Owin.Security.Interop/Constants.cs
new file mode 100644
index 0000000000..1e75761b70
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/Constants.cs
@@ -0,0 +1,13 @@
+// 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.
+
+namespace Microsoft.Owin.Security.Interop
+{
+ internal static class Constants
+ {
+ internal static class Headers
+ {
+ internal const string SetCookie = "Set-Cookie";
+ }
+ }
+}
diff --git a/src/Microsoft.Owin.Security.Interop/DataProtectorShim.cs b/src/Microsoft.Owin.Security.Interop/DataProtectorShim.cs
new file mode 100644
index 0000000000..7313588948
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/DataProtectorShim.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNetCore.DataProtection;
+
+namespace Microsoft.Owin.Security.Interop
+{
+ ///
+ /// Converts an to an
+ /// .
+ ///
+ public sealed class DataProtectorShim : Microsoft.Owin.Security.DataProtection.IDataProtector
+ {
+ private readonly IDataProtector _protector;
+
+ public DataProtectorShim(IDataProtector protector)
+ {
+ _protector = protector;
+ }
+
+ public byte[] Protect(byte[] userData)
+ {
+ return _protector.Protect(userData);
+ }
+
+ public byte[] Unprotect(byte[] protectedData)
+ {
+ return _protector.Unprotect(protectedData);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.csproj b/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.csproj
new file mode 100644
index 0000000000..10a8be30f5
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.csproj
@@ -0,0 +1,18 @@
+
+
+
+
+
+ A compatibility layer for sharing authentication tickets between Microsoft.Owin.Security and Microsoft.AspNetCore.Authentication.
+ net461
+ $(NoWarn);CS1591
+ true
+ aspnetcore;katana;owin;security
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs b/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..490fa7cb2a
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs
@@ -0,0 +1,8 @@
+// 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.Runtime.InteropServices;
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a7922dd8-09f1-43e4-938b-cc523ea08898")]
+
diff --git a/src/Microsoft.Owin.Security.Interop/baseline.netframework.json b/src/Microsoft.Owin.Security.Interop/baseline.netframework.json
new file mode 100644
index 0000000000..1fc242ec55
--- /dev/null
+++ b/src/Microsoft.Owin.Security.Interop/baseline.netframework.json
@@ -0,0 +1,373 @@
+{
+ "AssemblyIdentity": "Microsoft.Owin.Security.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+ "Types": [
+ {
+ "Name": "Microsoft.Owin.Security.Interop.AspNetTicketDataFormat",
+ "Visibility": "Public",
+ "Kind": "Class",
+ "BaseType": "Microsoft.Owin.Security.DataHandler.SecureDataFormat",
+ "ImplementedInterfaces": [],
+ "Members": [
+ {
+ "Kind": "Constructor",
+ "Name": ".ctor",
+ "Parameters": [
+ {
+ "Name": "protector",
+ "Type": "Microsoft.Owin.Security.DataProtection.IDataProtector"
+ }
+ ],
+ "Visibility": "Public",
+ "GenericParameter": []
+ }
+ ],
+ "GenericParameters": []
+ },
+ {
+ "Name": "Microsoft.Owin.Security.Interop.AspNetTicketSerializer",
+ "Visibility": "Public",
+ "Kind": "Class",
+ "ImplementedInterfaces": [
+ "Microsoft.Owin.Security.DataHandler.Serializer.IDataSerializer"
+ ],
+ "Members": [
+ {
+ "Kind": "Method",
+ "Name": "get_Default",
+ "Parameters": [],
+ "ReturnType": "Microsoft.Owin.Security.Interop.AspNetTicketSerializer",
+ "Static": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Serialize",
+ "Parameters": [
+ {
+ "Name": "ticket",
+ "Type": "Microsoft.Owin.Security.AuthenticationTicket"
+ }
+ ],
+ "ReturnType": "System.Byte[]",
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Security.DataHandler.Serializer.IDataSerializer",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Deserialize",
+ "Parameters": [
+ {
+ "Name": "data",
+ "Type": "System.Byte[]"
+ }
+ ],
+ "ReturnType": "Microsoft.Owin.Security.AuthenticationTicket",
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Security.DataHandler.Serializer.IDataSerializer",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Write",
+ "Parameters": [
+ {
+ "Name": "writer",
+ "Type": "System.IO.BinaryWriter"
+ },
+ {
+ "Name": "ticket",
+ "Type": "Microsoft.Owin.Security.AuthenticationTicket"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Virtual": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "WriteIdentity",
+ "Parameters": [
+ {
+ "Name": "writer",
+ "Type": "System.IO.BinaryWriter"
+ },
+ {
+ "Name": "identity",
+ "Type": "System.Security.Claims.ClaimsIdentity"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Virtual": true,
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "WriteClaim",
+ "Parameters": [
+ {
+ "Name": "writer",
+ "Type": "System.IO.BinaryWriter"
+ },
+ {
+ "Name": "claim",
+ "Type": "System.Security.Claims.Claim"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Virtual": true,
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Read",
+ "Parameters": [
+ {
+ "Name": "reader",
+ "Type": "System.IO.BinaryReader"
+ }
+ ],
+ "ReturnType": "Microsoft.Owin.Security.AuthenticationTicket",
+ "Virtual": true,
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "ReadIdentity",
+ "Parameters": [
+ {
+ "Name": "reader",
+ "Type": "System.IO.BinaryReader"
+ }
+ ],
+ "ReturnType": "System.Security.Claims.ClaimsIdentity",
+ "Virtual": true,
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "ReadClaim",
+ "Parameters": [
+ {
+ "Name": "reader",
+ "Type": "System.IO.BinaryReader"
+ },
+ {
+ "Name": "identity",
+ "Type": "System.Security.Claims.ClaimsIdentity"
+ }
+ ],
+ "ReturnType": "System.Security.Claims.Claim",
+ "Virtual": true,
+ "Visibility": "Protected",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Constructor",
+ "Name": ".ctor",
+ "Parameters": [],
+ "Visibility": "Public",
+ "GenericParameter": []
+ }
+ ],
+ "GenericParameters": []
+ },
+ {
+ "Name": "Microsoft.Owin.Security.Interop.ChunkingCookieManager",
+ "Visibility": "Public",
+ "Kind": "Class",
+ "ImplementedInterfaces": [
+ "Microsoft.Owin.Infrastructure.ICookieManager"
+ ],
+ "Members": [
+ {
+ "Kind": "Method",
+ "Name": "get_ChunkSize",
+ "Parameters": [],
+ "ReturnType": "System.Nullable",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "set_ChunkSize",
+ "Parameters": [
+ {
+ "Name": "value",
+ "Type": "System.Nullable"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "get_ThrowForPartialCookies",
+ "Parameters": [],
+ "ReturnType": "System.Boolean",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "set_ThrowForPartialCookies",
+ "Parameters": [
+ {
+ "Name": "value",
+ "Type": "System.Boolean"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "GetRequestCookie",
+ "Parameters": [
+ {
+ "Name": "context",
+ "Type": "Microsoft.Owin.IOwinContext"
+ },
+ {
+ "Name": "key",
+ "Type": "System.String"
+ }
+ ],
+ "ReturnType": "System.String",
+ "Sealed": true,
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Infrastructure.ICookieManager",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "AppendResponseCookie",
+ "Parameters": [
+ {
+ "Name": "context",
+ "Type": "Microsoft.Owin.IOwinContext"
+ },
+ {
+ "Name": "key",
+ "Type": "System.String"
+ },
+ {
+ "Name": "value",
+ "Type": "System.String"
+ },
+ {
+ "Name": "options",
+ "Type": "Microsoft.Owin.CookieOptions"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Sealed": true,
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Infrastructure.ICookieManager",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "DeleteCookie",
+ "Parameters": [
+ {
+ "Name": "context",
+ "Type": "Microsoft.Owin.IOwinContext"
+ },
+ {
+ "Name": "key",
+ "Type": "System.String"
+ },
+ {
+ "Name": "options",
+ "Type": "Microsoft.Owin.CookieOptions"
+ }
+ ],
+ "ReturnType": "System.Void",
+ "Sealed": true,
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Infrastructure.ICookieManager",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Constructor",
+ "Name": ".ctor",
+ "Parameters": [],
+ "Visibility": "Public",
+ "GenericParameter": []
+ }
+ ],
+ "GenericParameters": []
+ },
+ {
+ "Name": "Microsoft.Owin.Security.Interop.DataProtectorShim",
+ "Visibility": "Public",
+ "Kind": "Class",
+ "Sealed": true,
+ "ImplementedInterfaces": [
+ "Microsoft.Owin.Security.DataProtection.IDataProtector"
+ ],
+ "Members": [
+ {
+ "Kind": "Method",
+ "Name": "Protect",
+ "Parameters": [
+ {
+ "Name": "userData",
+ "Type": "System.Byte[]"
+ }
+ ],
+ "ReturnType": "System.Byte[]",
+ "Sealed": true,
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Security.DataProtection.IDataProtector",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Method",
+ "Name": "Unprotect",
+ "Parameters": [
+ {
+ "Name": "protectedData",
+ "Type": "System.Byte[]"
+ }
+ ],
+ "ReturnType": "System.Byte[]",
+ "Sealed": true,
+ "Virtual": true,
+ "ImplementedInterface": "Microsoft.Owin.Security.DataProtection.IDataProtector",
+ "Visibility": "Public",
+ "GenericParameter": []
+ },
+ {
+ "Kind": "Constructor",
+ "Name": ".ctor",
+ "Parameters": [
+ {
+ "Name": "protector",
+ "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector"
+ }
+ ],
+ "Visibility": "Public",
+ "GenericParameter": []
+ }
+ ],
+ "GenericParameters": []
+ }
+ ],
+ "SourceFilters": []
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj b/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj
index 98d727fde5..c44069f437 100644
--- a/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj
+++ b/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj
@@ -3,9 +3,8 @@
- netcoreapp2.0
- true
- true
+ netcoreapp2.0;net461
+ netcoreapp2.0
@@ -24,6 +23,7 @@
+
diff --git a/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj b/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj
index a9ba71a797..48b134740a 100644
--- a/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj
+++ b/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj
@@ -3,7 +3,8 @@
- netcoreapp2.0
+ netcoreapp2.0;net461
+ netcoreapp2.0
diff --git a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj
index 7908e98fcb..b578f5dcfa 100644
--- a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj
+++ b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj
@@ -3,7 +3,8 @@
- netcoreapp2.0
+ netcoreapp2.0;net461
+ netcoreapp2.0
diff --git a/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj b/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj
index b7b2c6afe0..f513de4b35 100644
--- a/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj
+++ b/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj
@@ -2,9 +2,8 @@
- netcoreapp2.0
- true
- true
+ netcoreapp2.0;net461
+ netcoreapp2.0
diff --git a/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs b/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs
new file mode 100644
index 0000000000..ae5e6f0183
--- /dev/null
+++ b/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs
@@ -0,0 +1,332 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Net.Http.Headers;
+using Microsoft.Owin.Security.Cookies;
+using Microsoft.Owin.Testing;
+using Owin;
+using Xunit;
+
+namespace Microsoft.Owin.Security.Interop
+{
+ public class CookiesInteropTests
+ {
+ [Fact]
+ public async Task AspNetCoreWithInteropCookieContainsIdentity()
+ {
+ var identity = new ClaimsIdentity("Cookies");
+ identity.AddClaim(new Claim(ClaimTypes.Name, "Alice"));
+
+ var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts"));
+ var dataProtector = dataProtection.CreateProtector(
+ "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type
+ Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2");
+
+ var interopServer = TestServer.Create(app =>
+ {
+ app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
+
+ app.UseCookieAuthentication(new Cookies.CookieAuthenticationOptions
+ {
+ TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector)),
+ CookieName = AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.CookiePrefix
+ + AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme,
+ });
+
+ app.Run(context =>
+ {
+ context.Authentication.SignIn(identity);
+ return Task.FromResult(0);
+ });
+ });
+
+ var transaction = await SendAsync(interopServer, "http://example.com");
+
+ var builder = new WebHostBuilder()
+ .Configure(app =>
+ {
+ app.UseAuthentication();
+ app.Run(async context =>
+ {
+ var result = await context.AuthenticateAsync("Cookies");
+ await context.Response.WriteAsync(result.Ticket.Principal.Identity.Name);
+ });
+ })
+ .ConfigureServices(services => services.AddCookieAuthentication(o => o.DataProtectionProvider = dataProtection));
+ var newServer = new AspNetCore.TestHost.TestServer(builder);
+
+ var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/login");
+ foreach (var cookie in SetCookieHeaderValue.ParseList(transaction.SetCookie))
+ {
+ request.Headers.Add("Cookie", cookie.Name + "=" + cookie.Value);
+ }
+ var response = await newServer.CreateClient().SendAsync(request);
+
+ Assert.Equal("Alice", await response.Content.ReadAsStringAsync());
+ }
+
+ [Fact]
+ public async Task AspNetCoreWithLargeInteropCookieContainsIdentity()
+ {
+ var identity = new ClaimsIdentity("Cookies");
+ identity.AddClaim(new Claim(ClaimTypes.Name, new string('a', 1024 * 5)));
+
+ var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts"));
+ var dataProtector = dataProtection.CreateProtector(
+ "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type
+ Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2");
+
+ var interopServer = TestServer.Create(app =>
+ {
+ app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
+
+ app.UseCookieAuthentication(new Cookies.CookieAuthenticationOptions
+ {
+ TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector)),
+ CookieName = AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.CookiePrefix
+ + AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme,
+ CookieManager = new ChunkingCookieManager(),
+ });
+
+ app.Run(context =>
+ {
+ context.Authentication.SignIn(identity);
+ return Task.FromResult(0);
+ });
+ });
+
+ var transaction = await SendAsync(interopServer, "http://example.com");
+
+ var builder = new WebHostBuilder()
+ .Configure(app =>
+ {
+ app.UseAuthentication();
+ app.Run(async context =>
+ {
+ var result = await context.AuthenticateAsync("Cookies");
+ await context.Response.WriteAsync(result.Ticket.Principal.Identity.Name);
+ });
+ })
+ .ConfigureServices(services => services.AddCookieAuthentication(o => o.DataProtectionProvider = dataProtection));
+ var newServer = new AspNetCore.TestHost.TestServer(builder);
+
+ var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/login");
+ foreach (var cookie in SetCookieHeaderValue.ParseList(transaction.SetCookie))
+ {
+ request.Headers.Add("Cookie", cookie.Name + "=" + cookie.Value);
+ }
+ var response = await newServer.CreateClient().SendAsync(request);
+
+ Assert.Equal(1024 * 5, (await response.Content.ReadAsStringAsync()).Length);
+ }
+
+ [Fact]
+ public async Task InteropWithNewCookieContainsIdentity()
+ {
+ var user = new ClaimsPrincipal();
+ var identity = new ClaimsIdentity("scheme");
+ identity.AddClaim(new Claim(ClaimTypes.Name, "Alice"));
+ user.AddIdentity(identity);
+
+ var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts"));
+ var dataProtector = dataProtection.CreateProtector(
+ "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type
+ Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2");
+
+ var builder = new WebHostBuilder()
+ .Configure(app =>
+ {
+ app.UseAuthentication();
+ app.Run(context => context.SignInAsync("Cookies", user));
+ })
+ .ConfigureServices(services => services.AddCookieAuthentication(o => o.DataProtectionProvider = dataProtection));
+ var newServer = new AspNetCore.TestHost.TestServer(builder);
+
+ var cookies = await SendAndGetCookies(newServer, "http://example.com/login");
+
+ var server = TestServer.Create(app =>
+ {
+ app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
+
+ app.UseCookieAuthentication(new Cookies.CookieAuthenticationOptions
+ {
+ TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector)),
+ CookieName = AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.CookiePrefix
+ + AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme,
+ });
+
+ app.Run(async context =>
+ {
+ var result = await context.Authentication.AuthenticateAsync("Cookies");
+ Describe(context.Response, result);
+ });
+ });
+
+ var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", cookies);
+
+ Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name));
+ }
+
+ [Fact]
+ public async Task InteropWithLargeNewCookieContainsIdentity()
+ {
+ var user = new ClaimsPrincipal();
+ var identity = new ClaimsIdentity("scheme");
+ identity.AddClaim(new Claim(ClaimTypes.Name, new string('a', 1024 * 5)));
+ user.AddIdentity(identity);
+
+ var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts"));
+ var dataProtector = dataProtection.CreateProtector(
+ "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type
+ Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2");
+
+ var builder = new WebHostBuilder()
+ .Configure(app =>
+ {
+ app.UseAuthentication();
+ app.Run(context => context.SignInAsync("Cookies", user));
+ })
+ .ConfigureServices(services => services.AddCookieAuthentication(o => o.DataProtectionProvider = dataProtection));
+ var newServer = new AspNetCore.TestHost.TestServer(builder);
+
+ var cookies = await SendAndGetCookies(newServer, "http://example.com/login");
+
+ var server = TestServer.Create(app =>
+ {
+ app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
+
+ app.UseCookieAuthentication(new Cookies.CookieAuthenticationOptions
+ {
+ TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector)),
+ CookieName = AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.CookiePrefix
+ + AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme,
+ CookieManager = new ChunkingCookieManager(),
+ });
+
+ app.Run(async context =>
+ {
+ var result = await context.Authentication.AuthenticateAsync("Cookies");
+ Describe(context.Response, result);
+ });
+ });
+
+ var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", cookies);
+
+ Assert.Equal(1024 * 5, FindClaimValue(transaction2, ClaimTypes.Name).Length);
+ }
+
+ private static async Task> SendAndGetCookies(AspNetCore.TestHost.TestServer server, string uri)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, uri);
+ var response = await server.CreateClient().SendAsync(request);
+ if (response.Headers.Contains("Set-Cookie"))
+ {
+ IList cookieHeaders = new List();
+ foreach (var cookie in SetCookieHeaderValue.ParseList(response.Headers.GetValues("Set-Cookie").ToList()))
+ {
+ cookieHeaders.Add(cookie.Name + "=" + cookie.Value);
+ }
+ return cookieHeaders;
+ }
+ return null;
+ }
+
+ private static string FindClaimValue(Transaction transaction, string claimType)
+ {
+ XElement claim = transaction.ResponseElement.Elements("claim").SingleOrDefault(elt => elt.Attribute("type").Value == claimType);
+ if (claim == null)
+ {
+ return null;
+ }
+ return claim.Attribute("value").Value;
+ }
+
+ private static void Describe(IOwinResponse res, AuthenticateResult result)
+ {
+ res.StatusCode = 200;
+ res.ContentType = "text/xml";
+ var xml = new XElement("xml");
+ if (result != null && result.Identity != null)
+ {
+ xml.Add(result.Identity.Claims.Select(claim => new XElement("claim", new XAttribute("type", claim.Type), new XAttribute("value", claim.Value))));
+ }
+ if (result != null && result.Properties != null)
+ {
+ xml.Add(result.Properties.Dictionary.Select(extra => new XElement("extra", new XAttribute("type", extra.Key), new XAttribute("value", extra.Value))));
+ }
+ using (var memory = new MemoryStream())
+ {
+ using (var writer = new XmlTextWriter(memory, Encoding.UTF8))
+ {
+ xml.WriteTo(writer);
+ }
+ res.Body.Write(memory.ToArray(), 0, memory.ToArray().Length);
+ }
+ }
+
+ private static async Task SendAsync(TestServer server, string uri, IList cookieHeaders = null, bool ajaxRequest = false)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, uri);
+ if (cookieHeaders != null)
+ {
+ request.Headers.Add("Cookie", cookieHeaders);
+ }
+ if (ajaxRequest)
+ {
+ request.Headers.Add("X-Requested-With", "XMLHttpRequest");
+ }
+ var transaction = new Transaction
+ {
+ Request = request,
+ Response = await server.HttpClient.SendAsync(request),
+ };
+ if (transaction.Response.Headers.Contains("Set-Cookie"))
+ {
+ transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
+ }
+ if (transaction.SetCookie != null && transaction.SetCookie.Any())
+ {
+ transaction.CookieNameValue = transaction.SetCookie.First().Split(new[] { ';' }, 2).First();
+ }
+ transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
+
+ if (transaction.Response.Content != null &&
+ transaction.Response.Content.Headers.ContentType != null &&
+ transaction.Response.Content.Headers.ContentType.MediaType == "text/xml")
+ {
+ transaction.ResponseElement = XElement.Parse(transaction.ResponseText);
+ }
+ return transaction;
+ }
+
+ private class Transaction
+ {
+ public HttpRequestMessage Request { get; set; }
+ public HttpResponseMessage Response { get; set; }
+
+ public IList SetCookie { get; set; }
+ public string CookieNameValue { get; set; }
+
+ public string ResponseText { get; set; }
+ public XElement ResponseElement { get; set; }
+ }
+
+ }
+}
+
diff --git a/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.csproj b/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.csproj
new file mode 100644
index 0000000000..d6e9d16e5f
--- /dev/null
+++ b/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+
+ net461
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs b/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs
new file mode 100644
index 0000000000..b14ea0d74e
--- /dev/null
+++ b/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs
@@ -0,0 +1,91 @@
+// 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;
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using Xunit;
+
+namespace Microsoft.Owin.Security.Interop.Test
+{
+ public class TicketInteropTests
+ {
+ [Fact]
+ public void NewSerializerCanReadInteropTicket()
+ {
+ var identity = new ClaimsIdentity("scheme");
+ identity.AddClaim(new Claim("Test", "Value"));
+
+ var expires = DateTime.Today;
+ var issued = new DateTime(1979, 11, 11);
+ var properties = new Owin.Security.AuthenticationProperties();
+ properties.IsPersistent = true;
+ properties.RedirectUri = "/redirect";
+ properties.Dictionary["key"] = "value";
+ properties.ExpiresUtc = expires;
+ properties.IssuedUtc = issued;
+
+ var interopTicket = new Owin.Security.AuthenticationTicket(identity, properties);
+ var interopSerializer = new AspNetTicketSerializer();
+
+ var bytes = interopSerializer.Serialize(interopTicket);
+
+ var newSerializer = new TicketSerializer();
+ var newTicket = newSerializer.Deserialize(bytes);
+
+ Assert.NotNull(newTicket);
+ Assert.Equal(1, newTicket.Principal.Identities.Count());
+ var newIdentity = newTicket.Principal.Identity as ClaimsIdentity;
+ Assert.NotNull(newIdentity);
+ Assert.Equal("scheme", newIdentity.AuthenticationType);
+ Assert.True(newIdentity.HasClaim(c => c.Type == "Test" && c.Value == "Value"));
+ Assert.NotNull(newTicket.Properties);
+ Assert.True(newTicket.Properties.IsPersistent);
+ Assert.Equal("/redirect", newTicket.Properties.RedirectUri);
+ Assert.Equal("value", newTicket.Properties.Items["key"]);
+ Assert.Equal(expires, newTicket.Properties.ExpiresUtc);
+ Assert.Equal(issued, newTicket.Properties.IssuedUtc);
+ }
+
+ [Fact]
+ public void InteropSerializerCanReadNewTicket()
+ {
+ var user = new ClaimsPrincipal();
+ var identity = new ClaimsIdentity("scheme");
+ identity.AddClaim(new Claim("Test", "Value"));
+ user.AddIdentity(identity);
+
+ var expires = DateTime.Today;
+ var issued = new DateTime(1979, 11, 11);
+ var properties = new AspNetCore.Authentication.AuthenticationProperties();
+ properties.IsPersistent = true;
+ properties.RedirectUri = "/redirect";
+ properties.Items["key"] = "value";
+ properties.ExpiresUtc = expires;
+ properties.IssuedUtc = issued;
+
+ var newTicket = new AspNetCore.Authentication.AuthenticationTicket(user, properties, "scheme");
+ var newSerializer = new TicketSerializer();
+
+ var bytes = newSerializer.Serialize(newTicket);
+
+ var interopSerializer = new AspNetTicketSerializer();
+ var interopTicket = interopSerializer.Deserialize(bytes);
+
+ Assert.NotNull(interopTicket);
+ var newIdentity = interopTicket.Identity;
+ Assert.NotNull(newIdentity);
+ Assert.Equal("scheme", newIdentity.AuthenticationType);
+ Assert.True(newIdentity.HasClaim(c => c.Type == "Test" && c.Value == "Value"));
+ Assert.NotNull(interopTicket.Properties);
+ Assert.True(interopTicket.Properties.IsPersistent);
+ Assert.Equal("/redirect", interopTicket.Properties.RedirectUri);
+ Assert.Equal("value", interopTicket.Properties.Dictionary["key"]);
+ Assert.Equal(expires, interopTicket.Properties.ExpiresUtc);
+ Assert.Equal(issued, interopTicket.Properties.IssuedUtc);
+ }
+ }
+}
+
+