diff --git a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/TypeAuth.cs b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/TypeAuth.cs new file mode 100644 index 00000000..a15cb100 --- /dev/null +++ b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/TypeAuth.cs @@ -0,0 +1,24 @@ +namespace CodeDesignPlus.Net.Vault.Abstractions.Options; + +/// +/// Type of authentication to use in the Vault +/// +public enum TypeAuth +{ + /// + /// None authentication + /// + None, + /// + /// Token authentication + /// + Token, + /// + /// AppRole authentication + /// + AppRole, + /// + /// Kubernetes authentication + /// + Kubernetes +} diff --git a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/VaultOptions.cs b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/VaultOptions.cs index d29df537..0733be11 100644 --- a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/VaultOptions.cs +++ b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault.Abstractions/Options/VaultOptions.cs @@ -12,6 +12,31 @@ public class VaultOptions : IValidatableObject /// public static readonly string Section = "Vault"; /// + /// Gets the type of authentication to use in the Vault + /// + public TypeAuth TypeAuth + { + get + { + if (!string.IsNullOrEmpty(this.Token)) + return TypeAuth.Token; + else if (!string.IsNullOrEmpty(this.RoleId) && !string.IsNullOrEmpty(this.SecretId)) + return TypeAuth.AppRole; + else if (this.Kubernetes != null && this.Kubernetes.Enable) + return TypeAuth.Kubernetes; + + return TypeAuth.None; + } + } + /// + /// Gets or sets the enable of the Vault server + /// + public bool Enable { get; set; } + /// + /// Gets or sets the token of the Vault server + /// + public string Token { get; set; } + /// /// Gets or sets the address of the Vault server /// [Required] @@ -69,10 +94,8 @@ public IEnumerable Validate(ValidationContext validationContex { var results = new List(); - if (string.IsNullOrEmpty(this.RoleId) && string.IsNullOrEmpty(this.SecretId) && this.Kubernetes != null && !this.Kubernetes.Enable) - { - results.Add(new ValidationResult("The RoleId and SecretId is required.")); - } + if (this.TypeAuth == TypeAuth.None) + results.Add(new ValidationResult("The TypeAuth is required.")); if (this.Mongo != null && this.Mongo.Enable) { diff --git a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Extensions/VaultExtensions.cs b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Extensions/VaultExtensions.cs index 626e566b..a47e7b4f 100644 --- a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Extensions/VaultExtensions.cs +++ b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Extensions/VaultExtensions.cs @@ -42,19 +42,18 @@ public static IServiceCollection AddVault(this IServiceCollection services, ICon /// /// The to add configuration to. /// An action to configure the . - /// Thrown if or is null. + /// Thrown if is null. /// Thrown if the Vault configuration section does not exist. /// The updated . - public static IConfigurationBuilder AddVault(this IConfigurationBuilder builder, Action options) + public static IConfigurationBuilder AddVault(this IConfigurationBuilder builder, Action options = null) { ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(options); var configuration = builder.Build(); var vaultOptions = configuration.GetSection(VaultOptions.Section).Get(); - options.Invoke(vaultOptions); + options?.Invoke(vaultOptions); var source = new VaultConfigurationSource(vaultOptions); diff --git a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Services/VaultClientFactory.cs b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Services/VaultClientFactory.cs index be472f3c..fb93e7bb 100644 --- a/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Services/VaultClientFactory.cs +++ b/packages/CodeDesignPlus.Net.Vault/src/CodeDesignPlus.Net.Vault/Services/VaultClientFactory.cs @@ -1,3 +1,5 @@ +using VaultSharp.V1.AuthMethods.Token; + namespace CodeDesignPlus.Net.Vault.Services; /// @@ -15,22 +17,23 @@ public static IVaultClient Create(VaultOptions options) { ArgumentNullException.ThrowIfNull(options); - var vaultClientSettings = new VaultClientSettings( - options.Address, - new AppRoleAuthMethodInfo(options.RoleId, options.SecretId) - ); + if (options.TypeAuth == TypeAuth.Token) + return new VaultClient(new VaultClientSettings(options.Address, new TokenAuthMethodInfo(options.Token))); + + if (options.TypeAuth == TypeAuth.AppRole) + return new VaultClient(new VaultClientSettings(options.Address, new AppRoleAuthMethodInfo(options.RoleId, options.SecretId))); - if (options.Kubernetes.Enable) + if (options.TypeAuth == TypeAuth.Kubernetes) { var jwt = File.ReadAllText(options.Kubernetes.PathTokenKubernetes); - vaultClientSettings = new VaultClientSettings( + return new VaultClient(new VaultClientSettings( options.Address, new KubernetesAuthMethodInfo($"{options.AppName}-{options.Kubernetes.RoleSufix}", jwt) - ); + )); } - return new VaultClient(vaultClientSettings); + throw new VaultException("The authentication type is not defined."); } } diff --git a/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Extensions/VaultExtensionsTest.cs b/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Extensions/VaultExtensionsTest.cs index 5b480b4b..f4cdc7c4 100644 --- a/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Extensions/VaultExtensionsTest.cs +++ b/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Extensions/VaultExtensionsTest.cs @@ -140,4 +140,50 @@ public void AddVault_ConfigurationBuilder_OvverideAppSettings() Assert.NotNull(server); } + [Fact] + public void AddVault_ConfigurationBuilder_TokenAppSettings() + { + var server = new TestServer(new WebHostBuilder() + .ConfigureAppConfiguration((context, builder) => + { + builder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); + + builder.AddVault(options => + { + options.Address = $"http://localhost:{fixture.Container.Port}"; + options.Token = "root"; + options.Solution = "unit-test"; + options.KeyVault.Enable = true; + options.Mongo.Enable = true; + options.RabbitMQ.Enable = true; + options.AppName = "my-app"; + }); + }).ConfigureServices(services => + { + + }).Configure(app => + { + var configuration = app.ApplicationServices.GetRequiredService(); + + var securityOptions = configuration.GetSection("Security").Get(); + var mongoOptions = configuration.GetSection("Mongo").Get(); + var rabbitMQOptions = configuration.GetSection("RabbitMQ").Get(); + + Assert.NotNull(securityOptions); + Assert.NotEmpty(securityOptions.ValidAudiences); + Assert.NotNull(securityOptions.ClientId); + + Assert.NotNull(mongoOptions); + Assert.NotNull(mongoOptions.ConnectionString); + Assert.NotEqual("mongodb://localhost:27017", mongoOptions.ConnectionString); + + Assert.NotNull(rabbitMQOptions); + Assert.NotNull(rabbitMQOptions.UserName); + Assert.NotNull(rabbitMQOptions.Password); + }) + ); + + Assert.NotNull(server); + } + } diff --git a/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Options/VaultOptionsTest.cs b/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Options/VaultOptionsTest.cs index 50492ede..1c899fab 100644 --- a/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Options/VaultOptionsTest.cs +++ b/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Options/VaultOptionsTest.cs @@ -55,12 +55,12 @@ public void VaultOptions_InvalidValues_Failed() // Assert Assert.NotEmpty(results); Assert.Contains(results, x => x.ErrorMessage == "The Address field is required."); - Assert.Contains(results, x => x.ErrorMessage == "The RoleId and SecretId is required."); Assert.Contains(results, x => x.ErrorMessage == "The AppName field is required."); Assert.Contains(results, x => x.ErrorMessage == "The Solution field is required."); Assert.Contains(results, x => x.ErrorMessage == "The RoleSufix field is required."); Assert.Contains(results, x => x.ErrorMessage == "The SufixMoundPoint field is required."); Assert.Contains(results, x => x.ErrorMessage == "The TemplateConnectionString field is required."); + Assert.Contains(results, x => x.ErrorMessage == "The TypeAuth is required."); } [Fact] @@ -114,5 +114,4 @@ public void VaultOptions_KubernetesValues_Valid() // Assert Assert.Empty(results); } - } diff --git a/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Services/VaultClientFactoryTest.cs b/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Services/VaultClientFactoryTest.cs index c5a53a8b..b3b1a954 100644 --- a/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Services/VaultClientFactoryTest.cs +++ b/packages/CodeDesignPlus.Net.Vault/tests/CodeDesignPlus.Net.Vault.Test/Services/VaultClientFactoryTest.cs @@ -13,7 +13,7 @@ public void CreateClient_OptionsIsNull_ThrowArgumentNullException() // Act var exception = Assert.Throws(() => VaultClientFactory.Create(options)); - + // Assert Assert.Equal("Value cannot be null. (Parameter 'options')", exception.Message); } @@ -40,14 +40,12 @@ public void CreateClient_KubernetesEnableIsFalse_ReturnVaultClient() } [Fact] - public void CreateClient_KubernetesEnableIsTrue_ReturnVaultClient() + public void CreateClient_KubernetesAuth_ReturnVaultClient() { // Arrange var options = new VaultOptions { Address = "http://localhost:8200", - RoleId = "role-id", - SecretId = "secret-id", AppName = "app-name" }; @@ -60,4 +58,21 @@ public void CreateClient_KubernetesEnableIsTrue_ReturnVaultClient() // Assert Assert.NotNull(client); } + + [Fact] + public void CreateClient_ThrowVaultException_InvalidAuth() + { + // Arrange + var options = new VaultOptions + { + Address = "http://localhost:8200", + AppName = "app-name" + }; + + // Act + var exception = Assert.Throws(() => VaultClientFactory.Create(options)); + + // Assert + Assert.Equal("The authentication type is not defined.", exception.Message); + } } diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/CodeDesignPlus.Net.xUnit.csproj b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/CodeDesignPlus.Net.xUnit.csproj index 24817d24..18aa0f10 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/CodeDesignPlus.Net.xUnit.csproj +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/CodeDesignPlus.Net.xUnit.csproj @@ -99,7 +99,4 @@ Always - - - \ No newline at end of file diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/docker-compose.yml b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/docker-compose.yml index 0121ecb0..9cc06d1a 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/docker-compose.yml +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/docker-compose.yml @@ -5,7 +5,6 @@ services: image: hashicorp/vault:latest ports: - "0:8200" - restart: unless-stopped environment: VAULT_DEV_ROOT_TOKEN_ID: "root" VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200" @@ -18,8 +17,9 @@ services: - ./resources/entrypoint.sh:/resources/entrypoint.sh cap_add: - IPC_LOCK - command: /bin/sh -c "chmod +x /resources/entrypoint.sh && chmod +x /resources/config.sh && /resources/entrypoint.sh" - + entrypoint: /bin/sh -c "chmod +x /resources/entrypoint.sh && chmod +x /resources/config.sh && /resources/entrypoint.sh" + + mongo: image: mongo:latest environment: diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/config.sh b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/config.sh index 96758109..e225194a 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/config.sh +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/config.sh @@ -1,3 +1,5 @@ +#!/bin/sh + export VAULT_ADDR="http://0.0.0.0:8200" vault login token=root diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/entrypoint.sh b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/entrypoint.sh index 14eced32..cee34073 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/entrypoint.sh +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/resources/entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/sh +echo "Hello, world!" echo "Starting Vault server in dev mode..." vault server -dev & diff --git a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/shared/vault-config/credentials.json b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/shared/vault-config/credentials.json index 8e2e9dc3..a4404c76 100644 --- a/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/shared/vault-config/credentials.json +++ b/packages/CodeDesignPlus.Net.xUnit/src/CodeDesignPlus.Net.xUnit/Helpers/VaultContainer/shared/vault-config/credentials.json @@ -1,4 +1,4 @@ { - "role_id": "39d25686-e06b-a1ff-93a7-35eba37e7c6e", - "secret_id": "66615763-1ed1-4963-7ca7-c9d25778b1ab" + "role_id": "d02c6882-3189-a9b7-7dab-8eef2ead8d60", + "secret_id": "382b241b-3446-49b6-30d4-958abed58665" }