Inheritance: IAsyncKeyVaultConfiguration
        public async Task HandlesKeyVaultExceptionAsNullWhenMissingInKeyVault()
        {
            Mock<IKeyVault> keyVault = new Mock<IKeyVault>();
            Mock<IKeyVaultConfigurationKeyEncoder> keyVaultEncoder = new Mock<IKeyVaultConfigurationKeyEncoder>();
            Mock<IAsyncConfiguration> asyncConfiguration = new Mock<IAsyncConfiguration>();

            keyVaultEncoder.Setup(x => x.Encode("mykey")).Returns("mykey");
            asyncConfiguration.Setup(x => x.GetAsync("mykey")).ReturnsAsync(null);
            keyVault.Setup(x => x.GetSecretAsync("mykey")).Throws(new AggregateException(new KeyVaultClientException(HttpStatusCode.NotFound, new Uri("http://localhost"))));

            AsyncKeyVaultConfiguration asyncKeyVaultConfiguration = new AsyncKeyVaultConfiguration(keyVault.Object, keyVaultEncoder.Object, KeyVaultConfigurationCachePolicy.Default, asyncConfiguration.Object);

            string result = await asyncKeyVaultConfiguration.GetAsync("mykey");
            Assert.IsNull(result);
        }
        public async Task GetsFromKeyVaultWhenMissingLocally()
        {
            Mock<IKeyVault> keyVault = new Mock<IKeyVault>();
            Mock<IKeyVaultConfigurationKeyEncoder> keyVaultEncoder = new Mock<IKeyVaultConfigurationKeyEncoder>();
            Mock<IAsyncConfiguration> asyncConfiguration = new Mock<IAsyncConfiguration>();

            keyVaultEncoder.Setup(x => x.Encode("mykey")).Returns("mykey");
            asyncConfiguration.Setup(x => x.GetAsync("mykey")).ReturnsAsync(null);
            keyVault.Setup(x => x.GetSecretAsync("mykey")).ReturnsAsync("keyvaultvalue");

            AsyncKeyVaultConfiguration asyncKeyVaultConfiguration = new AsyncKeyVaultConfiguration(keyVault.Object, keyVaultEncoder.Object, KeyVaultConfigurationCachePolicy.Default, asyncConfiguration.Object);

            string result = await asyncKeyVaultConfiguration.GetAsync("mykey");
            Assert.AreEqual("keyvaultvalue", result);
        }
        public async Task GetsFromCache()
        {
            Mock<IKeyVault> keyVault = new Mock<IKeyVault>();
            Mock<IKeyVaultConfigurationKeyEncoder> keyVaultEncoder = new Mock<IKeyVaultConfigurationKeyEncoder>();
            Mock<IAsyncConfiguration> asyncConfiguration = new Mock<IAsyncConfiguration>();

            keyVaultEncoder.Setup(x => x.Encode("mykey")).Returns("mykey");
            asyncConfiguration.Setup(x => x.GetAsync("mykey")).ReturnsAsync("incache");
            
            AsyncKeyVaultConfiguration asyncKeyVaultConfiguration = new AsyncKeyVaultConfiguration(keyVault.Object, keyVaultEncoder.Object, KeyVaultConfigurationCachePolicy.Default, asyncConfiguration.Object);

            await asyncKeyVaultConfiguration.GetAsync("mykey");
            string result = await asyncKeyVaultConfiguration.GetAsync("mykey");
            Assert.AreEqual("incache", result);
            asyncConfiguration.Verify(x => x.GetAsync("mykey"), Times.AtMostOnce);
        }
        protected override async Task ProcessRecordAsync()
        {
            WriteVerbose($"Processing configuration file {Configuration}");
            if (!File.Exists(Configuration))
            {
                throw new InvalidOperationException("Configuration file does not exist");
            }

            IAsyncConfiguration secretStore = null;
            bool useKeyVault = !string.IsNullOrWhiteSpace(KeyVaultClientId) && !string.IsNullOrWhiteSpace(KeyVaultClientKey) && !string.IsNullOrWhiteSpace(KeyVaultUri);
            KeyVault keyVault = new KeyVault(KeyVaultClientId, KeyVaultClientKey, KeyVaultUri, true);
            KeyVaultConfigurationKeyEncoder keyEncoder = new KeyVaultConfigurationKeyEncoder();

            if (useKeyVault)
            {
                secretStore = new AsyncKeyVaultConfiguration(
                    keyVault,
                    keyEncoder,
                    null);
            }

                WriteVerbose("Reading settings");
                ApplicationConfigurationSettings settings = Settings != null && Settings.Length > 0
                    ? ApplicationConfigurationSettings.FromFiles(Settings)
                    : null;
                WriteVerbose("Reading configuration");
                ApplicationConfiguration configuration = await ApplicationConfiguration.FromFileAsync(Configuration, settings,
                    CheckForMissingSettings, secretStore, WriteVerbose);

                ApplyCorsRules(configuration);

                foreach (ApplicationComponent component in configuration.ApplicationComponents)
                {
                    if (component.UsesServiceBus)
                    {
                        WriteVerbose($"Creating service bus resources for component {component.Fqn}");
                        if (!String.IsNullOrWhiteSpace(component.DefaultTopicName))
                        {
                            NamespaceManager namespaceManager =
                                NamespaceManager.CreateFromConnectionString(component.ServiceBusConnectionString);

                            if (!namespaceManager.TopicExists(component.DefaultTopicName))
                            {
                                namespaceManager.CreateTopic(new TopicDescription(component.DefaultTopicName));
                            }

                            if (!String.IsNullOrWhiteSpace(component.DefaultSubscriptionName))
                            {
                                if (
                                    !namespaceManager.SubscriptionExists(component.DefaultTopicName,
                                        component.DefaultSubscriptionName))
                                {
                                    namespaceManager.CreateSubscription(
                                        new SubscriptionDescription(component.DefaultTopicName,
                                            component.DefaultSubscriptionName));
                                }
                            }
                        }

                        if (!String.IsNullOrWhiteSpace(component.DefaultBrokeredMessageQueueName))
                        {
                            NamespaceManager namespaceManager =
                                NamespaceManager.CreateFromConnectionString(component.ServiceBusConnectionString);
                            if (!namespaceManager.QueueExists(component.DefaultBrokeredMessageQueueName))
                            {
                                namespaceManager.CreateQueue(component.DefaultBrokeredMessageQueueName);
                            }
                        }

                        foreach (ApplicationComponentSetting setting in component.Settings)
                        {
                            string resourceType = setting.ResourceType;
                            if (resourceType != null)
                            {
                                resourceType = resourceType.ToLower();
                                if (resourceType == "topic")
                                {
                                    NamespaceManager namespaceManager =
                                        NamespaceManager.CreateFromConnectionString(component.ServiceBusConnectionString);
                                    if (!namespaceManager.TopicExists(setting.Value))
                                    {
                                        namespaceManager.CreateTopic(new TopicDescription(setting.Value));
                                    }
                                }
                                else if (resourceType == "subscription")
                                {
                                    NamespaceManager namespaceManager =
                                        NamespaceManager.CreateFromConnectionString(component.ServiceBusConnectionString);
                                    string topicPath = setting.Attributes["topic"];
                                    if (!namespaceManager.TopicExists(topicPath))
                                    {
                                        namespaceManager.CreateTopic(new TopicDescription(topicPath));
                                    }
                                    if (!namespaceManager.SubscriptionExists(topicPath, setting.Value))
                                    {
                                        namespaceManager.CreateSubscription(new SubscriptionDescription(topicPath,
                                            setting.Value));
                                    }
                                }
                                else if (resourceType == "brokered-message-queue")
                                {
                                    NamespaceManager namespaceManager =
                                        NamespaceManager.CreateFromConnectionString(component.ServiceBusConnectionString);
                                    if (!namespaceManager.QueueExists(setting.Value))
                                    {
                                        namespaceManager.CreateQueue(setting.Value);
                                    }
                                }
                            }
                        }
                    }

                    if (component.UsesAzureStorage)
                    {
                        CloudStorageAccount storageAccount =
                            CloudStorageAccount.Parse(component.StorageAccountConnectionString);
                        if (!string.IsNullOrWhiteSpace(component.DefaultBlobContainerName))
                        {
                            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                            CloudBlobContainer blobContainer =
                                blobClient.GetContainerReference(component.DefaultBlobContainerName);
                            blobContainer.CreateIfNotExists(
                                BlobContainerPublicAccessType(component.DefaultBlobContainerAccessType));

                            WriteVerbose($"Creating blob container {component.DefaultBlobContainerName} in {storageAccount.BlobEndpoint}");

                            if (component.Uploads != null)
                            {
                                foreach (string uploadFilename in component.Uploads)
                                {
                                    string fullUploadFilename = Path.Combine(Path.GetDirectoryName(Configuration),
                                        uploadFilename);
                                    CloudBlockBlob blob =
                                        blobContainer.GetBlockBlobReference(Path.GetFileName(uploadFilename));
                                    blob.UploadFromFile(fullUploadFilename, FileMode.Open);
                                    WriteVerbose($"Uploading file {uploadFilename} to blob container {component.DefaultBlobContainerName}");
                                }
                            }
                        }

                        if (!string.IsNullOrWhiteSpace(component.DefaultLeaseBlockName))
                        {
                            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                            CloudBlobContainer blobContainer =
                                blobClient.GetContainerReference(component.DefaultLeaseBlockName);
                            blobContainer.CreateIfNotExists(
                                BlobContainerPublicAccessType(component.DefaultBlobContainerAccessType));

                            WriteVerbose($"Creating lease block container {component.DefaultLeaseBlockName} in {storageAccount.BlobEndpoint}");
                        }

                        if (!string.IsNullOrWhiteSpace(component.DefaultQueueName))
                        {
                            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
                            CloudQueue queue = queueClient.GetQueueReference(component.DefaultQueueName);
                            queue.CreateIfNotExists();

                            WriteVerbose($"Creating queue {component.DefaultQueueName} in {storageAccount.QueueEndpoint}");
                        }

                        if (!string.IsNullOrWhiteSpace(component.DefaultTableName))
                        {
                            CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
                            CloudTable table = tableClient.GetTableReference(component.DefaultTableName);
                            table.CreateIfNotExists();

                            WriteVerbose($"Creating table {component.DefaultTableName} in {storageAccount.TableEndpoint}");

                            if (!string.IsNullOrWhiteSpace(component.TableData))
                            {
                                XDocument document;
                                string tableDataFilename = Path.Combine(Path.GetDirectoryName(Configuration),
                                    component.TableData);
                                try
                                {

                                    using (StreamReader reader = new StreamReader(tableDataFilename))
                                    {
                                        document = XDocument.Load(reader);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    document = null;
                                    WriteVerbose($"Unable to load table data document {tableDataFilename}. Error: {ex.Message}");
                                }
                                if (document != null)
                                {
                                    UploadTableData(table, document);
                                }
                            }
                        }


                        foreach (ApplicationComponentSetting setting in component.Settings)
                        {
                            string resourceType = setting.ResourceType;
                            if (resourceType != null)
                            {
                                resourceType = resourceType.ToLower();
                                if (resourceType == "table")
                                {
                                    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
                                    CloudTable table = tableClient.GetTableReference(setting.Value);
                                    table.CreateIfNotExists();

                                    WriteVerbose($"Creating table {setting.Value} in {storageAccount.TableEndpoint}");
                                }
                                else if (resourceType == "queue")
                                {
                                    CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
                                    CloudQueue queue = queueClient.GetQueueReference(setting.Value);
                                    queue.CreateIfNotExists();
                                    WriteVerbose($"Creating queue {setting.Value} in {storageAccount.TableEndpoint}");
                                }
                                else if (resourceType == "blob-container")
                                {
                                    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                                    CloudBlobContainer blobContainer = blobClient.GetContainerReference(setting.Value);
                                    blobContainer.CreateIfNotExists();
                                    WriteVerbose($"Creating blob container {setting.Value} in {storageAccount.TableEndpoint}");
                                }
                            }
                        }
                    }
                }
         
        }
        public async Task IgnoresCacheBasedOnPolicy()
        {
            Mock<IKeyVault> keyVault = new Mock<IKeyVault>();
            Mock<IKeyVaultConfigurationKeyEncoder> keyVaultEncoder = new Mock<IKeyVaultConfigurationKeyEncoder>();
            Mock<IAsyncConfiguration> asyncConfiguration = new Mock<IAsyncConfiguration>();

            keyVaultEncoder.Setup(x => x.Encode("mykey")).Returns("mykey");
            asyncConfiguration.Setup(x => x.GetAsync("mykey")).ReturnsAsync("incache");

            AsyncKeyVaultConfiguration asyncKeyVaultConfiguration = new AsyncKeyVaultConfiguration(
                keyVault.Object,
                keyVaultEncoder.Object, 
                new KeyVaultConfigurationCachePolicy
                {
                    CachingEnabled = false
                },
                asyncConfiguration.Object);

            await asyncKeyVaultConfiguration.GetAsync("mykey");
            string result = await asyncKeyVaultConfiguration.GetAsync("mykey");
            Assert.AreEqual("incache", result);
            asyncConfiguration.Verify(x => x.GetAsync("mykey"), Times.Exactly(2));
        }
        public async Task ExpiresItemsInCache()
        {
            Mock<IKeyVault> keyVault = new Mock<IKeyVault>();
            Mock<IKeyVaultConfigurationKeyEncoder> keyVaultEncoder = new Mock<IKeyVaultConfigurationKeyEncoder>();
            Mock<IAsyncConfiguration> asyncConfiguration = new Mock<IAsyncConfiguration>();

            keyVaultEncoder.Setup(x => x.Encode("mykey")).Returns("mykey");
            asyncConfiguration.Setup(x => x.GetAsync("mykey")).ReturnsAsync("incache");

            AsyncKeyVaultConfiguration asyncKeyVaultConfiguration = new AsyncKeyVaultConfiguration(
                keyVault.Object,
                keyVaultEncoder.Object,
                new KeyVaultConfigurationCachePolicy
                {
                    CachingEnabled = true,
                    ExpiresAfter = TimeSpan.FromMilliseconds(500)
                },
                asyncConfiguration.Object);

            await asyncKeyVaultConfiguration.GetAsync("mykey");
            await Task.Delay(TimeSpan.FromMilliseconds(600));
            string result = await asyncKeyVaultConfiguration.GetAsync("mykey");
            Assert.AreEqual("incache", result);
            asyncConfiguration.Verify(x => x.GetAsync("mykey"), Times.Exactly(2));
        }
        /// <summary>
        /// Use key vault for application configuration. This provides a secure way of retrieving secrets at runtime (connection strings, passwords etc.)
        /// </summary>
        /// <param name="dependencyResolver">The dependency resolver</param>
        /// <param name="clientId">Client ID of the Azure AD application associated with the key vault (must be granted read access to secrets)</param>
        /// <param name="clientSecret">Client secret of the Azure AD application associated with the key vault (must be granted read access to secrets)</param>
        /// <param name="vaultUri">The URI of the key vault e.g. https://mykeyvault.vault.azure.net</param>
        /// <param name="useKeyVaultExclusively">Defaults to false in which case only application keys not found in the local configuration (app settings, cscfg etc.) will be looked up in the vault. True if everything should be looked up in the vault.</param>
        /// <param name="checkIfKeyVaultKeyExistsBeforeGet">If true then this checks if the key exists in the vault before attempting a get. This is expensive but currently helps with Powershell sync context / message pump issues.</param>
        /// <param name="cachePolicy">The cache policy, null for the default policy</param>
        /// <returns>The dependency resolver confiugred with a key vault used for application configuration</returns>
        public static IDependencyResolver UseAsyncKeyVaultApplicationConfiguration(this IDependencyResolver dependencyResolver,
            string clientId,
            string clientSecret,
            string vaultUri,
            bool useKeyVaultExclusively = false,
            KeyVaultConfigurationCachePolicy cachePolicy = null,
            bool checkIfKeyVaultKeyExistsBeforeGet = false)
        {
            if (cachePolicy == null)
            {
                cachePolicy = KeyVaultConfigurationCachePolicy.Default;
            }

            IAsyncConfiguration existingConfiguration = null;
            if (!useKeyVaultExclusively)
            {
                existingConfiguration = dependencyResolver.Resolve<IAsyncConfiguration>();
            }
            IAsyncConfiguration keyVaultConfiguration = new AsyncKeyVaultConfiguration(
                new KeyVault.Implementation.KeyVault(clientId, clientSecret, vaultUri, checkIfKeyVaultKeyExistsBeforeGet),
                dependencyResolver.Resolve<IKeyVaultConfigurationKeyEncoder>(),
                cachePolicy,
                existingConfiguration);
            dependencyResolver.Register(() => keyVaultConfiguration);

            return dependencyResolver;
        }