From bd6930c31f68ce4e673d25d240a81be283c7860c Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Wed, 25 Sep 2024 12:43:00 -0700 Subject: [PATCH] update to use sourceid as key in cached secret dictionary --- .../AzureKeyVaultKeyValueAdapter.cs | 10 ++++- .../AzureKeyVaultSecretProvider.cs | 42 +++++++++---------- .../ConfigurationClientExtensions.cs | 5 +++ .../KeyValueChange.cs | 2 + 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs index 9580a1cc..f0880809 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs @@ -84,7 +84,15 @@ public void InvalidateCache(ConfigurationSetting setting = null) } else { - _secretProvider.RemoveSecretFromCache(setting.Key); + if (CanProcess(setting)) + { + string secretRefUri = ParseSecretReferenceUri(setting); + + if (!string.IsNullOrEmpty(secretRefUri) && Uri.TryCreate(secretRefUri, UriKind.Absolute, out Uri secretUri) && KeyVaultSecretIdentifier.TryCreate(secretUri, out KeyVaultSecretIdentifier secretIdentifier)) + { + _secretProvider.RemoveSecretFromCache(secretIdentifier.SourceId); + } + } } } diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultSecretProvider.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultSecretProvider.cs index afa8af0f..ce091deb 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultSecretProvider.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultSecretProvider.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -16,14 +15,14 @@ internal class AzureKeyVaultSecretProvider { private readonly AzureAppConfigurationKeyVaultOptions _keyVaultOptions; private readonly IDictionary _secretClients; - private readonly Dictionary _cachedKeyVaultSecrets; - private string _nextRefreshKey; + private readonly Dictionary _cachedKeyVaultSecrets; + private Uri _nextRefreshSourceId; private DateTimeOffset? _nextRefreshTime; public AzureKeyVaultSecretProvider(AzureAppConfigurationKeyVaultOptions keyVaultOptions = null) { _keyVaultOptions = keyVaultOptions ?? new AzureAppConfigurationKeyVaultOptions(); - _cachedKeyVaultSecrets = new Dictionary(StringComparer.OrdinalIgnoreCase); + _cachedKeyVaultSecrets = new Dictionary(); _secretClients = new Dictionary(StringComparer.OrdinalIgnoreCase); if (_keyVaultOptions.SecretClients != null) @@ -40,8 +39,7 @@ public async Task GetSecretValue(KeyVaultSecretIdentifier secretIdentifi { string secretValue = null; - if (_cachedKeyVaultSecrets.TryGetValue(key, out CachedKeyVaultSecret cachedSecret) && - (cachedSecret.SourceId == secretIdentifier.SourceId) && + if (_cachedKeyVaultSecrets.TryGetValue(secretIdentifier.SourceId, out CachedKeyVaultSecret cachedSecret) && (!cachedSecret.RefreshAt.HasValue || DateTimeOffset.UtcNow < cachedSecret.RefreshAt.Value)) { return cachedSecret.SecretValue; @@ -75,7 +73,7 @@ public async Task GetSecretValue(KeyVaultSecretIdentifier secretIdentifi } finally { - SetSecretInCache(key, cachedSecret, success); + SetSecretInCache(secretIdentifier.SourceId, key, cachedSecret, success); } return secretValue; @@ -88,19 +86,19 @@ public bool ShouldRefreshKeyVaultSecrets() public void ClearCache() { - var keysToRemove = new List(); + var sourceIdsToRemove = new List(); - foreach (KeyValuePair secret in _cachedKeyVaultSecrets) + foreach (KeyValuePair secret in _cachedKeyVaultSecrets) { if (secret.Value.LastRefreshTime + RefreshConstants.MinimumSecretRefreshInterval < DateTimeOffset.UtcNow) { - keysToRemove.Add(secret.Key); + sourceIdsToRemove.Add(secret.Key); } } - foreach (string key in keysToRemove) + foreach (Uri sourceId in sourceIdsToRemove) { - _cachedKeyVaultSecrets.Remove(key); + _cachedKeyVaultSecrets.Remove(sourceId); } if (_cachedKeyVaultSecrets.Any()) @@ -109,11 +107,11 @@ public void ClearCache() } } - public void RemoveSecretFromCache(string key) + public void RemoveSecretFromCache(Uri sourceId) { - _cachedKeyVaultSecrets.Remove(key); + _cachedKeyVaultSecrets.Remove(sourceId); - if (key == _nextRefreshKey) + if (sourceId == _nextRefreshSourceId) { UpdateNextRefreshableSecretFromCache(); } @@ -143,7 +141,7 @@ private SecretClient GetSecretClient(Uri secretUri) return client; } - private void SetSecretInCache(string key, CachedKeyVaultSecret cachedSecret, bool success = true) + private void SetSecretInCache(Uri sourceId, string key, CachedKeyVaultSecret cachedSecret, bool success = true) { if (cachedSecret == null) { @@ -151,31 +149,31 @@ private void SetSecretInCache(string key, CachedKeyVaultSecret cachedSecret, boo } UpdateCacheExpirationTimeForSecret(key, cachedSecret, success); - _cachedKeyVaultSecrets[key] = cachedSecret; + _cachedKeyVaultSecrets[sourceId] = cachedSecret; - if (key == _nextRefreshKey) + if (sourceId == _nextRefreshSourceId) { UpdateNextRefreshableSecretFromCache(); } else if ((cachedSecret.RefreshAt.HasValue && _nextRefreshTime.HasValue && cachedSecret.RefreshAt.Value < _nextRefreshTime.Value) || (cachedSecret.RefreshAt.HasValue && !_nextRefreshTime.HasValue)) { - _nextRefreshKey = key; + _nextRefreshSourceId = sourceId; _nextRefreshTime = cachedSecret.RefreshAt.Value; } } private void UpdateNextRefreshableSecretFromCache() { - _nextRefreshKey = null; + _nextRefreshSourceId = null; _nextRefreshTime = DateTimeOffset.MaxValue; - foreach (KeyValuePair secret in _cachedKeyVaultSecrets) + foreach (KeyValuePair secret in _cachedKeyVaultSecrets) { if (secret.Value.RefreshAt.HasValue && secret.Value.RefreshAt.Value < _nextRefreshTime) { _nextRefreshTime = secret.Value.RefreshAt; - _nextRefreshKey = secret.Key; + _nextRefreshSourceId = secret.Key; } } diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ConfigurationClientExtensions.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ConfigurationClientExtensions.cs index 18c03178..d479ad6b 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ConfigurationClientExtensions.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ConfigurationClientExtensions.cs @@ -36,6 +36,7 @@ public static async Task GetKeyValueChange(this ConfigurationCli return new KeyValueChange { ChangeType = KeyValueChangeType.Modified, + Previous = setting, Current = response.Value, Key = setting.Key, Label = setting.Label @@ -47,6 +48,7 @@ public static async Task GetKeyValueChange(this ConfigurationCli return new KeyValueChange { ChangeType = KeyValueChangeType.Deleted, + Previous = setting, Current = null, Key = setting.Key, Label = setting.Label @@ -56,6 +58,7 @@ public static async Task GetKeyValueChange(this ConfigurationCli return new KeyValueChange { ChangeType = KeyValueChangeType.None, + Previous = setting, Current = setting, Key = setting.Key, Label = setting.Label @@ -158,6 +161,7 @@ await TracingUtils.CallWithRequestTracing(options.RequestTracingEnabled, Request ChangeType = KeyValueChangeType.Modified, Key = setting.Key, Label = options.Label.NormalizeNull(), + Previous = null, Current = setting }); string key = setting.Key.Substring(FeatureManagementConstants.FeatureFlagMarker.Length); @@ -176,6 +180,7 @@ await TracingUtils.CallWithRequestTracing(options.RequestTracingEnabled, Request ChangeType = KeyValueChangeType.Deleted, Key = kvp.Key, Label = options.Label.NormalizeNull(), + Previous = null, Current = null }); string key = kvp.Key.Substring(FeatureManagementConstants.FeatureFlagMarker.Length); diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/KeyValueChange.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/KeyValueChange.cs index 7d41e107..2286016d 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/KeyValueChange.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/KeyValueChange.cs @@ -21,5 +21,7 @@ internal struct KeyValueChange public string Label { get; set; } public ConfigurationSetting Current { get; set; } + + public ConfigurationSetting Previous { get; set; } } }