Merge branch 'release/2.2'

This commit is contained in:
Nate McMaster 2018-08-30 16:33:36 -07:00
commit a407a047f0
No known key found for this signature in database
GPG Key ID: A778D9601BD78810
16 changed files with 647 additions and 1 deletions

View File

@ -77,6 +77,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureKeyVault", "samples\Az
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection.AzureKeyVault.Test", "test\Microsoft.AspNetCore.DataProtection.AzureKeyVault.Test\Microsoft.AspNetCore.DataProtection.AzureKeyVault.Test.csproj", "{C85ED942-8121-453F-8308-9DB730843B63}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test", "test\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test.csproj", "{06728BF2-C5EB-44C7-9F30-14FAA5649E14}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore", "src\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj", "{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCoreSample", "samples\EntityFrameworkCoreSample\EntityFrameworkCoreSample.csproj", "{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -265,6 +271,30 @@ Global
{C85ED942-8121-453F-8308-9DB730843B63}.Release|Any CPU.Build.0 = Release|Any CPU
{C85ED942-8121-453F-8308-9DB730843B63}.Release|x86.ActiveCfg = Release|Any CPU
{C85ED942-8121-453F-8308-9DB730843B63}.Release|x86.Build.0 = Release|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Debug|x86.ActiveCfg = Debug|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Debug|x86.Build.0 = Debug|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|Any CPU.Build.0 = Release|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|x86.ActiveCfg = Release|Any CPU
{06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|x86.Build.0 = Release|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|x86.ActiveCfg = Debug|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|x86.Build.0 = Debug|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|Any CPU.Build.0 = Release|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|x86.ActiveCfg = Release|Any CPU
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|x86.Build.0 = Release|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|x86.ActiveCfg = Debug|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|x86.Build.0 = Debug|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|Any CPU.Build.0 = Release|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|x86.ActiveCfg = Release|Any CPU
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -293,6 +323,9 @@ Global
{4E76B2A8-9DC3-46E6-B5FC-097A1D1DFBE9} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
{295E8539-5450-4764-B3F5-51F968628022} = {5A3A5DE3-49AD-431C-971D-B01B62D94AE2}
{C85ED942-8121-453F-8308-9DB730843B63} = {60336AB3-948D-4D15-A5FB-F32A2B91E814}
{06728BF2-C5EB-44C7-9F30-14FAA5649E14} = {60336AB3-948D-4D15-A5FB-F32A2B91E814}
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76} = {5A3A5DE3-49AD-431C-971D-B01B62D94AE2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD305D75-BD1B-43AE-BF04-869DA6A0858F}

View File

@ -8,6 +8,8 @@
<MicrosoftAspNetCoreHostingPackageVersion>3.0.0-alpha1-10352</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>3.0.0-alpha1-10352</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAzureKeyVaultPackageVersion>2.3.2</MicrosoftAzureKeyVaultPackageVersion>
<MicrosoftEntityFrameworkCoreInMemoryPackageVersion>3.0.0-alpha1-10352</MicrosoftEntityFrameworkCoreInMemoryPackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>3.0.0-alpha1-10352</MicrosoftEntityFrameworkCorePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>3.0.0-alpha1-10352</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>3.0.0-alpha1-10352</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>3.0.0-alpha1-10352</MicrosoftExtensionsConfigurationPackageVersion>

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(MicrosoftEntityFrameworkCoreInMemoryPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,48 @@
// 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 Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace EntityFrameworkCoreSample
{
class Program
{
static void Main(string[] args)
{
// Configure
var services = new ServiceCollection()
.AddLogging(o => o.AddConsole().SetMinimumLevel(LogLevel.Debug))
.AddDbContext<DataProtectionKeyContext>(o =>
{
o.UseInMemoryDatabase("DataProtection_EntityFrameworkCore");
o.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
o.EnableSensitiveDataLogging();
})
.AddDataProtection()
.PersistKeysToDbContext<DataProtectionKeyContext>()
.SetDefaultKeyLifetime(TimeSpan.FromDays(7))
.Services
.BuildServiceProvider(validateScopes: true);
using(services)
{
// Run a sample payload
var protector = services.GetDataProtector("sample-purpose");
var protectedData = protector.Protect("Hello world!");
Console.WriteLine(protectedData);
}
}
}
class DataProtectionKeyContext : DbContext, IDataProtectionKeyContext
{
public DataProtectionKeyContext(DbContextOptions<DataProtectionKeyContext> options) : base(options) { }
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
}
}

View File

@ -7,7 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace Redis
namespace RedisSample
{
public class Program
{

View File

@ -0,0 +1,26 @@
// 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.AspNetCore.DataProtection.EntityFrameworkCore
{
/// <summary>
/// Code first model used by <see cref="EntityFrameworkCoreXmlRepository{TContext}"/>.
/// </summary>
public class DataProtectionKey
{
/// <summary>
/// The entity identifier of the <see cref="DataProtectionKey"/>.
/// </summary>
public int Id { get; set; }
/// <summary>
/// The friendly name of the <see cref="DataProtectionKey"/>.
/// </summary>
public string FriendlyName { get; set; }
/// <summary>
/// The XML representation of the <see cref="DataProtectionKey"/>.
/// </summary>
public string Xml { get; set; }
}
}

View File

@ -0,0 +1,39 @@
// 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 Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.DataProtection
{
/// <summary>
/// Extension method class for configuring instances of <see cref="EntityFrameworkCoreXmlRepository{TContext}"/>
/// </summary>
public static class EntityFrameworkCoreDataProtectionExtensions
{
/// <summary>
/// Configures the data protection system to persist keys to an EntityFrameworkCore datastore
/// </summary>
/// <param name="builder">The <see cref="IDataProtectionBuilder"/> instance to modify.</param>
/// <returns>The value <paramref name="builder"/>.</returns>
public static IDataProtectionBuilder PersistKeysToDbContext<TContext>(this IDataProtectionBuilder builder)
where TContext : DbContext, IDataProtectionKeyContext
{
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{
var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options =>
{
options.XmlRepository = new EntityFrameworkCoreXmlRepository<TContext>(services, loggerFactory);
});
});
return builder;
}
}
}

View File

@ -0,0 +1,81 @@
// 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.Linq;
using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
{
/// <summary>
/// An <see cref="IXmlRepository"/> backed by an EntityFrameworkCore datastore.
/// </summary>
public class EntityFrameworkCoreXmlRepository<TContext> : IXmlRepository
where TContext : DbContext, IDataProtectionKeyContext
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
/// <summary>
/// Creates a new instance of the <see cref="EntityFrameworkCoreXmlRepository{TContext}"/>.
/// </summary>
/// <param name="services"></param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public EntityFrameworkCoreXmlRepository(IServiceProvider services, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<EntityFrameworkCoreXmlRepository<TContext>>();
_services = services ?? throw new ArgumentNullException(nameof(services));
}
/// <inheritdoc />
public virtual IReadOnlyCollection<XElement> GetAllElements()
{
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<TContext>();
return context.DataProtectionKeys.AsNoTracking().Select(key => TryParseKeyXml(key.Xml)).ToList().AsReadOnly();
}
}
/// <inheritdoc />
public void StoreElement(XElement element, string friendlyName)
{
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<TContext>();
var newKey = new DataProtectionKey()
{
FriendlyName = friendlyName,
Xml = element.ToString(SaveOptions.DisableFormatting)
};
context.DataProtectionKeys.Add(newKey);
_logger.LogSavingKeyToDbContext(friendlyName, typeof(TContext).Name);
context.SaveChanges();
}
}
private XElement TryParseKeyXml(string xml)
{
try
{
return XElement.Parse(xml);
}
catch (Exception e)
{
_logger?.LogExceptionWhileParsingKeyXml(xml, e);
return null;
}
}
}
}

View File

@ -0,0 +1,18 @@
// 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 Microsoft.EntityFrameworkCore;
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
{
/// <summary>
/// Interface used to store instances of <see cref="DataProtectionKey"/> in a <see cref="DbContext"/>
/// </summary>
public interface IDataProtectionKeyContext
{
/// <summary>
/// A collection of <see cref="DataProtectionKey"/>
/// </summary>
DbSet<DataProtectionKey> DataProtectionKeys { get; }
}
}

View File

@ -0,0 +1,31 @@
// 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;
namespace Microsoft.Extensions.Logging
{
internal static class LoggingExtensions
{
private static readonly Action<ILogger, string, Exception> _anExceptionOccurredWhileParsingKeyXml;
private static readonly Action<ILogger, string, string, Exception> _savingKeyToDbContext;
static LoggingExtensions()
{
_anExceptionOccurredWhileParsingKeyXml = LoggerMessage.Define<string>(
eventId: 1,
logLevel: LogLevel.Warning,
formatString: "An exception occurred while parsing the key xml '{Xml}'.");
_savingKeyToDbContext = LoggerMessage.Define<string, string>(
eventId: 2,
logLevel: LogLevel.Debug,
formatString: "Saving key '{FriendlyName}' to '{DbContext}'.");
}
public static void LogExceptionWhileParsingKeyXml(this ILogger logger, string keyXml, Exception exception)
=> _anExceptionOccurredWhileParsingKeyXml(logger, keyXml, exception);
public static void LogSavingKeyToDbContext(this ILogger logger, string friendlyName, string contextName)
=> _savingKeyToDbContext(logger, friendlyName, contextName, null);
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Support for storing keys using Entity Framework Core.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection;entityframeworkcore</PackageTags>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.DataProtection\Microsoft.AspNetCore.DataProtection.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,203 @@
{
"AssemblyIdentity": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
"Types": [
{
"Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCoreDataProtectionExtensions",
"Visibility": "Public",
"Kind": "Class",
"Abstract": true,
"Static": true,
"Sealed": true,
"ImplementedInterfaces": [],
"Members": [
{
"Kind": "Method",
"Name": "PersistKeysToDbContext<T0>",
"Parameters": [
{
"Name": "builder",
"Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder"
}
],
"ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder",
"Static": true,
"Extension": true,
"Visibility": "Public",
"GenericParameter": [
{
"ParameterName": "TContext",
"ParameterPosition": 0,
"BaseTypeOrInterfaces": [
"Microsoft.EntityFrameworkCore.DbContext",
"Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.IDataProtectionKeyContext"
]
}
]
}
],
"GenericParameters": []
},
{
"Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey",
"Visibility": "Public",
"Kind": "Class",
"ImplementedInterfaces": [],
"Members": [
{
"Kind": "Method",
"Name": "get_Id",
"Parameters": [],
"ReturnType": "System.Int32",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Method",
"Name": "set_Id",
"Parameters": [
{
"Name": "value",
"Type": "System.Int32"
}
],
"ReturnType": "System.Void",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Method",
"Name": "get_FriendlyName",
"Parameters": [],
"ReturnType": "System.String",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Method",
"Name": "set_FriendlyName",
"Parameters": [
{
"Name": "value",
"Type": "System.String"
}
],
"ReturnType": "System.Void",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Method",
"Name": "get_Xml",
"Parameters": [],
"ReturnType": "System.String",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Method",
"Name": "set_Xml",
"Parameters": [
{
"Name": "value",
"Type": "System.String"
}
],
"ReturnType": "System.Void",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Constructor",
"Name": ".ctor",
"Parameters": [],
"Visibility": "Public",
"GenericParameter": []
}
],
"GenericParameters": []
},
{
"Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.EntityFrameworkCoreXmlRepository<T0>",
"Visibility": "Public",
"Kind": "Class",
"ImplementedInterfaces": [
"Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository"
],
"Members": [
{
"Kind": "Method",
"Name": "GetAllElements",
"Parameters": [],
"ReturnType": "System.Collections.Generic.IReadOnlyCollection<System.Xml.Linq.XElement>",
"Virtual": true,
"ImplementedInterface": "Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Method",
"Name": "StoreElement",
"Parameters": [
{
"Name": "element",
"Type": "System.Xml.Linq.XElement"
},
{
"Name": "friendlyName",
"Type": "System.String"
}
],
"ReturnType": "System.Void",
"Sealed": true,
"Virtual": true,
"ImplementedInterface": "Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository",
"Visibility": "Public",
"GenericParameter": []
},
{
"Kind": "Constructor",
"Name": ".ctor",
"Parameters": [
{
"Name": "services",
"Type": "System.IServiceProvider"
},
{
"Name": "loggerFactory",
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
}
],
"Visibility": "Public",
"GenericParameter": []
}
],
"GenericParameters": [
{
"ParameterName": "TContext",
"ParameterPosition": 0,
"BaseTypeOrInterfaces": [
"Microsoft.EntityFrameworkCore.DbContext",
"Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.IDataProtectionKeyContext"
]
}
]
},
{
"Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.IDataProtectionKeyContext",
"Visibility": "Public",
"Kind": "Interface",
"Abstract": true,
"ImplementedInterfaces": [],
"Members": [
{
"Kind": "Method",
"Name": "get_DataProtectionKeys",
"Parameters": [],
"ReturnType": "Microsoft.EntityFrameworkCore.DbSet<Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey>",
"GenericParameter": []
}
],
"GenericParameters": []
}
]
}

View File

@ -0,0 +1,69 @@
// 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.Xml.Linq;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.DataProtection
{
public class DataProtectionEntityFrameworkTests
{
[Fact]
public void CreateRepository_ThrowsIf_ContextIsNull()
{
Assert.Throws<ArgumentNullException>(() => new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(null, null));
}
[Fact]
public void StoreElement_PersistsData()
{
var element = XElement.Parse("<Element1/>");
var friendlyName = "Element1";
var key = new DataProtectionKey() { FriendlyName = friendlyName, Xml = element.ToString() };
var services = GetServices(nameof(StoreElement_PersistsData));
var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(services, NullLoggerFactory.Instance);
service.StoreElement(element, friendlyName);
// Use a separate instance of the context to verify correct data was saved to database
using (var context = services.CreateScope().ServiceProvider.GetRequiredService< DataProtectionKeyContext>())
{
Assert.Equal(1, context.DataProtectionKeys.Count());
Assert.Equal(key.FriendlyName, context.DataProtectionKeys.Single()?.FriendlyName);
Assert.Equal(key.Xml, context.DataProtectionKeys.Single()?.Xml);
}
}
[Fact]
public void GetAllElements_ReturnsAllElements()
{
var element1 = XElement.Parse("<Element1/>");
var element2 = XElement.Parse("<Element2/>");
var services = GetServices(nameof(GetAllElements_ReturnsAllElements));
var service1 = CreateRepo(services);
service1.StoreElement(element1, "element1");
service1.StoreElement(element2, "element2");
// Use a separate instance of the context to verify correct data was saved to database
var service2 = CreateRepo(services);
var elements = service2.GetAllElements();
Assert.Equal(2, elements.Count);
}
private EntityFrameworkCoreXmlRepository<DataProtectionKeyContext> CreateRepo(IServiceProvider services)
=> new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(services, NullLoggerFactory.Instance);
private IServiceProvider GetServices(string dbName)
=> new ServiceCollection()
.AddDbContext<DataProtectionKeyContext>(o => o.UseInMemoryDatabase(dbName))
.BuildServiceProvider(validateScopes: true);
}
}

View File

@ -0,0 +1,14 @@
// 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 Microsoft.EntityFrameworkCore;
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test
{
class DataProtectionKeyContext : DbContext, IDataProtectionKeyContext
{
public DataProtectionKeyContext(DbContextOptions<DataProtectionKeyContext> options) : base(options) { }
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
}
}

View File

@ -0,0 +1,26 @@
// 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 Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Xunit;
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test
{
public class EntityFrameworkCoreDataProtectionBuilderExtensionsTests
{
[Fact]
public void PersistKeysToEntityFrameworkCore_UsesEntityFrameworkCoreXmlRepository()
{
var serviceCollection = new ServiceCollection();
serviceCollection
.AddDbContext<DataProtectionKeyContext>()
.AddDataProtection()
.PersistKeysToDbContext<DataProtectionKeyContext>();
var serviceProvider = serviceCollection.BuildServiceProvider(validateScopes: true);
var keyManagementOptions = serviceProvider.GetRequiredService<IOptions<KeyManagementOptions>>();
Assert.IsType<EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>>(keyManagementOptions.Value.XmlRepository);
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(MicrosoftEntityFrameworkCoreInMemoryPackageVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj" />
</ItemGroup>
</Project>