Add initial Owin Security cookie interop package
This commit is contained in:
parent
b09777fe38
commit
e72a563902
30
Security.sln
30
Security.sln
|
|
@ -50,6 +50,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.CookiePoli
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Authentication.JwtBearer", "src\Microsoft.AspNet.Authentication.JwtBearer\Microsoft.AspNet.Authentication.JwtBearer.xproj", "{2755BFE5-7421-4A31-A644-F817DF5CAA98}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Owin.Security.Cookies.Interop", "src\Microsoft.Owin.Security.Cookies.Interop\Microsoft.Owin.Security.Cookies.Interop.xproj", "{21A56E78-31DE-4868-9778-7E4DBE2A4E35}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Owin.Security.Cookies.Interop.Test", "test\Microsoft.Owin.Security.Cookies.Interop.Test\Microsoft.Owin.Security.Cookies.Interop.Test.xproj", "{73E8E654-A2AC-4848-95F3-EB55512F6C39}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -270,6 +274,30 @@ Global
|
|||
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.Build.0 = Release|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35}.Release|x86.Build.0 = Release|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -293,5 +321,7 @@ Global
|
|||
{86183DC3-02A8-4A68-8B60-71ECEC066E79} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{1790E052-646F-4529-B90E-6FEA95520D69} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
{2755BFE5-7421-4A31-A644-F817DF5CAA98} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{21A56E78-31DE-4868-9778-7E4DBE2A4E35} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{73E8E654-A2AC-4848-95F3-EB55512F6C39} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
}
|
||||
if (Options.TicketDataFormat == null)
|
||||
{
|
||||
var dataProtector = dataProtectionProvider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2");
|
||||
var provider = Options.DataProtectionProvider ?? dataProtectionProvider;
|
||||
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2");
|
||||
Options.TicketDataFormat = new TicketDataFormat(dataProtector);
|
||||
}
|
||||
if (Options.CookieManager == null)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNet.DataProtection;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
|
||||
|
|
@ -74,6 +75,11 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
/// </summary>
|
||||
public CookieSecureOption CookieSecure { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set this will be used by the CookieAuthenticationMiddleware for data protection.
|
||||
/// </summary>
|
||||
public IDataProtectionProvider DataProtectionProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controls how much time the cookie will remain valid from the point it is created. The expiration
|
||||
/// information is in the protected cookie ticket. Because of that an expired cookie will be ignored
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Security.Claims;
|
|||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
// This MUST be kept in sync with Microsoft.Owin.Security.Cookies.AspNetTicketSerializer
|
||||
public class TicketSerializer : IDataSerializer<AuthenticationTicket>
|
||||
{
|
||||
private const string DefaultStringPlaceholder = "\0";
|
||||
|
|
|
|||
|
|
@ -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.Cookies.Interop
|
||||
{
|
||||
public class AspNetTicketDataFormat : SecureDataFormat<AuthenticationTicket>
|
||||
{
|
||||
public AspNetTicketDataFormat(IDataProtector protector)
|
||||
: base(new AspNetTicketSerializer(), protector, TextEncodings.Base64Url)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.Cookies.Interop
|
||||
{
|
||||
// This MUST be kept in sync with Microsoft.AspNet.Authentication.DataHandler.TicketSerializer
|
||||
public class AspNetTicketSerializer : IDataSerializer<AuthenticationTicket>
|
||||
{
|
||||
private const string DefaultStringPlaceholder = "\0";
|
||||
private const int FormatVersion = 5;
|
||||
|
||||
public static TicketSerializer Default { get; } = new TicketSerializer();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.AspNet.DataProtection;
|
||||
using Microsoft.Owin.Security.Cookies;
|
||||
using Microsoft.Owin.Security.Cookies.Interop;
|
||||
|
||||
namespace Owin
|
||||
{
|
||||
public static class CookieAuthenticationExtensions
|
||||
{
|
||||
public static IAppBuilder UseCookieAuthentication(
|
||||
this IAppBuilder app,
|
||||
CookieAuthenticationOptions options,
|
||||
DataProtectionProvider dataProtectionProvider,
|
||||
PipelineStage stage = PipelineStage.Authenticate)
|
||||
{
|
||||
var dataProtector = dataProtectionProvider.CreateProtector(
|
||||
"Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET 5 type
|
||||
options.AuthenticationType, "v2");
|
||||
options.TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector));
|
||||
|
||||
return app.UseCookieAuthentication(options, stage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.AspNet.DataProtection;
|
||||
|
||||
namespace Microsoft.Owin.Security.Cookies.Interop
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an <see cref="IDataProtector"/> to an
|
||||
/// <see cref="Microsoft.Owin.Security.DataProtection.IDataProtector"/>.
|
||||
/// </summary>
|
||||
internal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Helpful constants for working with the authentication cookie compatibility shim.
|
||||
/// </summary>
|
||||
public static class DefaultCompatibilityConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// The default authentication type for application authentication cookies.
|
||||
/// </summary>
|
||||
public const string ApplicationCookieAuthenticationType = "Microsoft.AspNet.Identity.Application.AuthType";
|
||||
|
||||
/// <summary>
|
||||
/// The default cookie name for application authentication cookies.
|
||||
/// Used by <see cref="CookieAuthenticationOptions.CookieName"/>.
|
||||
/// </summary>
|
||||
public const string CookieName = ".AspNet.Microsoft.AspNet.Identity.Application";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>21a56e78-31de-4868-9778-7e4dbe2a4e35</ProjectGuid>
|
||||
<RootNamespace>Microsoft.Owin.Security.Cookies.Shareable</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"description": "A compatibility layer for sharing authentication tickets between Microsoft.Owin.Security.Cookies and Microsoft.AspNet.Authentication.Cookies.",
|
||||
"dependencies": {
|
||||
},
|
||||
"frameworks": {
|
||||
"net451": {
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.DataProtection.Extensions": "1.0.0-*",
|
||||
"Microsoft.Owin.Security.Cookies": "3.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
// 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.Net;
|
||||
using System.Net.Http;
|
||||
|
|
@ -10,7 +9,6 @@ using System.Security.Claims;
|
|||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.DataProtection;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
"Microsoft.AspNet.Authentication.MicrosoftAccount": "1.0.0-*",
|
||||
"Microsoft.AspNet.Authentication.OpenIdConnect": "1.0.0-*",
|
||||
"Microsoft.AspNet.Authentication.Twitter": "1.0.0-*",
|
||||
"Microsoft.AspNet.DataProtection": "1.0.0-*",
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
"Microsoft.AspNet.Testing": "1.0.0-*",
|
||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>73e8e654-a2ac-4848-95f3-eb55512f6c39</ProjectGuid>
|
||||
<RootNamespace>Microsoft.Owin.Security.Cookies.Interop.Test</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNet.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Owin;
|
||||
using Microsoft.Owin.Security.Cookies;
|
||||
using Microsoft.Owin.Security.Cookies.Interop;
|
||||
using Microsoft.Owin.Testing;
|
||||
using Owin;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.CookiePolicy.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 Http.Authentication.AuthenticationProperties();
|
||||
properties.IsPersistent = true;
|
||||
properties.RedirectUri = "/redirect";
|
||||
properties.Items["key"] = "value";
|
||||
properties.ExpiresUtc = expires;
|
||||
properties.IssuedUtc = issued;
|
||||
|
||||
var newTicket = new 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AspNet5WithInteropCookieContainsIdentity()
|
||||
{
|
||||
var identity = new ClaimsIdentity("Cookies");
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, "Alice"));
|
||||
|
||||
var dataProtection = new DataProtection.DataProtectionProvider(new DirectoryInfo("."));
|
||||
|
||||
var interopServer = TestServer.Create(app =>
|
||||
{
|
||||
app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
|
||||
app.UseCookieAuthentication(new CookieAuthenticationOptions(), dataProtection);
|
||||
app.Run(context =>
|
||||
{
|
||||
context.Authentication.SignIn(identity);
|
||||
return Task.FromResult(0);
|
||||
});
|
||||
});
|
||||
|
||||
var transaction = await SendAsync(interopServer, "http://example.com");
|
||||
|
||||
var newServer = TestHost.TestServer.Create(app =>
|
||||
{
|
||||
app.UseCookieAuthentication(options => options.DataProtectionProvider = dataProtection);
|
||||
app.Run(async context =>
|
||||
{
|
||||
var result = await context.Authentication.AuthenticateAsync("Cookies");
|
||||
await context.Response.WriteAsync(result.Identity.Name);
|
||||
});
|
||||
}, services => services.AddAuthentication());
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/login");
|
||||
request.Headers.Add("Cookie", transaction.SetCookie.Split(new[] { ';' }, 2).First());
|
||||
var response = await newServer.CreateClient().SendAsync(request);
|
||||
|
||||
Assert.Equal("Alice", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[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 = new DataProtection.DataProtectionProvider(new DirectoryInfo("."));
|
||||
|
||||
var newServer = TestHost.TestServer.Create(app =>
|
||||
{
|
||||
app.UseCookieAuthentication(options => options.DataProtectionProvider = dataProtection);
|
||||
app.Run(context => context.Authentication.SignInAsync("Cookies", user));
|
||||
}, services => services.AddAuthentication());
|
||||
|
||||
var cookie = await SendAndGetCookie(newServer, "http://example.com/login");
|
||||
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.Properties["host.AppName"] = "Microsoft.Owin.Security.Tests";
|
||||
app.UseCookieAuthentication(new CookieAuthenticationOptions(), dataProtection);
|
||||
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", cookie);
|
||||
|
||||
Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name));
|
||||
}
|
||||
|
||||
private static async Task<string> SendAndGetCookie(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"))
|
||||
{
|
||||
return response.Headers.GetValues("Set-Cookie").ToList().First();
|
||||
}
|
||||
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, Owin.Security.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<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null, bool ajaxRequest = false)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
if (!string.IsNullOrEmpty(cookieHeader))
|
||||
{
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
}
|
||||
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").SingleOrDefault();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(transaction.SetCookie))
|
||||
{
|
||||
transaction.CookieNameValue = transaction.SetCookie.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 string SetCookie { get; set; }
|
||||
public string CookieNameValue { get; set; }
|
||||
|
||||
public string ResponseText { get; set; }
|
||||
public XElement ResponseElement { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<key id="38ae71c9-485f-46f6-8b5d-a1da2230875f" version="1">
|
||||
<creationDate>2015-10-21T22:18:44.8335016Z</creationDate>
|
||||
<activationDate>2015-10-21T22:18:44.8335016Z</activationDate>
|
||||
<expirationDate>2016-01-19T22:18:44.8335016Z</expirationDate>
|
||||
<descriptor deserializerType="Microsoft.AspNet.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNet.DataProtection, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<descriptor>
|
||||
<encryption algorithm="AES_256_CBC" />
|
||||
<validation algorithm="HMACSHA256" />
|
||||
<masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
|
||||
<!-- Warning: the key below is in an unencrypted form. -->
|
||||
<value>7LN6JAKaUxuHQmzldfRpxCuHZtkEoG6Zrvc0LaNXgP0Ful2wYocEwlB7JRdkKAEcmY53W5wqVNSVfcgln+hNVA==</value>
|
||||
</masterKey>
|
||||
</descriptor>
|
||||
</descriptor>
|
||||
</key>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Authentication.Cookies": "1.0.0-*",
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
"Microsoft.Owin.Security.Cookies.Interop": "1.0.0-*",
|
||||
"Microsoft.Owin.Testing": "3.0.1",
|
||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
||||
},
|
||||
"commands": {
|
||||
"test": "xunit.runner.aspnet"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue