| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- // 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.Reflection;
- using System.Runtime.InteropServices;
- using System.Security.Cryptography.X509Certificates;
- using Microsoft.AspNetCore.DataProtection.Repositories;
- using Microsoft.AspNetCore.DataProtection.Test.Shared;
- using Microsoft.AspNetCore.Testing.xunit;
- using Xunit;
- namespace Microsoft.AspNetCore.DataProtection
- {
- public class DataProtectionProviderTests
- {
- [Fact]
- public void System_UsesProvidedDirectory()
- {
- WithUniqueTempDirectory(directory =>
- {
- // Step 1: directory should be completely empty
- directory.Create();
- Assert.Empty(directory.GetFiles());
- // Step 2: instantiate the system and round-trip a payload
- var protector = DataProtectionProvider.Create(directory).CreateProtector("purpose");
- Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));
- // Step 3: validate that there's now a single key in the directory and that it's not protected
- var allFiles = directory.GetFiles();
- Assert.Equal(1, allFiles.Length);
- Assert.StartsWith("key-", allFiles[0].Name, StringComparison.OrdinalIgnoreCase);
- string fileText = File.ReadAllText(allFiles[0].FullName);
- Assert.Contains("Warning: the key below is in an unencrypted form.", fileText, StringComparison.Ordinal);
- Assert.DoesNotContain("Windows DPAPI", fileText, StringComparison.Ordinal);
- });
- }
- [Fact]
- public void System_NoKeysDirectoryProvided_UsesDefaultKeysDirectory()
- {
- Assert.NotNull(FileSystemXmlRepository.DefaultKeyStorageDirectory);
- var keysPath = FileSystemXmlRepository.DefaultKeyStorageDirectory.FullName;
- var tempPath = FileSystemXmlRepository.DefaultKeyStorageDirectory.FullName + "Temp";
- try
- {
- // Step 1: Move the current contents, if any, to a temporary directory.
- if (Directory.Exists(keysPath))
- {
- Directory.Move(keysPath, tempPath);
- }
- // Step 2: Instantiate the system and round-trip a payload
- var protector = DataProtectionProvider.Create("TestApplication").CreateProtector("purpose");
- Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));
- // Step 3: Validate that there's now a single key in the directory
- var newFileName = Assert.Single(Directory.GetFiles(keysPath));
- var file = new FileInfo(newFileName);
- Assert.StartsWith("key-", file.Name, StringComparison.OrdinalIgnoreCase);
- var fileText = File.ReadAllText(file.FullName);
- // On Windows, validate that it's protected using Windows DPAPI.
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- Assert.DoesNotContain("Warning: the key below is in an unencrypted form.", fileText, StringComparison.Ordinal);
- Assert.Contains("This key is encrypted with Windows DPAPI.", fileText, StringComparison.Ordinal);
- }
- else
- {
- Assert.Contains("Warning: the key below is in an unencrypted form.", fileText, StringComparison.Ordinal);
- }
- }
- finally
- {
- if (Directory.Exists(keysPath))
- {
- Directory.Delete(keysPath, recursive: true);
- }
- if (Directory.Exists(tempPath))
- {
- Directory.Move(tempPath, keysPath);
- }
- }
- }
- [ConditionalFact]
- [ConditionalRunTestOnlyOnWindows]
- public void System_UsesProvidedDirectory_WithConfigurationCallback()
- {
- WithUniqueTempDirectory(directory =>
- {
- // Step 1: directory should be completely empty
- directory.Create();
- Assert.Empty(directory.GetFiles());
- // Step 2: instantiate the system and round-trip a payload
- var protector = DataProtectionProvider.Create(directory, configure =>
- {
- configure.ProtectKeysWithDpapi();
- }).CreateProtector("purpose");
- Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));
- // Step 3: validate that there's now a single key in the directory and that it's protected with DPAPI
- var allFiles = directory.GetFiles();
- Assert.Equal(1, allFiles.Length);
- Assert.StartsWith("key-", allFiles[0].Name, StringComparison.OrdinalIgnoreCase);
- string fileText = File.ReadAllText(allFiles[0].FullName);
- Assert.DoesNotContain("Warning: the key below is in an unencrypted form.", fileText, StringComparison.Ordinal);
- Assert.Contains("Windows DPAPI", fileText, StringComparison.Ordinal);
- });
- }
- [Fact]
- public void System_UsesProvidedDirectoryAndCertificate()
- {
- var filePath = Path.Combine(GetTestFilesPath(), "TestCert.pfx");
- var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
- store.Open(OpenFlags.ReadWrite);
- store.Add(new X509Certificate2(filePath, "password", X509KeyStorageFlags.Exportable));
- store.Close();
- WithUniqueTempDirectory(directory =>
- {
- var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
- certificateStore.Open(OpenFlags.ReadWrite);
- var certificate = certificateStore.Certificates.Find(X509FindType.FindBySubjectName, "TestCert", false)[0];
- try
- {
- // Step 1: directory should be completely empty
- directory.Create();
- Assert.Empty(directory.GetFiles());
- // Step 2: instantiate the system and round-trip a payload
- var protector = DataProtectionProvider.Create(directory, certificate).CreateProtector("purpose");
- Assert.Equal("payload", protector.Unprotect(protector.Protect("payload")));
- // Step 3: validate that there's now a single key in the directory and that it's is protected using the certificate
- var allFiles = directory.GetFiles();
- Assert.Equal(1, allFiles.Length);
- Assert.StartsWith("key-", allFiles[0].Name, StringComparison.OrdinalIgnoreCase);
- string fileText = File.ReadAllText(allFiles[0].FullName);
- Assert.DoesNotContain("Warning: the key below is in an unencrypted form.", fileText, StringComparison.Ordinal);
- Assert.Contains("X509Certificate", fileText, StringComparison.Ordinal);
- }
- finally
- {
- certificateStore.Remove(certificate);
- certificateStore.Close();
- }
- });
- }
- /// <summary>
- /// Runs a test and cleans up the temp directory afterward.
- /// </summary>
- private static void WithUniqueTempDirectory(Action<DirectoryInfo> testCode)
- {
- string uniqueTempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
- var dirInfo = new DirectoryInfo(uniqueTempPath);
- try
- {
- testCode(dirInfo);
- }
- finally
- {
- // clean up when test is done
- if (dirInfo.Exists)
- {
- dirInfo.Delete(recursive: true);
- }
- }
- }
- private static string GetTestFilesPath()
- {
- var projectName = typeof(DataProtectionProviderTests).GetTypeInfo().Assembly.GetName().Name;
- var projectPath = RecursiveFind(projectName, Path.GetFullPath("."));
- return Path.Combine(projectPath, projectName, "TestFiles");
- }
- private static string RecursiveFind(string path, string start)
- {
- var test = Path.Combine(start, path);
- if (Directory.Exists(test))
- {
- return start;
- }
- else
- {
- return RecursiveFind(path, new DirectoryInfo(start).Parent.FullName);
- }
- }
- }
- }
|