Added Entity Framework Core backed IXmlRepository with tests and sample (#303)
This commit is contained in:
parent
c119bee8ef
commit
8f7d995508
|
|
@ -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}") = "EntityFrameworkCore", "samples\EntityFrameworkCore\EntityFrameworkCore.csproj", "{E837A2E3-FC93-494C-8689-5AF9C6802AD7}"
|
||||
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
|
||||
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
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7}.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
|
||||
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}
|
||||
{E837A2E3-FC93-494C-8689-5AF9C6802AD7} = {5A3A5DE3-49AD-431C-971D-B01B62D94AE2}
|
||||
{3E4CA7FE-741B-4C78-A775-220E0E3C1B03} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DD305D75-BD1B-43AE-BF04-869DA6A0858F}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34967</MicrosoftAspNetCoreHostingPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34967</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftAzureKeyVaultPackageVersion>2.3.2</MicrosoftAzureKeyVaultPackageVersion>
|
||||
<MicrosoftEntityFrameworkCoreInMemoryPackageVersion>2.2.0-preview1-34967</MicrosoftEntityFrameworkCoreInMemoryPackageVersion>
|
||||
<MicrosoftEntityFrameworkCorePackageVersion>2.2.0-preview1-34967</MicrosoftEntityFrameworkCorePackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.2.0-preview1-34967</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34967</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-preview1-34967</MicrosoftExtensionsConfigurationPackageVersion>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
// 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.EntityFrameworkCore;
|
||||
|
||||
namespace EntityFrameworkCore
|
||||
{
|
||||
class DataProtectionKeyContext : DbContext, IDataProtectionKeyContext
|
||||
{
|
||||
public DataProtectionKeyContext(DbContextOptions<DataProtectionKeyContext> options) : base(options) { }
|
||||
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
optionsBuilder.UseInMemoryDatabase("DataProtection_EntityFrameworkCore");
|
||||
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
optionsBuilder.EnableSensitiveDataLogging();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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;
|
||||
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
|
||||
namespace EntityFrameworkCore
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Configure
|
||||
using (var services = new ServiceCollection()
|
||||
.AddLogging(o => o.AddConsole().SetMinimumLevel(LogLevel.Debug))
|
||||
.AddDbContext<DataProtectionKeyContext>()
|
||||
.AddDataProtection()
|
||||
.PersistKeysToDbContext<DataProtectionKeyContext>()
|
||||
.SetDefaultKeyLifetime(TimeSpan.FromDays(7))
|
||||
.Services
|
||||
.BuildServiceProvider(validateScopes: true))
|
||||
{
|
||||
// Run a sample payload
|
||||
var protector = services.GetDataProtector("sample-purpose");
|
||||
var protectedData = protector.Protect("Hello world!");
|
||||
Console.WriteLine(protectedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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.AspNetCore.DataProtection.Repositories;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
|
||||
{
|
||||
internal class ConfigureKeyManagementOptions : IConfigureOptions<KeyManagementOptions>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ConfigureKeyManagementOptions(IServiceProvider serviceProvider)
|
||||
=> _serviceProvider = serviceProvider;
|
||||
|
||||
public void Configure(KeyManagementOptions options)
|
||||
=> options.XmlRepository = _serviceProvider.CreateScope().ServiceProvider.GetRequiredService<IXmlRepository>();
|
||||
}
|
||||
}
|
||||
|
|
@ -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.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
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>
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// 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.AspNetCore.DataProtection.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
|
||||
{
|
||||
/// <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
|
||||
{
|
||||
var services = builder.Services;
|
||||
|
||||
services.AddScoped<Func<TContext>>(
|
||||
provider => new Func<TContext>(
|
||||
() => provider.CreateScope().ServiceProvider.GetService<TContext>()));
|
||||
|
||||
services.AddScoped<IXmlRepository>(provider =>
|
||||
{
|
||||
var scope = provider.CreateScope();
|
||||
return new EntityFrameworkCoreXmlRepository<TContext>(
|
||||
contextFactory: scope.ServiceProvider.GetRequiredService<Func<TContext>>(),
|
||||
loggerFactory: scope.ServiceProvider.GetService<ILoggerFactory>());
|
||||
});
|
||||
|
||||
services.AddTransient<IConfigureOptions<KeyManagementOptions>, ConfigureKeyManagementOptions>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 Microsoft.AspNetCore.DataProtection.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
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 ILoggerFactory _loggerFactory;
|
||||
private readonly Func<TContext> _contextFactory;
|
||||
|
||||
private ILogger<EntityFrameworkCoreXmlRepository<TContext>> _logger => _loggerFactory?.CreateLogger<EntityFrameworkCoreXmlRepository<TContext>>();
|
||||
|
||||
private TContext _context => _contextFactory?.Invoke();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EntityFrameworkCoreXmlRepository{TContext}"/>.
|
||||
/// </summary>
|
||||
/// <param name="contextFactory">The factory method that creates a context to store instances of <see cref="DataProtectionKey"/></param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public EntityFrameworkCoreXmlRepository(Func<TContext> contextFactory, ILoggerFactory loggerFactory = null)
|
||||
{
|
||||
_contextFactory = contextFactory ?? throw new ArgumentNullException(nameof(contextFactory));
|
||||
_loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IReadOnlyCollection<XElement> GetAllElements()
|
||||
=> _context?.Set<DataProtectionKey>()?.AsNoTracking().Select(key => TryParseKeyXml(key.Xml)).ToList().AsReadOnly();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void StoreElement(XElement element, string friendlyName)
|
||||
{
|
||||
var newKey = new DataProtectionKey()
|
||||
{
|
||||
FriendlyName = friendlyName,
|
||||
Xml = element.ToString(SaveOptions.DisableFormatting)
|
||||
};
|
||||
var context = _context;
|
||||
context?.Set<DataProtectionKey>()?.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>EntityFramworkCore storage support as key store.</Description>
|
||||
<VersionPrefix Condition="'$(ExperimentalVersionPrefix)' != ''">$(ExperimentalVersionPrefix)</VersionPrefix>
|
||||
<VersionSuffix Condition="'$(ExperimentalVersionSuffix)' != ''">$(ExperimentalVersionSuffix)</VersionSuffix>
|
||||
<VerifyVersion Condition="'$(ExperimentalVersionPrefix)' != ''">false</VerifyVersion>
|
||||
<PackageVersion>$(ExperimentalPackageVersion)</PackageVersion>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageTags>aspnetcore;dataprotection;entityframeworkcore</PackageTags>
|
||||
<EnableApiCheck>false</EnableApiCheck>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.DataProtection\Microsoft.AspNetCore.DataProtection.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 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.EntityFrameworkCore.Test;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.DataProtection
|
||||
{
|
||||
public class DataProtectionEntityFrameworkTests
|
||||
{
|
||||
[Fact]
|
||||
public void CreateRepository_ThrowsIf_ContextIsNull()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StoreElement_PersistsData()
|
||||
{
|
||||
var element = XElement.Parse("<Element1/>");
|
||||
var friendlyName = "Element1";
|
||||
var key = new DataProtectionKey() { FriendlyName = friendlyName, Xml = element.ToString() };
|
||||
using (var context = BuildDataProtectionKeyContext(nameof(StoreElement_PersistsData)))
|
||||
{
|
||||
var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(() => context);
|
||||
service.StoreElement(element, friendlyName);
|
||||
}
|
||||
// Use a separate instance of the context to verify correct data was saved to database
|
||||
using (var context = BuildDataProtectionKeyContext(nameof(StoreElement_PersistsData)))
|
||||
{
|
||||
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/>");
|
||||
using (var context = BuildDataProtectionKeyContext(nameof(GetAllElements_ReturnsAllElements)))
|
||||
{
|
||||
var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(() => context);
|
||||
service.StoreElement(element1, "element1");
|
||||
service.StoreElement(element2, "element2");
|
||||
}
|
||||
// Use a separate instance of the context to verify correct data was saved to database
|
||||
using (var context = BuildDataProtectionKeyContext(nameof(GetAllElements_ReturnsAllElements)))
|
||||
{
|
||||
var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(() => context);
|
||||
var elements = service.GetAllElements();
|
||||
Assert.Equal(2, elements.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private DbContextOptions<DataProtectionKeyContext> BuildDbContextOptions(string databaseName)
|
||||
=> new DbContextOptionsBuilder<DataProtectionKeyContext>().UseInMemoryDatabase(databaseName: databaseName).Options;
|
||||
|
||||
private DataProtectionKeyContext BuildDataProtectionKeyContext(string databaseName)
|
||||
=> new DataProtectionKeyContext(BuildDbContextOptions(databaseName));
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
var keyManagementOptions = serviceProvider.GetRequiredService<IOptions<KeyManagementOptions>>();
|
||||
Assert.IsType<EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>>(keyManagementOptions.Value.XmlRepository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
Loading…
Reference in New Issue