diff --git a/src/VaultSharp/V1/SecretsEngines/TOTP/ITOTPSecretsEngine.cs b/src/VaultSharp/V1/SecretsEngines/TOTP/ITOTPSecretsEngine.cs index 47376229..4ef05722 100644 --- a/src/VaultSharp/V1/SecretsEngines/TOTP/ITOTPSecretsEngine.cs +++ b/src/VaultSharp/V1/SecretsEngines/TOTP/ITOTPSecretsEngine.cs @@ -8,45 +8,6 @@ namespace VaultSharp.V1.SecretsEngines.TOTP /// public interface ITOTPSecretsEngine { - /// - /// Generates a new time-based one-time use password based on the named key. - /// - /// [required] - /// Specifies the name of the key to create credentials against. - /// - /// [optional] - /// The mount point for the TOTP backend. Defaults to - /// Provide a value only if you have customized the TOTP mount point. - /// - /// [optional] - /// The TTL for the token and can be either an integer number of seconds or a string duration of seconds. - /// - /// - /// The secret with the as the data. - /// - Task> GetCodeAsync(string keyName, string mountPoint = null, string wrapTimeToLive = null); - - /// - /// Generates a new time-based one-time use password based on the named key. - /// - /// [required] - /// Specifies the name of the key to create credentials against. - /// - /// [required] - /// Specifies the the password you want to validate. - /// - /// [optional] - /// The mount point for the TOTP backend. Defaults to - /// Provide a value only if you have customized the TOTP mount point. - /// - /// [optional] - /// The TTL for the token and can be either an integer number of seconds or a string duration of seconds. - /// - /// - /// The secret with the as the data. - /// - Task> ValidateCodeAsync(string keyName, string code, string mountPoint = null, string wrapTimeToLive = null); - /// /// This endpoint creates or updates a key definition. /// @@ -101,5 +62,44 @@ public interface ITOTPSecretsEngine /// The mount point for the TOTP backend. Defaults to /// Provide a value only if you have customized the TOTP mount point. Task DeleteKeyAsync(string keyName, string mountPoint = null); + + /// + /// Generates a new time-based one-time use password based on the named key. + /// + /// [required] + /// Specifies the name of the key to create credentials against. + /// + /// [optional] + /// The mount point for the TOTP backend. Defaults to + /// Provide a value only if you have customized the TOTP mount point. + /// + /// [optional] + /// The TTL for the token and can be either an integer number of seconds or a string duration of seconds. + /// + /// + /// The secret with the as the data. + /// + Task> GetCodeAsync(string keyName, string mountPoint = null, string wrapTimeToLive = null); + + /// + /// Generates a new time-based one-time use password based on the named key. + /// + /// [required] + /// Specifies the name of the key to create credentials against. + /// + /// [required] + /// Specifies the the password you want to validate. + /// + /// [optional] + /// The mount point for the TOTP backend. Defaults to + /// Provide a value only if you have customized the TOTP mount point. + /// + /// [optional] + /// The TTL for the token and can be either an integer number of seconds or a string duration of seconds. + /// + /// + /// The secret with the as the data. + /// + Task> ValidateCodeAsync(string keyName, string code, string mountPoint = null, string wrapTimeToLive = null); } } \ No newline at end of file diff --git a/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPKey.cs b/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPKey.cs index 15dc2a62..c1a8e4a0 100644 --- a/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPKey.cs +++ b/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPKey.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace VaultSharp.V1.SecretsEngines.TOTP { @@ -40,6 +37,6 @@ public class TOTPKey /// create a counter for the TOTP code calculation. /// [JsonProperty("period")] - public string Period { get; set; } + public long Period { get; set; } } } diff --git a/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPSecretsEngineProvider.cs b/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPSecretsEngineProvider.cs index 2eff1ad4..4b4e5b7b 100644 --- a/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPSecretsEngineProvider.cs +++ b/src/VaultSharp/V1/SecretsEngines/TOTP/TOTPSecretsEngineProvider.cs @@ -14,22 +14,6 @@ public TOTPSecretsEngineProvider(Polymath polymath) _polymath = polymath; } - public async Task> GetCodeAsync(string keyName, string mountPoint = null, string wrapTimeToLive = null) - { - Checker.NotNull(keyName, "keyName"); - - return await _polymath.MakeVaultApiRequest>(mountPoint ?? _polymath.VaultClientSettings.SecretsEngineMountPoints.TOTP, "/code/" + keyName.Trim('/'), HttpMethod.Get, wrapTimeToLive: wrapTimeToLive).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); - } - - public async Task> ValidateCodeAsync(string keyName, string code, string mountPoint = null, string wrapTimeToLive = null) - { - Checker.NotNull(keyName, "keyName"); - Checker.NotNull(code, "code"); - - var requestData = new { code = code }; - return await _polymath.MakeVaultApiRequest>(mountPoint ?? _polymath.VaultClientSettings.SecretsEngineMountPoints.TOTP, "/code/" + keyName.Trim('/'), HttpMethod.Post, requestData, wrapTimeToLive: wrapTimeToLive).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); - } - public async Task> CreateKeyAsync(string keyName, TOTPCreateKeyRequest createKeyRequest, string mountPoint) { Checker.NotNull(keyName, "keyName"); @@ -95,5 +79,21 @@ public async Task DeleteKeyAsync(string keyName, string mountPoint = null) await _polymath.MakeVaultApiRequest(mountPoint ?? _polymath.VaultClientSettings.SecretsEngineMountPoints.TOTP, "/keys/" + keyName.Trim('/'), HttpMethod.Delete).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); } + + public async Task> GetCodeAsync(string keyName, string mountPoint = null, string wrapTimeToLive = null) + { + Checker.NotNull(keyName, "keyName"); + + return await _polymath.MakeVaultApiRequest>(mountPoint ?? _polymath.VaultClientSettings.SecretsEngineMountPoints.TOTP, "/code/" + keyName.Trim('/'), HttpMethod.Get, wrapTimeToLive: wrapTimeToLive).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); + } + + public async Task> ValidateCodeAsync(string keyName, string code, string mountPoint = null, string wrapTimeToLive = null) + { + Checker.NotNull(keyName, "keyName"); + Checker.NotNull(code, "code"); + + var requestData = new { code = code }; + return await _polymath.MakeVaultApiRequest>(mountPoint ?? _polymath.VaultClientSettings.SecretsEngineMountPoints.TOTP, "/code/" + keyName.Trim('/'), HttpMethod.Post, requestData, wrapTimeToLive: wrapTimeToLive).ConfigureAwait(_polymath.VaultClientSettings.ContinueAsyncTasksOnCapturedContext); + } } } \ No newline at end of file diff --git a/test/VaultSharp.Samples/Backends/Secrets/TOTPSecretsBackendSamples.cs b/test/VaultSharp.Samples/Backends/Secrets/TOTPSecretsBackendSamples.cs new file mode 100644 index 00000000..866cb560 --- /dev/null +++ b/test/VaultSharp.Samples/Backends/Secrets/TOTPSecretsBackendSamples.cs @@ -0,0 +1,110 @@ +using System.Linq; +using System; +using Xunit; +using VaultSharp.V1.SecretsEngines; +using VaultSharp.V1.SecretsEngines.TOTP; + +namespace VaultSharp.Samples +{ + partial class Program + { + private static void RunTOTPSecretsBackendSamples() + { + var mountPoint = Guid.NewGuid().ToString(); + + var totpSecretsEngine = new SecretsEngine + { + Type = SecretsEngineType.TOTP, + Path = mountPoint + }; + + _authenticatedVaultClient.V1.System.MountSecretBackendAsync(totpSecretsEngine).Wait(); + + // Create key 1 + + var keyName = Guid.NewGuid().ToString(); + var createKeyRequest = new TOTPCreateKeyRequest() + { + KeyGenerationOption = new TOTPVaultBasedKeyGeneration + { + Exported = true, + KeySize = 32, + Issuer = "raja-issuer", + AccountName = "raja-account-name", + QRSize = 200, + Skew = 1 + }, + AccountName = "raja-account-name", + Algorithm = "SHA512", + Issuer = "raja-issuer" + }; + + var createKeyResponse = _authenticatedVaultClient.V1.Secrets.TOTP.CreateKeyAsync(keyName, createKeyRequest, mountPoint).Result; + DisplayJson(createKeyResponse); + Assert.NotNull(createKeyResponse.Data.Url); + Assert.NotNull(createKeyResponse.Data.Barcode); + + // Read key 1 + + var retrievedKey = _authenticatedVaultClient.V1.Secrets.TOTP.ReadKeyAsync(keyName, mountPoint).Result; + DisplayJson(retrievedKey); + Assert.Equal(createKeyRequest.AccountName, retrievedKey.Data.AccountName); + + // Create key 2 + + var keyName2 = Guid.NewGuid().ToString(); + var createKeyRequest2 = new TOTPCreateKeyRequest() + { + KeyGenerationOption = new TOTPVaultBasedKeyGeneration + { + Exported = true, + KeySize = 64, + Issuer = "raja-issuer2", + AccountName = "raja-account-name2", + QRSize = 200, + Skew = 0 + }, + AccountName = "raja-account-name2", + Algorithm = "SHA256", + Issuer = "raja-issuer2" + + }; + + var createKeyResponse2 = _authenticatedVaultClient.V1.Secrets.TOTP.CreateKeyAsync(keyName2, createKeyRequest2, mountPoint).Result; + DisplayJson(createKeyResponse2); + Assert.NotNull(createKeyResponse2.Data.Url); + Assert.NotNull(createKeyResponse2.Data.Barcode); + + // Read all keys + + var allKeys = _authenticatedVaultClient.V1.Secrets.TOTP.ReadAllKeysAsync(mountPoint).Result; + DisplayJson(allKeys); + Assert.True(allKeys.Data.Keys.Count() == 2); + + // Delete key 2 + + _authenticatedVaultClient.V1.Secrets.TOTP.DeleteKeyAsync(keyName2, mountPoint).Wait(); + allKeys = _authenticatedVaultClient.V1.Secrets.TOTP.ReadAllKeysAsync(mountPoint).Result; + DisplayJson(allKeys); + Assert.True(allKeys.Data.Keys.Count() == 1); + + // generate code + var generatedCode = _authenticatedVaultClient.V1.Secrets.TOTP.GetCodeAsync(keyName, mountPoint).Result; + DisplayJson(generatedCode); + Assert.NotNull(generatedCode.Data.Code); + + // validate code + var validResponse = _authenticatedVaultClient.V1.Secrets.TOTP.ValidateCodeAsync(keyName, generatedCode.Data.Code, mountPoint).Result; + DisplayJson(validResponse); + Assert.True(validResponse.Data.Valid); + + var invalidResponse = _authenticatedVaultClient.V1.Secrets.TOTP.ValidateCodeAsync(keyName, generatedCode.Data.Code + "2", mountPoint).Result; + DisplayJson(invalidResponse); + Assert.False(invalidResponse.Data.Valid); + + // unmount + + _authenticatedVaultClient.V1.System.UnmountSecretBackendAsync(mountPoint).Wait(); + } + } +} \ No newline at end of file diff --git a/test/VaultSharp.Samples/Backends/SecretsBackendSamples.cs b/test/VaultSharp.Samples/Backends/SecretsBackendSamples.cs index 269f17ca..23e5684a 100644 --- a/test/VaultSharp.Samples/Backends/SecretsBackendSamples.cs +++ b/test/VaultSharp.Samples/Backends/SecretsBackendSamples.cs @@ -19,6 +19,9 @@ private static void RunSecretsEngineSamples() Console.WriteLine("\n RunKeyValueSecretsBackendSamples \n"); RunKeyValueSecretsBackendSamples(); + Console.WriteLine("\n RunTOTPSecretsBackendSamples \n"); + RunTOTPSecretsBackendSamples(); + Console.WriteLine("\n RunTransitSecretsBackendSamples \n"); RunTransitSecretsBackendSamples(); }