From f177a3ad65f437c2939f69723951b28dfbb5c28b Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Tue, 28 Jan 2025 17:50:22 +0100 Subject: [PATCH 01/13] Finish Security.AzureFunctions --- .../IFunctionHostBuilderExtensions.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs b/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs index 039e0d77..3b9826d9 100644 --- a/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs +++ b/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs @@ -1,6 +1,5 @@ using System; using Arcus.Security.Core; -using GuardNet; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -22,8 +21,14 @@ public static class IFunctionHostBuilderExtensions /// Thrown when the or is null. public static IFunctionsHostBuilder ConfigureSecretStore(this IFunctionsHostBuilder functionsHostBuilder, Action configureSecretStores) { - Guard.NotNull(functionsHostBuilder, nameof(functionsHostBuilder), "Requires a functions host builder to add the secret store"); - Guard.NotNull(configureSecretStores, nameof(configureSecretStores), "Requires a function to configure the secret store with potential secret providers"); + if (functionsHostBuilder is null) + { + throw new ArgumentNullException(nameof(functionsHostBuilder), "Requires a functions host builder to add the secret store"); + } + if (configureSecretStores is null) + { + throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to configure the secret store with potential secret providers"); + } functionsHostBuilder.Services.AddSecretStore(configureSecretStores); return functionsHostBuilder; @@ -39,8 +44,14 @@ public static IFunctionsHostBuilder ConfigureSecretStore( this IFunctionsHostBuilder functionsHostBuilder, Action configureSecretStores) { - Guard.NotNull(functionsHostBuilder, nameof(functionsHostBuilder), "Requires a functions host builder to add the secret store"); - Guard.NotNull(configureSecretStores, nameof(configureSecretStores), "Requires a function to configure the secret store with potential secret providers"); + if (functionsHostBuilder is null) + { + throw new ArgumentNullException(nameof(functionsHostBuilder), "Requires a functions host builder to add the secret store"); + } + if (configureSecretStores is null) + { + throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to configure the secret store with potential secret providers"); + } FunctionsHostBuilderContext context = functionsHostBuilder.GetContext(); functionsHostBuilder.Services.AddSecretStore(stores => configureSecretStores(context, context.Configuration, stores)); From 10c553948cb21fa15d7f196a087bed0ff94e5b2d Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:27:54 +0100 Subject: [PATCH 02/13] Finish Security.Core --- .../Configuration/CacheConfiguration.cs | 7 +- .../SecretProviderCachingExtensions.cs | 31 ++++++-- .../Extensions/IHostBuilderExtensions.cs | 21 ++++-- .../ISecretProviderExtensions.Deprecated.cs | 71 ------------------- .../Extensions/ISecretProviderExtensions.cs | 31 ++++++-- .../IServiceCollectionExtensions.cs | 11 ++- .../SecretStoreBuilderExtensions.cs | 43 ++++++++--- .../Providers/ConfigurationSecretProvider.cs | 26 +++++-- .../EnvironmentVariableSecretProvider.cs | 27 +++++-- .../MutatedSecretNameCachedSecretProvider.cs | 22 ++++-- .../MutatedSecretNameSecretProvider.cs | 64 +++++++++++++---- src/Arcus.Security.Core/Secret.cs | 1 - 12 files changed, 215 insertions(+), 140 deletions(-) delete mode 100644 src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs diff --git a/src/Arcus.Security.Core/Caching/Configuration/CacheConfiguration.cs b/src/Arcus.Security.Core/Caching/Configuration/CacheConfiguration.cs index c084cb03..e8d6ad24 100644 --- a/src/Arcus.Security.Core/Caching/Configuration/CacheConfiguration.cs +++ b/src/Arcus.Security.Core/Caching/Configuration/CacheConfiguration.cs @@ -1,5 +1,4 @@ using System; -using GuardNet; namespace Arcus.Security.Core.Caching.Configuration { @@ -15,7 +14,11 @@ public class CacheConfiguration : ICacheConfiguration /// Thrown when the cache duration is not a positive time duration. public CacheConfiguration(TimeSpan duration) { - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration in which the caching should take place"); + if (duration < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(duration), duration, "Requires a positive time duration in which the caching should take place"); + } + Duration = duration; } diff --git a/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs b/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs index a139a453..aa47cd6b 100644 --- a/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs +++ b/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs @@ -1,6 +1,5 @@ using System; using Arcus.Security.Core.Caching.Configuration; -using GuardNet; using Microsoft.Extensions.Caching.Memory; namespace Arcus.Security.Core.Caching @@ -21,9 +20,18 @@ public static class SecretProviderCachingExtensions /// Thrown when the is not a positive time duration. public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvider, TimeSpan cachingDuration, IMemoryCache memoryCache) { - Guard.NotNull(secretProvider, nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); - Guard.NotLessThan(cachingDuration, TimeSpan.Zero, nameof(cachingDuration), "Requires a positive time duration in which the caching should take place"); - Guard.NotNull(memoryCache, nameof(memoryCache), "Requires a memory caching implementation to include caching while retrieving secrets"); + if (secretProvider is null) + { + throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); + } + if (cachingDuration < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(cachingDuration), "Requires a positive time duration in which the caching should take place"); + } + if (memoryCache is null) + { + throw new ArgumentNullException(nameof(memoryCache), "Requires a memory caching implementation to include caching while retrieving secrets"); + } return new CachedSecretProvider(secretProvider, new CacheConfiguration(cachingDuration), memoryCache); } @@ -39,8 +47,14 @@ public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvi /// Thrown when the is not a positive time duration. public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvider, TimeSpan cachingDuration) { - Guard.NotNull(secretProvider, nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); - Guard.NotLessThan(cachingDuration, TimeSpan.Zero, nameof(cachingDuration), "Requires a positive time duration in which the caching should take place"); + if (secretProvider is null) + { + throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); + } + if (cachingDuration < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(cachingDuration), "Requires a positive time duration in which the caching should take place"); + } return new CachedSecretProvider(secretProvider, new CacheConfiguration(cachingDuration)); } @@ -54,7 +68,10 @@ public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvi /// Thrown when the is null. public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvider) { - Guard.NotNull(secretProvider, nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); + if (secretProvider is null) + { + throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); + } return new CachedSecretProvider(secretProvider); } diff --git a/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs b/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs index 63098060..c6dda0ab 100644 --- a/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs @@ -1,5 +1,4 @@ using Arcus.Security.Core; -using GuardNet; using Microsoft.Extensions.Configuration; using System; using Microsoft.Extensions.DependencyInjection; @@ -21,8 +20,14 @@ public static class IHostBuilderExtensions /// Thrown when the or is null. public static IHostBuilder ConfigureSecretStore(this IHostBuilder hostBuilder, Action configureSecretStores) { - Guard.NotNull(hostBuilder, nameof(hostBuilder), "Requires a host builder to add the secret store"); - Guard.NotNull(configureSecretStores, nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); + if (hostBuilder is null) + { + throw new ArgumentNullException(nameof(hostBuilder), "Requires a host builder to add the secret store"); + } + if (configureSecretStores is null) + { + throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); + } return ConfigureSecretStore(hostBuilder, (context, config, secretStores) => configureSecretStores(config, secretStores)); } @@ -35,8 +40,14 @@ public static IHostBuilder ConfigureSecretStore(this IHostBuilder hostBuilder, A /// Thrown when the or is null. public static IHostBuilder ConfigureSecretStore(this IHostBuilder hostBuilder, Action configureSecretStores) { - Guard.NotNull(hostBuilder, nameof(hostBuilder), "Requires a host builder to add the secret store"); - Guard.NotNull(configureSecretStores, nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); + if (hostBuilder is null) + { + throw new ArgumentNullException(nameof(hostBuilder), "Requires a host builder to add the secret store"); + } + if (configureSecretStores is null) + { + throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); + } return hostBuilder.ConfigureServices((context, services) => { diff --git a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs deleted file mode 100644 index 50c36631..00000000 --- a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using GuardNet; - -namespace Arcus.Security.Core.Extensions -{ - /// - /// Extensions on the to retrieve several secret values based on configured allowed versions. - /// - // ReSharper disable once InconsistentNaming - [ExcludeFromCodeCoverage] - public static class ISecretProviderExtensions - { - /// - /// Retrieves all the allowed versions of a secret value, based on the given . - /// - /// - /// This extension is made for easy access to the versions of a secret, and is expected to be used on the secret store implementation, - /// any other uses will fallback on the general secret retrieval. In that case, the resulting sequence will contain a single secret value. - /// - /// The secret store composite secret provider. - /// The name of the secret that was made versioned with . - /// The must not be empty - /// The must not be null - /// The secret was not found, using the given name - [Obsolete("Use the " + nameof(Core.ISecretProviderExtensions.GetRawSecretsAsync) + " extension instead")] - public static async Task> GetRawSecretsAsync(this ISecretProvider secretProvider, string secretName) - { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); - - if (secretProvider is CompositeSecretProvider composite) - { - IEnumerable secretValues = await composite.GetRawSecretsAsync(secretName); - return secretValues.ToArray(); - } - - string secretValue = await secretProvider.GetRawSecretAsync(secretName); - return new[] { secretValue }; - } - - /// - /// Retrieves all the allowed versions of a secret value, based on the given . - /// - /// - /// This extension is made for easy access to the versions of a secret, and is expected to be used on the secret store implementation, - /// any other uses will fallback on the general secret retrieval. In that case, the resulting sequence will contain a single secret value. - /// - /// The secret store composite secret provider. - /// The name of the secret that was made versioned with . - /// The must not be empty - /// The must not be null - /// The secret was not found, using the given name - [Obsolete("Use the " + nameof(Core.ISecretProviderExtensions.GetSecretsAsync) + " extension instead")] - public static async Task> GetSecretsAsync(this ISecretProvider secretProvider, string secretName) - { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); - - if (secretProvider is CompositeSecretProvider composite) - { - IEnumerable secrets = await composite.GetSecretsAsync(secretName); - return secrets.ToArray(); - } - - Secret secret = await secretProvider.GetSecretAsync(secretName); - return new[] { secret }; - } - } -} \ No newline at end of file diff --git a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs index 22ab60be..155bd608 100644 --- a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using GuardNet; // ReSharper disable once CheckNamespace namespace Arcus.Security.Core @@ -23,8 +22,14 @@ public static class ISecretProviderExtensions /// Thrown when the secret was not found, using the given name. public static string GetRawSecret(this ISecretProvider secretProvider, string secretName) { - Guard.NotNull(secretProvider, nameof(secretProvider), "Requires a secret provider to synchronously look up the secret"); - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); + if (secretProvider is null) + { + throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider to synchronously look up the secret"); + } + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + } if (secretProvider is ISyncSecretProvider composite) { @@ -46,8 +51,14 @@ public static string GetRawSecret(this ISecretProvider secretProvider, string se /// Thrown when the secret was not found, using the given name. public static Secret GetSecret(this ISecretProvider secretProvider, string secretName) { - Guard.NotNull(secretProvider, nameof(secretProvider), "Requires a secret provider to synchronously look up the secret"); - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); + if (secretProvider is null) + { + throw new ArgumentNullException(nameof(secretProvider + } + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + } if (secretProvider is ISyncSecretProvider composite) { @@ -73,7 +84,10 @@ public static Secret GetSecret(this ISecretProvider secretProvider, string secre /// The secret was not found, using the given name public static async Task> GetRawSecretsAsync(this ISecretProvider secretProvider, string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + } if (secretProvider is CompositeSecretProvider composite) { @@ -99,7 +113,10 @@ public static async Task> GetRawSecretsAsync(this ISecretPro /// The secret was not found, using the given name public static async Task> GetSecretsAsync(this ISecretProvider secretProvider, string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + } if (secretProvider is CompositeSecretProvider composite) { diff --git a/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs b/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs index b2b53490..1fcec367 100644 --- a/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs @@ -1,6 +1,5 @@ using System; using Arcus.Security.Core; -using GuardNet; using Microsoft.Extensions.Hosting; // ReSharper disable once CheckNamespace @@ -20,8 +19,14 @@ public static class IServiceCollectionExtensions /// Thrown when the or is null. public static IServiceCollection AddSecretStore(this IServiceCollection services, Action configureSecretStores) { - Guard.NotNull(services, nameof(services), "Requires a set of services to add the secret store"); - Guard.NotNull(configureSecretStores, nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); + if (services is null) + { + throw new ArgumentNullException(nameof(services), "Requires a set of services to add the secret store"); + } + if (configureSecretStores is null) + { + throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); + } var builder = new SecretStoreBuilder(services); configureSecretStores(builder); diff --git a/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs b/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs index a749ce9c..8fdba1a8 100644 --- a/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs @@ -1,6 +1,5 @@ using System; using Arcus.Security.Core.Providers; -using GuardNet; using Microsoft.Extensions.Configuration; // ReSharper disable once CheckNamespace @@ -26,9 +25,14 @@ public static SecretStoreBuilder AddEnvironmentVariables( string prefix = null, Func mutateSecretName = null) { - Guard.NotNull(builder, nameof(builder), "Requires a secret store builder to add the environment secrets"); - Guard.For(() => !Enum.IsDefined(typeof(EnvironmentVariableTarget), target), - $"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + if (builder is null) + { + throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the environment secrets"); + } + if (!Enum.IsDefined(typeof(EnvironmentVariableTarget), target)) + { + throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + } return AddEnvironmentVariables(builder, target, prefix, name: null, mutateSecretName: mutateSecretName); } @@ -50,9 +54,14 @@ public static SecretStoreBuilder AddEnvironmentVariables( string name, Func mutateSecretName) { - Guard.NotNull(builder, nameof(builder), "Requires a secret store builder to add the environment secrets"); - Guard.For(() => !Enum.IsDefined(typeof(EnvironmentVariableTarget), target), - $"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + if (builder is null) + { + throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the environment secrets"); + } + if (!Enum.IsDefined(typeof(EnvironmentVariableTarget), target)) + { + throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + } return builder.AddProvider(new EnvironmentVariableSecretProvider(target, prefix), options => { @@ -73,8 +82,14 @@ public static SecretStoreBuilder AddConfiguration( IConfiguration configuration, Func mutateSecretName = null) { - Guard.NotNull(builder, nameof(builder), "Requires a secret store builder to add the configuration secrets"); - Guard.NotNull(configuration, nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); + if (builder is null) + { + throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the configuration secrets"); + } + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); + } return AddConfiguration(builder, configuration, name: null, mutateSecretName: mutateSecretName); } @@ -93,8 +108,14 @@ public static SecretStoreBuilder AddConfiguration( string name, Func mutateSecretName) { - Guard.NotNull(builder, nameof(builder), "Requires a secret store builder to add the configuration secrets"); - Guard.NotNull(configuration, nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); + if (builder is null) + { + throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the configuration secrets"); + } + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); + } return builder.AddProvider(new ConfigurationSecretProvider(configuration), options => { diff --git a/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs b/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs index d51e28f0..6bf1a628 100644 --- a/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using GuardNet; using Microsoft.Extensions.Configuration; namespace Arcus.Security.Core.Providers @@ -19,7 +18,10 @@ public class ConfigurationSecretProvider : ISyncSecretProvider /// Thrown when the is null. public ConfigurationSecretProvider(IConfiguration configuration) { - Guard.NotNull(configuration, nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); + } _configuration = configuration; } @@ -32,7 +34,10 @@ public ConfigurationSecretProvider(IConfiguration configuration) /// The secret was not found, using the given name public Task GetSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + } Secret secret = GetSecret(secretName); return Task.FromResult(secret); @@ -46,7 +51,10 @@ public Task GetSecretAsync(string secretName) /// The secret was not found, using the given name public Task GetRawSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + } string secretValue = GetRawSecret(secretName); return Task.FromResult(secretValue); @@ -61,7 +69,10 @@ public Task GetRawSecretAsync(string secretName) /// Thrown when the secret was not found, using the given name. public Secret GetSecret(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + } string secretValue = GetRawSecret(secretName); if (secretValue is null) @@ -81,7 +92,10 @@ public Secret GetSecret(string secretName) /// Thrown when the secret was not found, using the given name. public string GetRawSecret(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + } string secretValue = _configuration[secretName]; return secretValue; diff --git a/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs b/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs index 1b23ecb5..93ff3e75 100644 --- a/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using GuardNet; namespace Arcus.Security.Core.Providers { @@ -22,8 +21,10 @@ public class EnvironmentVariableSecretProvider : ISyncSecretProvider /// Thrown when the is outside the bounds of the enumeration. public EnvironmentVariableSecretProvider(EnvironmentVariableTarget target = DefaultTarget, string prefix = null) { - Guard.For(() => !Enum.IsDefined(typeof(EnvironmentVariableTarget), target), - $"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + if (!Enum.IsDefined(typeof(EnvironmentVariableTarget), target)) + { + throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + } _prefix = prefix ?? String.Empty; _target = target; @@ -39,7 +40,10 @@ public EnvironmentVariableSecretProvider(EnvironmentVariableTarget target = Defa /// The secret was not found, using the given name public Task GetSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + } Secret secret = GetSecret(secretName); return Task.FromResult(secret); @@ -55,7 +59,10 @@ public Task GetSecretAsync(string secretName) /// The secret was not found, using the given name public Task GetRawSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + } string secretValue = GetRawSecret(secretName); return Task.FromResult(secretValue); @@ -70,7 +77,10 @@ public Task GetRawSecretAsync(string secretName) /// Thrown when the secret was not found, using the given name. public Secret GetSecret(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + } string secretValue = GetRawSecret(secretName); if (secretValue is null) @@ -90,7 +100,10 @@ public Secret GetSecret(string secretName) /// Thrown when the secret was not found, using the given name. public string GetRawSecret(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + } string environmentVariable = Environment.GetEnvironmentVariable(_prefix + secretName, _target); return environmentVariable; diff --git a/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs b/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs index b7517f68..3d13ddb1 100644 --- a/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Arcus.Security.Core.Caching; using Arcus.Security.Core.Caching.Configuration; -using GuardNet; using Microsoft.Extensions.Logging; namespace Arcus.Security.Core.Providers @@ -29,7 +28,11 @@ public MutatedSecretNameCachedSecretProvider( ILogger logger) : base(implementation, mutateSecretName, logger) { - Guard.NotNull(implementation, nameof(implementation), "Requires an secret provider instance to pass the mutated secret name to"); + if (implementation is null) + { + throw new ArgumentNullException(nameof(implementation), "Requires a secret provider instance to pass the mutated") + } + _implementation = implementation; } @@ -49,7 +52,10 @@ public MutatedSecretNameCachedSecretProvider( /// The secret was not found, using the given name public async Task GetRawSecretAsync(string secretName, bool ignoreCache) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } string secretValue = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => { @@ -70,7 +76,10 @@ public async Task GetRawSecretAsync(string secretName, bool ignoreCache) /// The secret was not found, using the given name public async Task GetSecretAsync(string secretName, bool ignoreCache) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } Secret secret = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => { @@ -87,7 +96,10 @@ public async Task GetSecretAsync(string secretName, bool ignoreCache) /// The name of the secret that should be removed from the cache. public async Task InvalidateSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } await SafeguardMutateSecretAsync(secretName, async mutatedSecretName => { diff --git a/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs b/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs index ba4741da..5ad3d4b1 100644 --- a/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using GuardNet; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -25,9 +24,14 @@ public class MutatedSecretNameSecretProvider : ISyncSecretProvider /// public MutatedSecretNameSecretProvider(ISecretProvider implementation, Func mutateSecretName, ILogger logger) { - Guard.NotNull(implementation, nameof(implementation), "Requires an secret provider instance to pass the mutated secret name to"); - Guard.NotNull(mutateSecretName, nameof(mutateSecretName), - "Requires an transformation function to mutate the incoming secret name to something that the actual secret provider can understand"); + if (implementation is null) + { + throw new ArgumentNullException(nameof(implementation), "Requires a secret provider instance to pass the mutated"); + } + if (mutateSecretName is null) + { + throw new ArgumentNullException(nameof(mutateSecretName), "Requires a transformation function to mutate the incoming secret name to something that the actual secret provider can understand"); + } _mutateSecretName = mutateSecretName; _implementation = implementation; @@ -50,7 +54,7 @@ public MutatedSecretNameSecretProvider(ISecretProvider implementation, FuncThe secret was not found, using the given name public async Task GetRawSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName), "Requires a non-blank secret name when mutating secret names"); string secretValue = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => { @@ -70,7 +74,10 @@ public async Task GetRawSecretAsync(string secretName) /// The secret was not found, using the given name public async Task GetSecretAsync(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } Secret secret = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => { @@ -89,7 +96,10 @@ public async Task GetSecretAsync(string secretName) /// Thrown when the secret was not found, using the given name. public string GetRawSecret(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } string secretValue = SafeguardMutateSecret(secretName, mutatedSecretName => { @@ -108,7 +118,10 @@ public string GetRawSecret(string secretName) /// Thrown when the secret was not found, using the given name. public Secret GetSecret(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } Secret secret = SafeguardMutateSecret(secretName, mutatedSecretName => { @@ -127,8 +140,14 @@ public Secret GetSecret(string secretName) /// Thrown when the is null. protected async Task SafeguardMutateSecretAsync(string secretName, Func asyncFuncAfterMutation) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); - Guard.NotNull(asyncFuncAfterMutation, nameof(asyncFuncAfterMutation), "Requires a function to run after the secret name mutation"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } + if (asyncFuncAfterMutation is null) + { + throw new ArgumentNullException(nameof(asyncFuncAfterMutation), "Requires a function to run after the secret name mutation"); + } await SafeguardMutateSecretAsync(secretName, async mutatedSecretName => { @@ -152,8 +171,14 @@ await SafeguardMutateSecretAsync(secretName, async mutatedSecretName => /// Thrown when the is null. protected async Task SafeguardMutateSecretAsync(string secretName, Func> asyncFuncAfterMutation) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); - Guard.NotNull(asyncFuncAfterMutation, nameof(asyncFuncAfterMutation), "Requires a function to run after the secret name mutation"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } + if (asyncFuncAfterMutation is null) + { + throw new ArgumentNullException(nameof(asyncFuncAfterMutation), "Requires a function to run after the secret name mutation"); + } string mutatedSecretName = MutateSecretName(secretName); Task task = asyncFuncAfterMutation(mutatedSecretName); @@ -190,8 +215,14 @@ protected async Task SafeguardMutateSecretAsync(string secretName, FuncThrown when the is null. protected T SafeguardMutateSecret(string secretName, Func afterMutation) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); - Guard.NotNull(afterMutation, nameof(afterMutation), "Requires a function to run after the secret name mutation"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } + if (afterMutation is null) + { + throw new ArgumentNullException(nameof(afterMutation), "Requires a function to run after the secret name mutation"); + } string mutatedSecretName = MutateSecretName(secretName); @@ -209,7 +240,10 @@ protected T SafeguardMutateSecret(string secretName, Func afterMut private string MutateSecretName(string secretName) { - Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + } try { diff --git a/src/Arcus.Security.Core/Secret.cs b/src/Arcus.Security.Core/Secret.cs index 51d490ef..6f62db3c 100644 --- a/src/Arcus.Security.Core/Secret.cs +++ b/src/Arcus.Security.Core/Secret.cs @@ -1,5 +1,4 @@ using System; -using GuardNet; namespace Arcus.Security.Core { From d19166b01f00ac6f624706f8b0f474a7af95c977 Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Wed, 29 Jan 2025 10:48:12 +0100 Subject: [PATCH 03/13] Finish Security.Providers.AzureKeyVault --- .../Configuration/ArcusConfigurationProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Configuration/ArcusConfigurationProvider.cs b/src/Arcus.Security.Providers.AzureKeyVault/Configuration/ArcusConfigurationProvider.cs index 35a5ce7f..a33b372d 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Configuration/ArcusConfigurationProvider.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Configuration/ArcusConfigurationProvider.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Arcus.Security.Core; using Microsoft.Extensions.Configuration; -using GuardNet; namespace Arcus.Security.Providers.AzureKeyVault.Configuration { From 3791fc560011205b5c215e5d0d4684599fe307e5 Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:33:39 +0100 Subject: [PATCH 04/13] Finish Security.Tests.Core --- .../Arcus.Security.Tests.Core.csproj | 1 - .../Fixture/TemporaryEnvironmentVariable.cs | 13 ++++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj b/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj index e47afac1..3ac5d9c2 100644 --- a/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj +++ b/src/Arcus.Security.Tests.Core/Arcus.Security.Tests.Core.csproj @@ -5,7 +5,6 @@ - diff --git a/src/Arcus.Security.Tests.Core/Fixture/TemporaryEnvironmentVariable.cs b/src/Arcus.Security.Tests.Core/Fixture/TemporaryEnvironmentVariable.cs index c45a4f60..ca5ec276 100644 --- a/src/Arcus.Security.Tests.Core/Fixture/TemporaryEnvironmentVariable.cs +++ b/src/Arcus.Security.Tests.Core/Fixture/TemporaryEnvironmentVariable.cs @@ -1,5 +1,4 @@ using System; -using GuardNet; namespace Arcus.Security.Tests.Core.Fixture { @@ -12,7 +11,11 @@ public class TemporaryEnvironmentVariable : IDisposable private TemporaryEnvironmentVariable(string name) { - Guard.NotNull(name, nameof(name)); + if (name is null) + { + throw new ArgumentNullException(nameof(name)); + } + _name = name; } @@ -23,7 +26,11 @@ private TemporaryEnvironmentVariable(string name) /// The value of the environment variable. public static TemporaryEnvironmentVariable Create(string name, string value) { - Guard.NotNull(name, nameof(name)); + if (name is null) + { + throw new ArgumentNullException(nameof(name)); + } + Environment.SetEnvironmentVariable(name, value); return new TemporaryEnvironmentVariable(name); From 33096bd2d442cf1c95d0c048e3174bf51d9220df Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:13:50 +0100 Subject: [PATCH 05/13] Finish Security.Tests.Integration --- .../Hosting/HashiCorpVaultTestServer.cs | 99 ++++++++++++++----- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs index 435a0ddd..e8349203 100644 --- a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs +++ b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs @@ -10,7 +10,6 @@ using Arcus.Security.Providers.HashiCorp; using Arcus.Security.Tests.Integration.HashiCorp.Mounting; using Arcus.Testing; -using GuardNet; using Microsoft.Extensions.Logging; using Polly; using Vault; @@ -43,10 +42,22 @@ public class HashiCorpVaultTestServer : IDisposable private HashiCorpVaultTestServer(Process process, string rootToken, string listenAddress, ILogger logger) { - Guard.NotNull(process, nameof(process)); - Guard.NotNullOrWhitespace(rootToken, nameof(rootToken)); - Guard.NotNullOrWhitespace(listenAddress, nameof(listenAddress)); - Guard.NotNull(logger, nameof(logger)); + if (process is null) + { + throw new ArgumentNullException(nameof(process)); + } + if (string.IsNullOrWhiteSpace(rootToken)) + { + throw new ArgumentNullException(nameof(rootToken)); + } + if (string.IsNullOrWhiteSpace(listenAddress)) + { + throw new ArgumentNullException(nameof(listenAddress)); + } + if (logger is null) + { + throw new ArgumentNullException(nameof(logger)); + } _process = process; _rootToken = rootToken; @@ -84,10 +95,14 @@ private HashiCorpVaultTestServer(Process process, string rootToken, string liste /// Thrown when the or is null. public static async Task StartServerAsync(TestConfig configuration, ILogger logger) { - Guard.NotNull(logger, nameof(logger), - "Requires a logger for logging diagnostic trace messages during the lifetime of the test server"); - Guard.NotNull(configuration, nameof(configuration), - "Requires a configuration instance to retrieve the HashiCorp Vault installation folder"); + if (logger is null) + { + throw new ArgumentNullException(nameof(logger), "Requires a logger for logging diagnostic trace messages during the lifetime of the test server"); + } + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the HashiCorp Vault installation folder"); + } var rootToken = Guid.NewGuid().ToString(); int port = GetRandomUnusedPort(); @@ -186,8 +201,14 @@ private async Task StartHashiCorpVaultAsync() /// public async Task MountKeyValueAsync(string path, VaultKeyValueSecretEngineVersion version) { - Guard.NotNullOrWhitespace(path, nameof(path), "Requires a path to mount the KeyValue secret engine to"); - Guard.For(() => !Enum.IsDefined(typeof(VaultKeyValueSecretEngineVersion), version), "Requires a KeyValue secret engine version that is either V1 or V2"); + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException(nameof(path), "Requires a path to mount the KeyValue secret engine to"); + } + if (!Enum.IsDefined(typeof(VaultKeyValueSecretEngineVersion), version)) + { + throw new ArgumentException("Requires a KeyValue secret engine version that is either V1 or V2", nameof(version)); + } var content = new MountInfo { @@ -211,11 +232,22 @@ public async Task MountKeyValueAsync(string path, VaultKeyValueSecretEngineVersi /// Thrown when the is null. public async Task AddPolicyAsync(string name, string path, string[] capabilities) { - Guard.NotNullOrWhitespace(name, nameof(name), "Requires a name to identify the policy"); - Guard.NotNullOrWhitespace(path, nameof(path), "Requires a path where the policy will be applicable"); - Guard.NotNull(capabilities, nameof(capabilities), "Requires a set of capabilities that should be available in this policy"); - Guard.NotAny(capabilities, nameof(capabilities), "Requires a set of capabilities that should be available in this policy"); - Guard.For(() => capabilities.Any(String.IsNullOrWhiteSpace), "Requires all the capabilities of the policy to be filled out (not blank)"); + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException(nameof(name), "Requires a name to identify the policy"); + } + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException(nameof(path), "Requires a path where the policy will be applicable"); + } + if (capabilities is null || !capabilities.Any()) + { + throw new ArgumentNullException(nameof(capabilities), "Requires a set of capabilities that should be available in this policy"); + } + if (capabilities.Any(string.IsNullOrWhiteSpace)) + { + throw new ArgumentException("Requires all the capabilities of the policy to be filled out (not blank)", nameof(capabilities)); + } string joinedCapabilities = String.Join(", ", capabilities.Select(c => $"\"{c}\"")); string rules = $"path \"{path}/*\" {{ capabilities = [ {joinedCapabilities} ]}}"; @@ -231,7 +263,10 @@ public async Task AddPolicyAsync(string name, string path, string[] capabilities /// Thrown when the is blank. public async Task EnableAuthenticationTypeAsync(string type, string description) { - Guard.NotNullOrWhitespace(type, nameof(type), "Requires an authentication type to enable the authentication"); + if (string.IsNullOrWhiteSpace(type)) + { + throw new ArgumentNullException(nameof(type), "Requires an authentication type to enable the authentication"); + } await _systemEndpoint.EnableAuth(path: type, authType: type, description: description); } @@ -246,9 +281,18 @@ public async Task EnableAuthenticationTypeAsync(string type, string description) /// Thrown when the , , or is blank. public async Task AddUserPassUserAsync(string username, string password, string policyName) { - Guard.NotNullOrWhitespace(username, nameof(username)); - Guard.NotNullOrWhitespace(password, nameof(password)); - Guard.NotNullOrWhitespace(policyName, nameof(policyName)); + if (string.IsNullOrWhiteSpace(username)) + { + throw new ArgumentNullException(nameof(username)); + } + if (string.IsNullOrWhiteSpace(password)) + { + throw new ArgumentNullException(nameof(password)); + } + if (string.IsNullOrWhiteSpace(policyName)) + { + throw new ArgumentNullException(nameof(policyName)); + } await _authenticationEndpoint.Write($"/userpass/users/{username}", new UsersRequest { @@ -292,9 +336,18 @@ private void StopHashiCorpVault() protected PolicyResult RetryAction(Action action, int timeoutInSeconds = 30, int retryIntervalInSeconds = 1) { - Guard.NotNull(action, nameof(action), "Requires disposing function to be retried"); - Guard.NotLessThan(timeoutInSeconds, 0, nameof(timeoutInSeconds), "Requires a timeout (in sec) greater than zero"); - Guard.NotLessThan(retryIntervalInSeconds, 0, nameof(retryIntervalInSeconds), "Requires a retry interval (in sec) greater than zero"); + if (action is null) + { + throw new ArgumentNullException(nameof(action), "Requires disposing function to be retried"); + } + if (timeoutInSeconds < 0) + { + throw new ArgumentOutOfRangeException(nameof(timeoutInSeconds), "Requires a timeout (in sec) greater than zero"); + } + if (retryIntervalInSeconds < 0) + { + throw new ArgumentOutOfRangeException(nameof(retryIntervalInSeconds), "Requires a retry interval (in sec) greater than zero"); + } return Policy.Timeout(TimeSpan.FromSeconds(timeoutInSeconds)) .Wrap(Policy.Handle() From a2aeba510531b5a4fbe71f976f72187ece36c604 Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:14:54 +0100 Subject: [PATCH 06/13] Finish Security.Tests.Runtimes.AzureFunctions --- .../OrderFunction.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Arcus.Security.Tests.Runtimes.AzureFunctions/OrderFunction.cs b/src/Arcus.Security.Tests.Runtimes.AzureFunctions/OrderFunction.cs index 9d264675..230ea16f 100644 --- a/src/Arcus.Security.Tests.Runtimes.AzureFunctions/OrderFunction.cs +++ b/src/Arcus.Security.Tests.Runtimes.AzureFunctions/OrderFunction.cs @@ -2,7 +2,6 @@ using System.Net; using System.Threading.Tasks; using Arcus.Security.Core; -using GuardNet; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; @@ -24,7 +23,11 @@ public class OrderFunction /// Thrown when the is null. public OrderFunction(ISecretProvider secretProvider, ILogger logger) { - Guard.NotNull(secretProvider, nameof(secretProvider), "Requires a secret provider instance"); + if (secretProvider is null) + { + throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider instance"); + } + _secretProvider = secretProvider; } From a3cc9ad6eeffc5cdcc0cad390eaad41635610d8e Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:17:22 +0100 Subject: [PATCH 07/13] Finish Security.Tests.Unit --- .../Core/Stubs/SaboteurSecretProvider.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs b/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs index 329f6f62..15654ec3 100644 --- a/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs +++ b/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Arcus.Security.Core; -using GuardNet; namespace Arcus.Security.Tests.Unit.Core.Stubs { @@ -19,7 +18,11 @@ public class SaboteurSecretProvider: ISyncSecretProvider /// Thrown when the is null. public SaboteurSecretProvider(Exception exception) { - Guard.NotNull(exception, nameof(exception), "Requires an specific exception to sabotage the secret retrieval"); + if (exception is null) + { + throw new ArgumentNullException(nameof(exception), "Requires a specific exception to sabotage the secret retrieval"); + } + _exception = exception; } From 58bf838f77a7a29b210309ff1301339251ba46c2 Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:05:23 +0100 Subject: [PATCH 08/13] revert removed file --- .../ISecretProviderExtensions.Deprecated.cs | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs diff --git a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs new file mode 100644 index 00000000..50c36631 --- /dev/null +++ b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using GuardNet; + +namespace Arcus.Security.Core.Extensions +{ + /// + /// Extensions on the to retrieve several secret values based on configured allowed versions. + /// + // ReSharper disable once InconsistentNaming + [ExcludeFromCodeCoverage] + public static class ISecretProviderExtensions + { + /// + /// Retrieves all the allowed versions of a secret value, based on the given . + /// + /// + /// This extension is made for easy access to the versions of a secret, and is expected to be used on the secret store implementation, + /// any other uses will fallback on the general secret retrieval. In that case, the resulting sequence will contain a single secret value. + /// + /// The secret store composite secret provider. + /// The name of the secret that was made versioned with . + /// The must not be empty + /// The must not be null + /// The secret was not found, using the given name + [Obsolete("Use the " + nameof(Core.ISecretProviderExtensions.GetRawSecretsAsync) + " extension instead")] + public static async Task> GetRawSecretsAsync(this ISecretProvider secretProvider, string secretName) + { + Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); + + if (secretProvider is CompositeSecretProvider composite) + { + IEnumerable secretValues = await composite.GetRawSecretsAsync(secretName); + return secretValues.ToArray(); + } + + string secretValue = await secretProvider.GetRawSecretAsync(secretName); + return new[] { secretValue }; + } + + /// + /// Retrieves all the allowed versions of a secret value, based on the given . + /// + /// + /// This extension is made for easy access to the versions of a secret, and is expected to be used on the secret store implementation, + /// any other uses will fallback on the general secret retrieval. In that case, the resulting sequence will contain a single secret value. + /// + /// The secret store composite secret provider. + /// The name of the secret that was made versioned with . + /// The must not be empty + /// The must not be null + /// The secret was not found, using the given name + [Obsolete("Use the " + nameof(Core.ISecretProviderExtensions.GetSecretsAsync) + " extension instead")] + public static async Task> GetSecretsAsync(this ISecretProvider secretProvider, string secretName) + { + Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to look up the secret"); + + if (secretProvider is CompositeSecretProvider composite) + { + IEnumerable secrets = await composite.GetSecretsAsync(secretName); + return secrets.ToArray(); + } + + Secret secret = await secretProvider.GetSecretAsync(secretName); + return new[] { secret }; + } + } +} \ No newline at end of file From 4edd6da83ba0079f25b9df9a4f2f4e84a5c646f5 Mon Sep 17 00:00:00 2001 From: Joachim Goris <23077318+joachimgoris@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:42:07 +0100 Subject: [PATCH 09/13] Apply PR comments --- .../IFunctionHostBuilderExtensions.cs | 2 ++ .../SecretProviderCachingExtensions.cs | 5 +++- .../Extensions/IHostBuilderExtensions.cs | 2 ++ .../Extensions/ISecretProviderExtensions.cs | 10 ++++--- .../IServiceCollectionExtensions.cs | 1 + .../SecretStoreBuilderExtensions.cs | 28 +++---------------- .../Providers/ConfigurationSecretProvider.cs | 4 +-- .../EnvironmentVariableSecretProvider.cs | 4 +-- .../MutatedSecretNameCachedSecretProvider.cs | 4 +-- .../MutatedSecretNameSecretProvider.cs | 21 +++++++++----- .../Hosting/HashiCorpVaultTestServer.cs | 22 +++++++++++---- 11 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs b/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs index 3b9826d9..da4fd9b7 100644 --- a/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs +++ b/src/Arcus.Security.AzureFunctions/Extensions/IFunctionHostBuilderExtensions.cs @@ -25,6 +25,7 @@ public static IFunctionsHostBuilder ConfigureSecretStore(this IFunctionsHostBuil { throw new ArgumentNullException(nameof(functionsHostBuilder), "Requires a functions host builder to add the secret store"); } + if (configureSecretStores is null) { throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to configure the secret store with potential secret providers"); @@ -48,6 +49,7 @@ public static IFunctionsHostBuilder ConfigureSecretStore( { throw new ArgumentNullException(nameof(functionsHostBuilder), "Requires a functions host builder to add the secret store"); } + if (configureSecretStores is null) { throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to configure the secret store with potential secret providers"); diff --git a/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs b/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs index aa47cd6b..aa0c6328 100644 --- a/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs +++ b/src/Arcus.Security.Core/Caching/SecretProviderCachingExtensions.cs @@ -24,10 +24,12 @@ public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvi { throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); } + if (cachingDuration < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(cachingDuration), "Requires a positive time duration in which the caching should take place"); } + if (memoryCache is null) { throw new ArgumentNullException(nameof(memoryCache), "Requires a memory caching implementation to include caching while retrieving secrets"); @@ -51,9 +53,10 @@ public static ICachedSecretProvider WithCaching(this ISecretProvider secretProvi { throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider instance to include caching while retrieving secrets"); } + if (cachingDuration < TimeSpan.Zero) { - throw new ArgumentOutOfRangeException(nameof(cachingDuration), "Requires a positive time duration in which the caching should take place"); + throw new ArgumentOutOfRangeException(nameof(cachingDuration), cachingDuration, "Requires a positive time duration in which the caching should take place"); } return new CachedSecretProvider(secretProvider, new CacheConfiguration(cachingDuration)); diff --git a/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs b/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs index c6dda0ab..d3a965b5 100644 --- a/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/IHostBuilderExtensions.cs @@ -24,6 +24,7 @@ public static IHostBuilder ConfigureSecretStore(this IHostBuilder hostBuilder, A { throw new ArgumentNullException(nameof(hostBuilder), "Requires a host builder to add the secret store"); } + if (configureSecretStores is null) { throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); @@ -44,6 +45,7 @@ public static IHostBuilder ConfigureSecretStore(this IHostBuilder hostBuilder, A { throw new ArgumentNullException(nameof(hostBuilder), "Requires a host builder to add the secret store"); } + if (configureSecretStores is null) { throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); diff --git a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs index 155bd608..418c1eb5 100644 --- a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.cs @@ -26,9 +26,10 @@ public static string GetRawSecret(this ISecretProvider secretProvider, string se { throw new ArgumentNullException(nameof(secretProvider), "Requires a secret provider to synchronously look up the secret"); } + if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret", nameof(secretName)); } if (secretProvider is ISyncSecretProvider composite) @@ -55,9 +56,10 @@ public static Secret GetSecret(this ISecretProvider secretProvider, string secre { throw new ArgumentNullException(nameof(secretProvider } + if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret", nameof(secretName)); } if (secretProvider is ISyncSecretProvider composite) @@ -86,7 +88,7 @@ public static async Task> GetRawSecretsAsync(this ISecretPro { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret", nameof(secretName)); } if (secretProvider is CompositeSecretProvider composite) @@ -115,7 +117,7 @@ public static async Task> GetSecretsAsync(this ISecretProvid { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret", nameof(secretName)); } if (secretProvider is CompositeSecretProvider composite) diff --git a/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs b/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs index 1fcec367..cf336d06 100644 --- a/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/IServiceCollectionExtensions.cs @@ -23,6 +23,7 @@ public static IServiceCollection AddSecretStore(this IServiceCollection services { throw new ArgumentNullException(nameof(services), "Requires a set of services to add the secret store"); } + if (configureSecretStores is null) { throw new ArgumentNullException(nameof(configureSecretStores), "Requires a function to register the secret providers in the secret store"); diff --git a/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs b/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs index 8fdba1a8..cc495966 100644 --- a/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs +++ b/src/Arcus.Security.Core/Extensions/SecretStoreBuilderExtensions.cs @@ -24,18 +24,7 @@ public static SecretStoreBuilder AddEnvironmentVariables( EnvironmentVariableTarget target = EnvironmentVariableSecretProvider.DefaultTarget, string prefix = null, Func mutateSecretName = null) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the environment secrets"); - } - if (!Enum.IsDefined(typeof(EnvironmentVariableTarget), target)) - { - throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); - } - - return AddEnvironmentVariables(builder, target, prefix, name: null, mutateSecretName: mutateSecretName); - } + => AddEnvironmentVariables(builder, target, prefix, name: null, mutateSecretName: mutateSecretName); /// /// Adds a secret source to the secret store of the application that gets its secrets from the environment. @@ -58,6 +47,7 @@ public static SecretStoreBuilder AddEnvironmentVariables( { throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the environment secrets"); } + if (!Enum.IsDefined(typeof(EnvironmentVariableTarget), target)) { throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); @@ -81,18 +71,7 @@ public static SecretStoreBuilder AddConfiguration( this SecretStoreBuilder builder, IConfiguration configuration, Func mutateSecretName = null) - { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the configuration secrets"); - } - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); - } - - return AddConfiguration(builder, configuration, name: null, mutateSecretName: mutateSecretName); - } + => AddConfiguration(builder, configuration, name: null, mutateSecretName: mutateSecretName); /// /// Adds a secret source to the secret store of the application that gets its secrets from the . @@ -112,6 +91,7 @@ public static SecretStoreBuilder AddConfiguration( { throw new ArgumentNullException(nameof(builder), "Requires a secret store builder to add the configuration secrets"); } + if (configuration is null) { throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the secrets from"); diff --git a/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs b/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs index 6bf1a628..c55331b4 100644 --- a/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs @@ -36,7 +36,7 @@ public Task GetSecretAsync(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret configuration value", nameof(secretName)); } Secret secret = GetSecret(secretName); @@ -94,7 +94,7 @@ public string GetRawSecret(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret configuration value", nameof(secretName)); } string secretValue = _configuration[secretName]; diff --git a/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs b/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs index 93ff3e75..000f1be7 100644 --- a/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs @@ -23,7 +23,7 @@ public EnvironmentVariableSecretProvider(EnvironmentVariableTarget target = Defa { if (!Enum.IsDefined(typeof(EnvironmentVariableTarget), target)) { - throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'"); + throw new ArgumentException($"Requires an environment variable target of either '{EnvironmentVariableTarget.Process}', '{EnvironmentVariableTarget.Machine}', or '{EnvironmentVariableTarget.User}'", nameof(target)); } _prefix = prefix ?? String.Empty; @@ -102,7 +102,7 @@ public string GetRawSecret(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the environment secret", nameof(secretName)); } string environmentVariable = Environment.GetEnvironmentVariable(_prefix + secretName, _target); diff --git a/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs b/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs index 3d13ddb1..ddb54873 100644 --- a/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs @@ -54,7 +54,7 @@ public async Task GetRawSecretAsync(string secretName, bool ignoreCache) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } string secretValue = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => @@ -78,7 +78,7 @@ public async Task GetSecretAsync(string secretName, bool ignoreCache) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } Secret secret = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => diff --git a/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs b/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs index 5ad3d4b1..3650006e 100644 --- a/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs @@ -28,6 +28,7 @@ public MutatedSecretNameSecretProvider(ISecretProvider implementation, FuncThe secret was not found, using the given name public async Task GetRawSecretAsync(string secretName) { - if (string.IsNullOrWhiteSpace(secretName), "Requires a non-blank secret name when mutating secret names"); + if (string.IsNullOrWhiteSpace(secretName)) + { + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); + } string secretValue = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => { @@ -76,7 +80,7 @@ public async Task GetSecretAsync(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } Secret secret = await SafeguardMutateSecretAsync(secretName, mutatedSecretName => @@ -120,7 +124,7 @@ public Secret GetSecret(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } Secret secret = SafeguardMutateSecret(secretName, mutatedSecretName => @@ -142,8 +146,9 @@ protected async Task SafeguardMutateSecretAsync(string secretName, Func SafeguardMutateSecretAsync(string secretName, Func(string secretName, Func afterMut { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } + if (afterMutation is null) { throw new ArgumentNullException(nameof(afterMutation), "Requires a function to run after the secret name mutation"); @@ -242,7 +249,7 @@ private string MutateSecretName(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } try diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs index e8349203..2ae164e9 100644 --- a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs +++ b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs @@ -46,14 +46,17 @@ private HashiCorpVaultTestServer(Process process, string rootToken, string liste { throw new ArgumentNullException(nameof(process)); } + if (string.IsNullOrWhiteSpace(rootToken)) { throw new ArgumentNullException(nameof(rootToken)); } + if (string.IsNullOrWhiteSpace(listenAddress)) { throw new ArgumentNullException(nameof(listenAddress)); } + if (logger is null) { throw new ArgumentNullException(nameof(logger)); @@ -99,6 +102,7 @@ public static async Task StartServerAsync(TestConfig c { throw new ArgumentNullException(nameof(logger), "Requires a logger for logging diagnostic trace messages during the lifetime of the test server"); } + if (configuration is null) { throw new ArgumentNullException(nameof(configuration), "Requires a configuration instance to retrieve the HashiCorp Vault installation folder"); @@ -203,8 +207,9 @@ public async Task MountKeyValueAsync(string path, VaultKeyValueSecretEngineVersi { if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentNullException(nameof(path), "Requires a path to mount the KeyValue secret engine to"); + throw new ArgumentException("Requires a path to mount the KeyValue secret engine to", nameof(path)); } + if (!Enum.IsDefined(typeof(VaultKeyValueSecretEngineVersion), version)) { throw new ArgumentException("Requires a KeyValue secret engine version that is either V1 or V2", nameof(version)); @@ -236,14 +241,17 @@ public async Task AddPolicyAsync(string name, string path, string[] capabilities { throw new ArgumentNullException(nameof(name), "Requires a name to identify the policy"); } + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException(nameof(path), "Requires a path where the policy will be applicable"); } + if (capabilities is null || !capabilities.Any()) { throw new ArgumentNullException(nameof(capabilities), "Requires a set of capabilities that should be available in this policy"); } + if (capabilities.Any(string.IsNullOrWhiteSpace)) { throw new ArgumentException("Requires all the capabilities of the policy to be filled out (not blank)", nameof(capabilities)); @@ -265,7 +273,7 @@ public async Task EnableAuthenticationTypeAsync(string type, string description) { if (string.IsNullOrWhiteSpace(type)) { - throw new ArgumentNullException(nameof(type), "Requires an authentication type to enable the authentication"); + throw new ArgumentException("Requires an authentication type to enable the authentication", nameof(type)); } await _systemEndpoint.EnableAuth(path: type, authType: type, description: description); @@ -283,15 +291,17 @@ public async Task AddUserPassUserAsync(string username, string password, string { if (string.IsNullOrWhiteSpace(username)) { - throw new ArgumentNullException(nameof(username)); + throw new ArgumentNullException("Requires a non-blank user name", nameof(username)); } + if (string.IsNullOrWhiteSpace(password)) { - throw new ArgumentNullException(nameof(password)); + throw new ArgumentNullException("Requires a non-blank password", nameof(password)); } + if (string.IsNullOrWhiteSpace(policyName)) { - throw new ArgumentNullException(nameof(policyName)); + throw new ArgumentNullException("Requires a non-blank policy name", nameof(policyName)); } await _authenticationEndpoint.Write($"/userpass/users/{username}", new UsersRequest @@ -340,10 +350,12 @@ protected PolicyResult RetryAction(Action action, int timeoutInSeconds = 30, int { throw new ArgumentNullException(nameof(action), "Requires disposing function to be retried"); } + if (timeoutInSeconds < 0) { throw new ArgumentOutOfRangeException(nameof(timeoutInSeconds), "Requires a timeout (in sec) greater than zero"); } + if (retryIntervalInSeconds < 0) { throw new ArgumentOutOfRangeException(nameof(retryIntervalInSeconds), "Requires a retry interval (in sec) greater than zero"); From ec394f3050e3a4756f6d5910ab2b02def62675fe Mon Sep 17 00:00:00 2001 From: Frederik Gheysels Date: Wed, 5 Feb 2025 09:44:21 +0100 Subject: [PATCH 10/13] Update src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs Co-authored-by: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> --- .../Providers/MutatedSecretNameCachedSecretProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs b/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs index ddb54873..994f12e5 100644 --- a/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/MutatedSecretNameCachedSecretProvider.cs @@ -98,7 +98,7 @@ public async Task InvalidateSecretAsync(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } await SafeguardMutateSecretAsync(secretName, async mutatedSecretName => From 4f34bf67f622db1c89647f4817527470a879dc1d Mon Sep 17 00:00:00 2001 From: Frederik Gheysels Date: Wed, 5 Feb 2025 09:45:02 +0100 Subject: [PATCH 11/13] Update src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs Co-authored-by: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> --- .../Providers/MutatedSecretNameSecretProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs b/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs index 3650006e..7a314a7d 100644 --- a/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/MutatedSecretNameSecretProvider.cs @@ -102,7 +102,7 @@ public string GetRawSecret(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name when mutating secret names"); + throw new ArgumentException("Requires a non-blank secret name when mutating secret names", nameof(secretName)); } string secretValue = SafeguardMutateSecret(secretName, mutatedSecretName => From 71366500d7f2b97a57a5107e9576d2f8d503624c Mon Sep 17 00:00:00 2001 From: Joachim Goris Date: Wed, 5 Feb 2025 23:50:22 +0100 Subject: [PATCH 12/13] Corrected exception in missed files --- .../Providers/ConfigurationSecretProvider.cs | 4 ++-- .../Providers/EnvironmentVariableSecretProvider.cs | 6 +++--- .../HashiCorp/Hosting/HashiCorpVaultTestServer.cs | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs b/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs index c55331b4..d1d13b90 100644 --- a/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/ConfigurationSecretProvider.cs @@ -53,7 +53,7 @@ public Task GetRawSecretAsync(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret configuration value", nameof(secretName)); } string secretValue = GetRawSecret(secretName); @@ -71,7 +71,7 @@ public Secret GetSecret(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the secret configuration value"); + throw new ArgumentException("Requires a non-blank secret name to look up the secret configuration value", nameof(secretName)); } string secretValue = GetRawSecret(secretName); diff --git a/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs b/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs index 000f1be7..9ea91550 100644 --- a/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs +++ b/src/Arcus.Security.Core/Providers/EnvironmentVariableSecretProvider.cs @@ -42,7 +42,7 @@ public Task GetSecretAsync(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the environment secret", nameof(secretName)); } Secret secret = GetSecret(secretName); @@ -61,7 +61,7 @@ public Task GetRawSecretAsync(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the environment secret", nameof(secretName)); } string secretValue = GetRawSecret(secretName); @@ -79,7 +79,7 @@ public Secret GetSecret(string secretName) { if (string.IsNullOrWhiteSpace(secretName)) { - throw new ArgumentNullException(nameof(secretName), "Requires a non-blank secret name to look up the environment secret"); + throw new ArgumentException("Requires a non-blank secret name to look up the environment secret", nameof(secretName)); } string secretValue = GetRawSecret(secretName); diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs index 2ae164e9..3c0e4a40 100644 --- a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs +++ b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs @@ -49,12 +49,12 @@ private HashiCorpVaultTestServer(Process process, string rootToken, string liste if (string.IsNullOrWhiteSpace(rootToken)) { - throw new ArgumentNullException(nameof(rootToken)); + throw new ArgumentException(nameof(rootToken)); } if (string.IsNullOrWhiteSpace(listenAddress)) { - throw new ArgumentNullException(nameof(listenAddress)); + throw new ArgumentException(nameof(listenAddress)); } if (logger is null) @@ -239,12 +239,12 @@ public async Task AddPolicyAsync(string name, string path, string[] capabilities { if (string.IsNullOrWhiteSpace(name)) { - throw new ArgumentNullException(nameof(name), "Requires a name to identify the policy"); + throw new ArgumentException("Requires a name to identify the policy", nameof(name)); } if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentNullException(nameof(path), "Requires a path where the policy will be applicable"); + throw new ArgumentException("Requires a path where the policy will be applicable", nameof(path)); } if (capabilities is null || !capabilities.Any()) @@ -291,17 +291,17 @@ public async Task AddUserPassUserAsync(string username, string password, string { if (string.IsNullOrWhiteSpace(username)) { - throw new ArgumentNullException("Requires a non-blank user name", nameof(username)); + throw new ArgumentException("Requires a non-blank user name", nameof(username)); } if (string.IsNullOrWhiteSpace(password)) { - throw new ArgumentNullException("Requires a non-blank password", nameof(password)); + throw new ArgumentException("Requires a non-blank password", nameof(password)); } if (string.IsNullOrWhiteSpace(policyName)) { - throw new ArgumentNullException("Requires a non-blank policy name", nameof(policyName)); + throw new ArgumentException("Requires a non-blank policy name", nameof(policyName)); } await _authenticationEndpoint.Write($"/userpass/users/{username}", new UsersRequest From 66e8304eed89f7399cf4137f49d50f229962da1d Mon Sep 17 00:00:00 2001 From: Joachim Goris Date: Fri, 7 Feb 2025 14:27:13 +0100 Subject: [PATCH 13/13] Replace ArgumentNullException with ArgumentException --- .../HashiCorp/Hosting/HashiCorpVaultTestServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs index 2ae164e9..ac60a211 100644 --- a/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs +++ b/src/Arcus.Security.Tests.Integration/HashiCorp/Hosting/HashiCorpVaultTestServer.cs @@ -249,7 +249,7 @@ public async Task AddPolicyAsync(string name, string path, string[] capabilities if (capabilities is null || !capabilities.Any()) { - throw new ArgumentNullException(nameof(capabilities), "Requires a set of capabilities that should be available in this policy"); + throw new ArgumentException("Requires a set of capabilities that should be available in this policy", nameof(capabilities)); } if (capabilities.Any(string.IsNullOrWhiteSpace))