コード例 #1
0
    public void StoreElement_WithInvalidFriendlyName_CreatesNewGuidAsName(string friendlyName)
    {
        WithUniqueTempDirectory(dirInfo =>
        {
            // Arrange
            var element    = XElement.Parse("<element1 />");
            var repository = new FileSystemXmlRepository(dirInfo, NullLoggerFactory.Instance);

            // Act
            repository.StoreElement(element, friendlyName);

            // Assert
            var fileInfos = dirInfo.GetFiles();
            var fileInfo  = fileInfos.Single(); // only one file should've been created

            // filename should be "{GUID}.xml"
            var filename = fileInfo.Name;
            Assert.EndsWith(".xml", filename, StringComparison.OrdinalIgnoreCase);
            var filenameNoSuffix = filename.Substring(0, filename.Length - ".xml".Length);
            Guid parsedGuid      = Guid.Parse(filenameNoSuffix, CultureInfo.InvariantCulture);
            Assert.NotEqual(Guid.Empty, parsedGuid);

            // file contents should be "<element1 />"
            var parsedElement = XElement.Parse(File.ReadAllText(fileInfo.FullName));
            XmlAssert.Equal("<element1 />", parsedElement);
        });
    }
コード例 #2
0
    public void GetAllElements_EmptyOrNonexistentDirectory_ReturnsEmptyCollection()
    {
        WithUniqueTempDirectory(dirInfo =>
        {
            // Arrange
            var repository = new FileSystemXmlRepository(dirInfo, NullLoggerFactory.Instance);

            // Act
            var allElements = repository.GetAllElements();

            // Assert
            Assert.Equal(0, allElements.Count);
        });
    }
コード例 #3
0
    public void Directory_Property()
    {
        WithUniqueTempDirectory(dirInfo =>
        {
            // Arrange
            var repository = new FileSystemXmlRepository(dirInfo, NullLoggerFactory.Instance);

            // Act
            var retVal = repository.Directory;

            // Assert
            Assert.Equal(dirInfo, retVal);
        });
    }
コード例 #4
0
    public void Logs_DockerEphemeralFolders()
    {
        // Arrange
        var loggerFactory = new StringLoggerFactory(LogLevel.Warning);

        WithUniqueTempDirectory(dirInfo =>
        {
            // Act
            var repo = new FileSystemXmlRepository(dirInfo, loggerFactory);

            // Assert
            Assert.Contains(Resources.FormatFileSystem_EphemeralKeysLocationInContainer(dirInfo.FullName), loggerFactory.ToString());
        });
    }
コード例 #5
0
    public void StoreElements_ThenRetrieve_SeesAllElements()
    {
        WithUniqueTempDirectory(dirInfo =>
        {
            // Arrange
            var repository = new FileSystemXmlRepository(dirInfo, NullLoggerFactory.Instance);

            // Act
            repository.StoreElement(new XElement("element1"), friendlyName: null);
            repository.StoreElement(new XElement("element2"), friendlyName: null);
            repository.StoreElement(new XElement("element3"), friendlyName: null);
            var allElements = repository.GetAllElements();

            // Assert
            var orderedNames = allElements.Select(el => el.Name.LocalName).OrderBy(name => name);
            Assert.Equal(new[] { "element1", "element2", "element3" }, orderedNames);
        });
    }
コード例 #6
0
        /// <summary>
        /// https://github.com/dotnet/aspnetcore/blob/d8906c8523f071371ce95d4e2d2fdfa89858047e/src/DataProtection/DataProtection/src/KeyManagement/XmlKeyManager.cs#L105
        /// </summary>
        /// <returns></returns>
        internal IXmlRepository GetFallbackKeyRepositoryEncryptorPair()
        {
            IXmlRepository key;
            var            forAzureWebSites = DefaultKeyStorageDirectories.Instance.GetKeyStorageDirectoryForAzureWebSites();

            if (forAzureWebSites != null)
            {
                key = new FileSystemXmlRepository(forAzureWebSites, this._loggerFactory);
            }
            else
            {
                var storageDirectory = DefaultKeyStorageDirectories.Instance.GetKeyStorageDirectory();
                if (storageDirectory != null)
                {
                    key = new FileSystemXmlRepository(storageDirectory, this._loggerFactory);
                }
                else
                {
                    RegistryKey registryKey = null;
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        registryKey = RegistryXmlRepository.DefaultRegistryKey;
                    }

                    if (registryKey != null)
                    {
                        var defaultRegistryKey = RegistryXmlRepository.DefaultRegistryKey;
                        key = new RegistryXmlRepository(defaultRegistryKey, this._loggerFactory);
                    }
                    else
                    {
                        throw new Exception(
                                  "Is not possible to determine which folder are the protection keys. NetDevPack.Security.JwtSigningCredentials.Store.FileSystem or NetDevPack.Security.JwtSigningCredentials.Store.EntityFrameworkCore");
                    }
                }
            }
            return(key);
        }
コード例 #7
0
    public void StoreElement_WithValidFriendlyName_UsesFriendlyName()
    {
        WithUniqueTempDirectory(dirInfo =>
        {
            // Arrange
            var element    = XElement.Parse("<element1 />");
            var repository = new FileSystemXmlRepository(dirInfo, NullLoggerFactory.Instance);

            // Act
            repository.StoreElement(element, "valid-friendly-name");

            // Assert
            var fileInfos = dirInfo.GetFiles();
            var fileInfo  = fileInfos.Single(); // only one file should've been created

            // filename should be "valid-friendly-name.xml"
            Assert.Equal("valid-friendly-name.xml", fileInfo.Name, StringComparer.OrdinalIgnoreCase);

            // file contents should be "<element1 />"
            var parsedElement = XElement.Parse(File.ReadAllText(fileInfo.FullName));
            XmlAssert.Equal("<element1 />", parsedElement);
        });
    }
コード例 #8
0
ファイル: XmlKeyManager.cs プロジェクト: zzl1010/aspnetcore
        internal KeyValuePair <IXmlRepository, IXmlEncryptor> GetFallbackKeyRepositoryEncryptorPair()
        {
            IXmlRepository repository = null;
            IXmlEncryptor  encryptor  = null;

            // If we're running in Azure Web Sites, the key repository goes in the %HOME% directory.
            var azureWebSitesKeysFolder = _keyStorageDirectories.GetKeyStorageDirectoryForAzureWebSites();

            if (azureWebSitesKeysFolder != null)
            {
                _logger.UsingAzureAsKeyRepository(azureWebSitesKeysFolder.FullName);

                // Cloud DPAPI isn't yet available, so we don't encrypt keys at rest.
                // This isn't all that different than what Azure Web Sites does today, and we can always add this later.
                repository = new FileSystemXmlRepository(azureWebSitesKeysFolder, _loggerFactory);
            }
            else
            {
                // If the user profile is available, store keys in the user profile directory.
                var localAppDataKeysFolder = _keyStorageDirectories.GetKeyStorageDirectory();
                if (localAppDataKeysFolder != null)
                {
                    if (OSVersionUtil.IsWindows())
                    {
                        Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); // Hint for the platform compatibility analyzer.

                        // If the user profile is available, we can protect using DPAPI.
                        // Probe to see if protecting to local user is available, and use it as the default if so.
                        encryptor = new DpapiXmlEncryptor(
                            protectToLocalMachine: !DpapiSecretSerializerHelper.CanProtectToCurrentUserAccount(),
                            loggerFactory: _loggerFactory);
                    }
                    repository = new FileSystemXmlRepository(localAppDataKeysFolder, _loggerFactory);

                    if (encryptor != null)
                    {
                        _logger.UsingProfileAsKeyRepositoryWithDPAPI(localAppDataKeysFolder.FullName);
                    }
                    else
                    {
                        _logger.UsingProfileAsKeyRepository(localAppDataKeysFolder.FullName);
                    }
                }
                else
                {
                    // Use profile isn't available - can we use the HKLM registry?
                    RegistryKey regKeyStorageKey = null;
                    if (OSVersionUtil.IsWindows())
                    {
                        Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); // Hint for the platform compatibility analyzer.
                        regKeyStorageKey = RegistryXmlRepository.DefaultRegistryKey;
                    }
                    if (regKeyStorageKey != null)
                    {
                        Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); // Hint for the platform compatibility analyzer.
                        regKeyStorageKey = RegistryXmlRepository.DefaultRegistryKey;

                        // If the user profile isn't available, we can protect using DPAPI (to machine).
                        encryptor  = new DpapiXmlEncryptor(protectToLocalMachine: true, loggerFactory: _loggerFactory);
                        repository = new RegistryXmlRepository(regKeyStorageKey, _loggerFactory);

                        _logger.UsingRegistryAsKeyRepositoryWithDPAPI(regKeyStorageKey.Name);
                    }
                    else
                    {
                        // Final fallback - use an ephemeral repository since we don't know where else to go.
                        // This can only be used for development scenarios.
                        repository = new EphemeralXmlRepository(_loggerFactory);

                        _logger.UsingEphemeralKeyRepository();
                    }
                }
            }

            return(new KeyValuePair <IXmlRepository, IXmlEncryptor>(repository, encryptor));
        }
コード例 #9
0
        /// <summary>
        /// Returns a collection of default <see cref="ServiceDescriptor"/> instances that can be
        /// used to bootstrap the Data Protection system.
        /// </summary>
        public static IEnumerable <ServiceDescriptor> GetDefaultServices()
        {
            // The default key services are a strange beast. We don't want to return
            // IXmlEncryptor and IXmlRepository as-is because they almost always have to be
            // set as a matched pair. Instead, our built-in key manager will use a meta-service
            // which represents the default pairing (logic based on hosting environment as
            // demonstrated below), and if the developer explicitly specifies one or the other
            // we'll not use the fallback at all.
            yield return(ServiceDescriptor.Singleton <IDefaultKeyServices>(services =>
            {
                var log = services.GetLogger(typeof(DataProtectionServices));

                ServiceDescriptor keyEncryptorDescriptor = null;
                ServiceDescriptor keyRepositoryDescriptor = null;

                // If we're running in Azure Web Sites, the key repository goes in the %HOME% directory.
                var azureWebSitesKeysFolder = FileSystemXmlRepository.GetKeyStorageDirectoryForAzureWebSites();
                if (azureWebSitesKeysFolder != null)
                {
                    log?.UsingAzureAsKeyRepository(azureWebSitesKeysFolder.FullName);

                    // Cloud DPAPI isn't yet available, so we don't encrypt keys at rest.
                    // This isn't all that different than what Azure Web Sites does today, and we can always add this later.
                    keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_FileSystem(azureWebSitesKeysFolder);
                }
                else
                {
                    // If the user profile is available, store keys in the user profile directory.
                    var localAppDataKeysFolder = FileSystemXmlRepository.DefaultKeyStorageDirectory;
                    if (localAppDataKeysFolder != null)
                    {
                        if (OSVersionUtil.IsWindows())
                        {
                            // If the user profile is available, we can protect using DPAPI.
                            // Probe to see if protecting to local user is available, and use it as the default if so.
                            keyEncryptorDescriptor = DataProtectionServiceDescriptors.IXmlEncryptor_Dpapi(protectToMachine: !DpapiSecretSerializerHelper.CanProtectToCurrentUserAccount());
                        }
                        keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_FileSystem(localAppDataKeysFolder);

                        if (keyEncryptorDescriptor != null)
                        {
                            log?.UsingProfileAsKeyRepositoryWithDPAPI(localAppDataKeysFolder.FullName);
                        }
                        else
                        {
                            log?.UsingProfileAsKeyRepository(localAppDataKeysFolder.FullName);
                        }
                    }
                    else
                    {
                        // Use profile isn't available - can we use the HKLM registry?
                        RegistryKey regKeyStorageKey = null;
                        if (OSVersionUtil.IsWindows())
                        {
                            regKeyStorageKey = RegistryXmlRepository.DefaultRegistryKey;
                        }
                        if (regKeyStorageKey != null)
                        {
                            // If the user profile isn't available, we can protect using DPAPI (to machine).
                            keyEncryptorDescriptor = DataProtectionServiceDescriptors.IXmlEncryptor_Dpapi(protectToMachine: true);
                            keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_Registry(regKeyStorageKey);

                            log?.UsingRegistryAsKeyRepositoryWithDPAPI(regKeyStorageKey.Name);
                        }
                        else
                        {
                            // Final fallback - use an ephemeral repository since we don't know where else to go.
                            // This can only be used for development scenarios.
                            keyRepositoryDescriptor = ServiceDescriptor.Singleton <IXmlRepository>(
                                s => new EphemeralXmlRepository(s));

                            log?.UsingEphemeralKeyRepository();
                        }
                    }
                }

                return new DefaultKeyServices(
                    services: services,
                    keyEncryptorDescriptor: keyEncryptorDescriptor,
                    keyRepositoryDescriptor: keyRepositoryDescriptor);
            }));

            // Provide root key management and data protection services
            yield return(ServiceDescriptor.Singleton <IKeyManager>(services => new XmlKeyManager(services)));

            yield return(ServiceDescriptor.Singleton <IDataProtectionProvider>(
                             services => DataProtectionProviderFactory.GetProviderFromServices(
                                 options: services.GetRequiredService <IOptions <DataProtectionOptions> >().Value,
                                 services: services,
                                 mustCreateImmediately: true /* this is the ultimate fallback */)));

            // Provide services required for XML encryption
#if !NETSTANDARD1_3 // [[ISSUE60]] Remove this #ifdef when Core CLR gets support for EncryptedXml
            yield return(DataProtectionServiceDescriptors.ICertificateResolver_Default());
#endif

            // Hook up the logic which allows populating default options
            yield return(ServiceDescriptor.Transient <IConfigureOptions <DataProtectionOptions> >(services =>
            {
                return new ConfigureOptions <DataProtectionOptions>(options =>
                {
                    options.ApplicationDiscriminator = services.GetApplicationUniqueIdentifier();
                });
            }));

            // Read and apply policy from the registry, overriding any other defaults.
            var encryptorConfigurationReadFromRegistry = false;
            if (OSVersionUtil.IsWindows())
            {
                foreach (var descriptor in RegistryPolicyResolver.ResolveDefaultPolicy())
                {
                    yield return(descriptor);

                    if (descriptor.ServiceType == typeof(IAuthenticatedEncryptorConfiguration))
                    {
                        encryptorConfigurationReadFromRegistry = true;
                    }
                }
            }

            // Finally, provide a fallback encryptor configuration if one wasn't already specified.
            if (!encryptorConfigurationReadFromRegistry)
            {
                yield return(DataProtectionServiceDescriptors.IAuthenticatedEncryptorConfiguration_FromSettings(
                                 new AuthenticatedEncryptionSettings()));;
            }
        }
コード例 #10
0
        /// <summary>
        /// Returns a collection of default <see cref="ServiceDescriptor"/> instances that can be
        /// used to bootstrap the Data Protection system.
        /// </summary>
        public static IEnumerable <ServiceDescriptor> GetDefaultServices()
        {
            // The default key services are a strange beast. We don't want to return
            // IXmlEncryptor and IXmlRepository as-is because they almost always have to be
            // set as a matched pair. Instead, our built-in key manager will use a meta-service
            // which represents the default pairing (logic based on hosting environment as
            // demonstrated below), and if the developer explicitly specifies one or the other
            // we'll not use the fallback at all.
            yield return(ServiceDescriptor.Singleton <IDefaultKeyServices>(services =>
            {
                ILogger log = services.GetLogger(typeof(DataProtectionServices));

                ServiceDescriptor keyEncryptorDescriptor = null;
                ServiceDescriptor keyRepositoryDescriptor = null;

                // If we're running in Azure Web Sites, the key repository goes in the %HOME% directory.
                var azureWebSitesKeysFolder = FileSystemXmlRepository.GetKeyStorageDirectoryForAzureWebSites();
                if (azureWebSitesKeysFolder != null)
                {
                    if (log.IsInformationLevelEnabled())
                    {
                        log.LogInformationF($"Azure Web Sites environment detected. Using '{azureWebSitesKeysFolder.FullName}' as key repository; keys will not be encrypted at rest.");
                    }

                    // Cloud DPAPI isn't yet available, so we don't encrypt keys at rest.
                    // This isn't all that different than what Azure Web Sites does today, and we can always add this later.
                    keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_FileSystem(azureWebSitesKeysFolder);
                }
                else
                {
                    // If the user profile is available, store keys in the user profile directory.
                    var localAppDataKeysFolder = FileSystemXmlRepository.DefaultKeyStorageDirectory;
                    if (localAppDataKeysFolder != null)
                    {
                        if (OSVersionUtil.IsWindows())
                        {
                            // If the user profile is available, we can protect using DPAPI.
                            // Probe to see if protecting to local user is available, and use it as the default if so.
                            keyEncryptorDescriptor = DataProtectionServiceDescriptors.IXmlEncryptor_Dpapi(protectToMachine: !DpapiSecretSerializerHelper.CanProtectToCurrentUserAccount());
                        }
                        keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_FileSystem(localAppDataKeysFolder);

                        if (log.IsInformationLevelEnabled())
                        {
                            if (keyEncryptorDescriptor != null)
                            {
                                log.LogInformationF($"User profile is available. Using '{localAppDataKeysFolder.FullName}' as key repository and Windows DPAPI to encrypt keys at rest.");
                            }
                            else
                            {
                                log.LogInformationF($"User profile is available. Using '{localAppDataKeysFolder.FullName}' as key repository; keys will not be encrypted at rest.");
                            }
                        }
                    }
                    else
                    {
                        // Use profile isn't available - can we use the HKLM registry?
                        RegistryKey regKeyStorageKey = null;
                        if (OSVersionUtil.IsWindows())
                        {
                            regKeyStorageKey = RegistryXmlRepository.DefaultRegistryKey;
                        }
                        if (regKeyStorageKey != null)
                        {
                            // If the user profile isn't available, we can protect using DPAPI (to machine).
                            keyEncryptorDescriptor = DataProtectionServiceDescriptors.IXmlEncryptor_Dpapi(protectToMachine: true);
                            keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_Registry(regKeyStorageKey);

                            if (log.IsInformationLevelEnabled())
                            {
                                log.LogInformationF($"User profile not available. Using '{regKeyStorageKey.Name}' as key repository and Windows DPAPI to encrypt keys at rest.");
                            }
                        }
                        else
                        {
                            // Final fallback - use an ephemeral repository since we don't know where else to go.
                            // This can only be used for development scenarios.
                            keyRepositoryDescriptor = DataProtectionServiceDescriptors.IXmlRepository_InMemory();

                            if (log.IsWarningLevelEnabled())
                            {
                                log.LogWarning("Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.");
                            }
                        }
                    }
                }

                return new DefaultKeyServices(
                    services: services,
                    keyEncryptorDescriptor: keyEncryptorDescriptor,
                    keyRepositoryDescriptor: keyRepositoryDescriptor);
            }));

            // Provide root key management and data protection services
            yield return(DataProtectionServiceDescriptors.IKeyManager_Default());

            yield return(DataProtectionServiceDescriptors.IDataProtectionProvider_Default());

            // Provide services required for XML encryption
#if !DOTNET5_4 // [[ISSUE60]] Remove this #ifdef when Core CLR gets support for EncryptedXml
            yield return(DataProtectionServiceDescriptors.ICertificateResolver_Default());
#endif

            // Hook up the logic which allows populating default options
            yield return(DataProtectionServiceDescriptors.ConfigureOptions_DataProtectionOptions());

            // Read and apply policy from the registry, overriding any other defaults.
            bool encryptorConfigurationReadFromRegistry = false;
            if (OSVersionUtil.IsWindows())
            {
                foreach (var descriptor in RegistryPolicyResolver.ResolveDefaultPolicy())
                {
                    yield return(descriptor);

                    if (descriptor.ServiceType == typeof(IAuthenticatedEncryptorConfiguration))
                    {
                        encryptorConfigurationReadFromRegistry = true;
                    }
                }
            }

            // Finally, provide a fallback encryptor configuration if one wasn't already specified.
            if (!encryptorConfigurationReadFromRegistry)
            {
                yield return(DataProtectionServiceDescriptors.IAuthenticatedEncryptorConfiguration_Default());
            }
        }