// 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.Cryptography; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.Repositories; using Microsoft.AspNetCore.DataProtection.XmlEncryption; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.DataProtection.KeyManagement { internal sealed class DefaultKeyServices : IDefaultKeyServices { private readonly Lazy _keyEncryptorLazy; private readonly Lazy _keyRepositoryLazy; public DefaultKeyServices(IServiceProvider services, ServiceDescriptor keyEncryptorDescriptor, ServiceDescriptor keyRepositoryDescriptor) { if (keyEncryptorDescriptor != null) { // optional CryptoUtil.Assert(keyEncryptorDescriptor.ServiceType == typeof(IXmlEncryptor), "Bad service type."); _keyEncryptorLazy = GetLazyForService(services, keyEncryptorDescriptor); } CryptoUtil.Assert(keyRepositoryDescriptor.ServiceType == typeof(IXmlRepository), "Bad service type."); _keyRepositoryLazy = GetLazyForService(services, keyRepositoryDescriptor); } /// /// Gets the default service (could return null). /// /// public IXmlEncryptor GetKeyEncryptor() { return (IXmlEncryptor)_keyEncryptorLazy?.Value; } /// /// Gets the default service (must not be null). /// /// public IXmlRepository GetKeyRepository() { return (IXmlRepository)_keyRepositoryLazy.Value ?? CryptoUtil.Fail("GetKeyRepository returned null."); } private static Lazy GetLazyForService(IServiceProvider services, ServiceDescriptor descriptor) { CryptoUtil.Assert(descriptor != null && descriptor.Lifetime == ServiceLifetime.Singleton, "Descriptor must represent singleton."); CryptoUtil.Assert(descriptor.ImplementationFactory != null, "Descriptor must have an implementation factory."); // pull the factory out so we don't close over the whole descriptor instance Func wrapped = descriptor.ImplementationFactory; return new Lazy(() => wrapped(services)); } } }