/// <summary> /// An <see cref="IDataProtectionProvider"/> backed by the default keyring. /// </summary> public static ServiceDescriptor IDataProtectionProvider_Default() { return(ServiceDescriptor.Singleton <IDataProtectionProvider>( services => DataProtectionProviderFactory.GetProviderFromServices( options: services.GetRequiredService <IOptions <DataProtectionOptions> >().Value, services: services, mustCreateImmediately: true /* this is the ultimate fallback */))); }
/// <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()));; } }