/// <summary> /// Gets the registered named <see cref="ICachedSecretProvider"/> from the secret store. /// </summary> /// <param name="name">The name that was used to register the <see cref="ICachedSecretProvider"/> in the secret store.</param> /// <typeparam name="TCachedSecretProvider">The concrete <see cref="ICachedSecretProvider"/> type.</typeparam> /// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception> /// <exception cref="KeyNotFoundException">Thrown when there was no <see cref="ICachedSecretProvider"/> found in the secret store with the given <paramref name="name"/>.</exception> /// <exception cref="NotSupportedException"> /// Thrown when their was either none of the registered secret providers are registered as <see cref="ICachedSecretProvider"/> instances /// or there was an <see cref="ISecretProvider"/> registered but not with caching. /// </exception> /// <exception cref="InvalidCastException">Thrown when the registered <see cref="ICachedSecretProvider"/> cannot be cast to the specific <typeparamref name="TCachedSecretProvider"/>.</exception> /// <exception cref="InvalidOperationException">Thrown when multiple <see cref="ICachedSecretProvider"/> were registered with the same name.</exception> public TCachedSecretProvider GetCachedProvider <TCachedSecretProvider>(string name) where TCachedSecretProvider : ICachedSecretProvider { Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to retrieve the registered named secret provider"); Guard.For <NotSupportedException>( () => !HasCachedSecretProviders, $"Cannot use cached secret store operation because none of the secret providers in the secret store were registered as cached secret providers ({nameof(ICachedSecretProvider)})"); ICachedSecretProvider provider = GetCachedProvider(name); if (provider is TCachedSecretProvider concreteProvider) { return(concreteProvider); } if (provider is CompositeSecretProvider) { throw new InvalidOperationException( $"Cannot cast registered {nameof(ICachedSecretProvider)} with name '{name}' to type '{typeof(TCachedSecretProvider).Name}' " + $"because multiple secret providers were registered with the name '{name}', " + $"use the non-generic '{nameof(GetCachedProvider)}' to retrieve them"); } throw new InvalidCastException( $"Cannot cast registered {nameof(ICachedSecretProvider)} with name '{name}' to type '{typeof(TCachedSecretProvider).Name}'"); }
/// <summary> /// Initializes a new instance of the <see cref="SecretStoreSource"/> class. /// </summary> public SecretStoreSource(ICachedSecretProvider secretProvider) { Guard.NotNull(secretProvider, nameof(secretProvider)); SecretProvider = secretProvider; CachedSecretProvider = secretProvider; }
/// <summary> /// Initializes a new instance of the <see cref="InvalidateKeyVaultSecretHandler"/> class. /// </summary> public InvalidateKeyVaultSecretHandler(ICachedSecretProvider secretProvider, ILogger <InvalidateKeyVaultSecretHandler> logger) { Guard.NotNull(secretProvider, nameof(secretProvider)); Guard.NotNull(logger, nameof(logger)); _cachedSecretProvider = secretProvider; _logger = logger; }
/// <summary> /// Initializes a new instance of the <see cref="MutatedSecretNameSecretProvider"/> class. /// </summary> /// <param name="implementation">The actual <see cref="ISecretProvider"/> implementation to look up the secret.</param> /// <param name="mutateSecretName">The function to mutate the name of the secret before looking up the secret.</param> /// <param name="logger">The instance to log diagnostic messages during the secret name mutation.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the <paramref name="implementation"/> or the <paramref name="mutateSecretName"/> is <c>null</c>. /// </exception> public MutatedSecretNameCachedSecretProvider( ICachedSecretProvider implementation, Func <string, string> mutateSecretName, ILogger logger) : base(implementation, mutateSecretName, logger) { Guard.NotNull(implementation, nameof(implementation), "Requires an secret provider instance to pass the mutated secret name to"); _implementation = implementation; }
/// <summary> /// Removes the secret with the given <paramref name="secretName"/> from the cache; /// so the next time <see cref="CachedSecretProvider.GetSecretAsync(string)"/> is called, a new version of the secret will be added back to the cache. /// </summary> /// <param name="secretName">The name of the secret that should be removed from the cache.</param> public async Task InvalidateSecretAsync(string secretName) { Guard.NotNullOrWhitespace(secretName, nameof(secretName)); ICachedSecretProvider provider = await WithCachedSecretStoreAsync(secretName, async source => { Secret secret = await source.CachedSecretProvider.GetSecretAsync(secretName); return(secret is null ? null : source.CachedSecretProvider); }); await provider.InvalidateSecretAsync(secretName); }
/// <summary> /// Gets the registered named <see cref="ICachedSecretProvider"/> from the secret store. /// </summary> /// <param name="name">The name that was used to register the <see cref="ICachedSecretProvider"/> in the secret store.</param> /// <typeparam name="TCachedSecretProvider">The concrete <see cref="ICachedSecretProvider"/> type.</typeparam> /// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception> /// <exception cref="KeyNotFoundException"> /// Thrown when there was no <see cref="ICachedSecretProvider"/> found in the secret store with the given <paramref name="name"/>, /// or there were multiple <see cref="ICachedSecretProvider"/> instances registered with the same name. /// </exception> /// <exception cref="NotSupportedException">Thrown when there was an <see cref="ICachedSecretProvider"/> registered but not with caching.</exception> /// <exception cref="InvalidCastException">Thrown when the registered <see cref="ICachedSecretProvider"/> cannot be cast to the specific <typeparamref name="TCachedSecretProvider"/>.</exception> public TCachedSecretProvider GetCachedProvider <TCachedSecretProvider>(string name) where TCachedSecretProvider : ICachedSecretProvider { Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to retrieve the registered named secret provider"); ICachedSecretProvider provider = GetCachedProvider(name); if (provider is TCachedSecretProvider concreteProvider) { return(concreteProvider); } throw new InvalidCastException($"Cannot cast registered {nameof(ICachedSecretProvider)} with name '{name}' to type '{typeof(TCachedSecretProvider).Name}'"); }
public async Task SecretProviderCachingExtensions_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice() { // Arrange string secretKeyValue = Guid.NewGuid().ToString("N"); var testSecretProvider = new TestSecretProviderStub(secretKeyValue); string keyName = "MyValue"; // Act ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromSeconds(3)); var firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); testSecretProvider.SecretValue = Guid.NewGuid().ToString("N"); // Change actual value on the internal secret provider ! var secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); // Assert Assert.Equal(firstValue, secondValue); Assert.Equal(1, testSecretProvider.CallsMadeSinceCreation); }
public async Task SecretProviderCachingExtensions_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue() { // Arrange string secretKeyValue = Guid.NewGuid().ToString("N"); var testSecretProvider = new TestSecretProviderStub(secretKeyValue); string keyName = "MyValue"; // Act ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromMilliseconds(100)); var firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); await Task.Delay(TimeSpan.FromMilliseconds(150)); string newSecretValue = Guid.NewGuid().ToString("N"); testSecretProvider.SecretValue = newSecretValue; // Change actual value on the internal secret provider ! var secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); // Assert Assert.Equal(secretKeyValue, firstValue); Assert.Equal(newSecretValue, secondValue); Assert.Equal(2, testSecretProvider.CallsMadeSinceCreation); }
public SecretsWithCachingController(ICachedSecretProvider secretProvider, ITelemetryProvider telemetryProvider) { this.secretProvider = secretProvider; this.telemetryProvider = telemetryProvider; }
/// <summary> /// Initializes a new instance of the <see cref="AuthorizedSecretProvider"/> class. /// </summary> /// <param name="permittedRole">The role that is required to access the <paramref name="cachedSecretProvider"/>.</param> /// <param name="authorization">The instance to determine if the <paramref name="permittedRole"/> is considered authorized.</param> /// <param name="cachedSecretProvider">The actual provider to access the secrets.</param> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="authorization"/> or <paramref name="cachedSecretProvider"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown when the <paramref name="permittedRole"/> is outside the bounds of the enumeration.</exception> public AuthorizedCachedSecretProvider(Role permittedRole, IRoleAuthorization authorization, ICachedSecretProvider cachedSecretProvider) : base(permittedRole, authorization, cachedSecretProvider) { Guard.NotNull(cachedSecretProvider, nameof(cachedSecretProvider), "Requires an instance to access the authorized secrets"); _cachedSecretProvider = cachedSecretProvider; }