Skip to content

Commit 74f2456

Browse files
authored
feat(61): implement AdditionalStringsForConfigurationPath (#69)
* feat(61): implement AdditionalStringsForConfigurationPath * chore: made AdditionalCharactersForConfigurationPath obsolete
1 parent f4c294e commit 74f2456

File tree

3 files changed

+45
-14
lines changed

3 files changed

+45
-14
lines changed

Source/VaultSharp.Extensions.Configuration/VaultConfigurationProvider.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public override void Load()
8181
{
8282
if (this.ConfigurationSource.Options.AcceptInsecureConnection)
8383
{
84-
#if NETSTANDARD2_0
84+
#if NETSTANDARD2_0
8585
clientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true;
8686
#else
8787
clientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
@@ -119,7 +119,7 @@ public override void Load()
119119

120120
/// <summary>
121121
/// This will fetch the vault token again before the new operation.
122-
/// Use IConfiguration object: configurationRoot.Providers.OfType&lt;VaultConfigurationProvider&lt;().FirstOrDefault().ResetToken();
122+
/// Use IConfiguration object: configurationRoot.Providers.OfType&lt;VaultConfigurationProvider&lt;().FirstOrDefault().ResetToken();
123123
/// See https://github.com/rajanadar/VaultSharp/blob/34ab400c2a295f4a81d97fc5d65f38509c7e0f05/README.md?plain=1#L92
124124
/// </summary>
125125
public void ResetToken() => this.vaultClient?.V1.Auth.ResetVaultToken();
@@ -146,7 +146,7 @@ private async Task<bool> LoadVaultDataAsync(IVaultClient vaultClient)
146146
{
147147
key = this.ConfigurationSource.Options.KeyPrefix + ":" + key;
148148
}
149-
149+
150150
}
151151
var data = secretData.SecretData.Data;
152152

@@ -292,16 +292,16 @@ private async IAsyncEnumerable<KeyedSecretData> ReadKeysAsync(IVaultClient vault
292292

293293
private string ReplaceTheAdditionalCharactersForConfigurationPath(string inputKey)
294294
{
295-
if (!this.ConfigurationSource.Options.AdditionalCharactersForConfigurationPath.Any())
295+
if (!this.ConfigurationSource.Options.AdditionalStringsForConfigurationPath.Any())
296296
{
297297
return inputKey;
298298
}
299299

300300
var outputKey = new StringBuilder(inputKey);
301301

302-
foreach (var c in this.ConfigurationSource.Options.AdditionalCharactersForConfigurationPath)
302+
foreach (var c in this.ConfigurationSource.Options.AdditionalStringsForConfigurationPath)
303303
{
304-
outputKey.Replace(c, ':');
304+
outputKey.Replace(c, ":");
305305
}
306306

307307
return outputKey.ToString();

Source/VaultSharp.Extensions.Configuration/VaultOptions.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ namespace VaultSharp.Extensions.Configuration
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.Linq;
56
using System.Net.Http;
67
using System.Net.Security;
78
using System.Security.Cryptography.X509Certificates;
@@ -24,6 +25,7 @@ public class VaultOptions
2425
/// <param name="omitVaultKeyName">Omit Vault Key Name in Configuration Keys.</param>
2526
/// <param name="keyPrefix">Store all Vault keys under this prefix </param>
2627
/// <param name="additionalCharactersForConfigurationPath">Additional characters for the Configuration path.</param>
28+
/// <param name="additionalStringsForConfigurationPath">Additional strings for the Configuration path.</param>
2729
/// <param name="namespace">Vault namespace.</param>
2830
/// <param name="alwaysAddTrailingSlashToBasePath">Should a trailing slash be added to the base path. See AlwaysAddTrailingSlashToBasePath property for details </param>
2931
/// <param name="insecureConnection">(Dangerous!) Ignore certificate validation. This implies self-signed certificates are accepted.</param>
@@ -38,6 +40,7 @@ public VaultOptions(
3840
bool omitVaultKeyName = false,
3941
string? keyPrefix = null,
4042
IEnumerable<char>? additionalCharactersForConfigurationPath = null,
43+
IEnumerable<string>? additionalStringsForConfigurationPath = null,
4144
string? @namespace = null,
4245
bool alwaysAddTrailingSlashToBasePath = true,
4346
bool insecureConnection = false,
@@ -51,7 +54,10 @@ public VaultOptions(
5154
this.ReloadCheckIntervalSeconds = reloadCheckIntervalSeconds;
5255
this.OmitVaultKeyName = omitVaultKeyName;
5356
this.KeyPrefix = keyPrefix;
57+
#pragma warning disable CS0618 // Type or member is obsolete
5458
this.AdditionalCharactersForConfigurationPath = additionalCharactersForConfigurationPath ?? Array.Empty<char>();
59+
#pragma warning restore CS0618 // Type or member is obsolete
60+
this.AdditionalStringsForConfigurationPath = [..additionalStringsForConfigurationPath ?? [], ..(additionalCharactersForConfigurationPath ?? []).Select(x => x.ToString())];
5561
this.Namespace = @namespace;
5662
this.AlwaysAddTrailingSlashToBasePath = alwaysAddTrailingSlashToBasePath;
5763
this.AcceptInsecureConnection = insecureConnection;
@@ -67,6 +73,7 @@ public VaultOptions(
6773
/// <param name="reloadCheckIntervalSeconds">Interval in seconds to check Vault for any changes.</param>
6874
/// <param name="omitVaultKeyName">Omit Vault Key Name in Configuration Keys.</param>
6975
/// <param name="additionalCharactersForConfigurationPath">Additional characters for the Configuration path.</param>
76+
/// <param name="additionalStringsForConfigurationPath">Additional strings for the Configuration path.</param>
7077
/// <param name="namespace">Vault namespace.</param>
7178
/// <param name="alwaysAddTrailingSlashToBasePath">Should a trailing slash be added to the base path. See AlwaysAddTrailingSlashToBasePath property for details </param>
7279
/// <param name="insecureConnection">(Dangerous!) Ignore certificate validation. This implies self-signed certificates are accepted.</param>
@@ -78,6 +85,7 @@ public VaultOptions(
7885
int reloadCheckIntervalSeconds = 300,
7986
bool omitVaultKeyName = false,
8087
IEnumerable<char>? additionalCharactersForConfigurationPath = null,
88+
IEnumerable<string>? additionalStringsForConfigurationPath = null,
8189
string? @namespace = null,
8290
bool alwaysAddTrailingSlashToBasePath = true,
8391
bool insecureConnection = false,
@@ -88,7 +96,10 @@ public VaultOptions(
8896
this.ReloadOnChange = reloadOnChange;
8997
this.ReloadCheckIntervalSeconds = reloadCheckIntervalSeconds;
9098
this.OmitVaultKeyName = omitVaultKeyName;
99+
#pragma warning disable CS0618 // Type or member is obsolete
91100
this.AdditionalCharactersForConfigurationPath = additionalCharactersForConfigurationPath ?? Array.Empty<char>();
101+
#pragma warning restore CS0618 // Type or member is obsolete
102+
this.AdditionalStringsForConfigurationPath = [..additionalStringsForConfigurationPath ?? [], ..(additionalCharactersForConfigurationPath ?? []).Select(x => x.ToString())];
92103
this.Namespace = @namespace;
93104
this.AlwaysAddTrailingSlashToBasePath = alwaysAddTrailingSlashToBasePath;
94105
this.AcceptInsecureConnection = insecureConnection;
@@ -143,9 +154,17 @@ public VaultOptions(
143154

144155
/// <summary>
145156
/// Gets an array of characters that will be used as a path to form the Configuration.
157+
/// This may not be equal to <see cref="AdditionalStringsForConfigurationPath"/>.
146158
/// </summary>
159+
[Obsolete($"Please use ${nameof(AdditionalStringsForConfigurationPath)}. This property will be removed in a future release.")]
147160
public IEnumerable<char> AdditionalCharactersForConfigurationPath { get; }
148161

162+
/// <summary>
163+
/// Gets an array of strings that will be used as a path to form the Configuration.
164+
/// Contains string values of <see cref="AdditionalCharactersForConfigurationPath"/>.
165+
/// </summary>
166+
public IEnumerable<string> AdditionalStringsForConfigurationPath { get; }
167+
149168
/// <summary>
150169
/// Gets Vault namespace.
151170
/// </summary>
@@ -161,8 +180,8 @@ public VaultOptions(
161180
/// <summary>
162181
/// Indicates whether we should disregard the certificate validation (for examples, servers behind Internet aren't likely to have a strong certs but we can't afford to use HTTP either)
163182
/// Previously, the certificate behavior can be set globally, but subsequently removed in .NET Core and onwards due to security reasons.
164-
/// We need to set the behavior to each HttpClient on a case-by-case basis. As such, this option is provided as a resolution.
165-
/// If it is true, a custom PostProcessHttpClientHandlerAction will be injected to the VaultClientSettings to accept any server certificate.
183+
/// We need to set the behavior to each HttpClient on a case-by-case basis. As such, this option is provided as a resolution.
184+
/// If it is true, a custom PostProcessHttpClientHandlerAction will be injected to the VaultClientSettings to accept any server certificate.
166185
/// Default value: false. Hashicorp also recommend using a proper CA to setup Vault access due to security concerns.
167186
/// </summary>
168187
public bool AcceptInsecureConnection { get; }
@@ -178,7 +197,7 @@ public VaultOptions(
178197
/// </summary>
179198
/// <remarks>
180199
/// The action will be invoked after the VaultSharp provider applies the AcceptInsecureConnection and ServerCertificateCustomValidationCallback
181-
/// customizations, if you enabled them. Be aware that if you overwrite the HttpMessageHandler's ServerCertificateCustomValidationCallback
200+
/// customizations, if you enabled them. Be aware that if you overwrite the HttpMessageHandler's ServerCertificateCustomValidationCallback
182201
/// in your action-handler method, you will cancel out the effect of enabling the AcceptInsecureConnection and/or
183202
/// ServerCertificateCustomValidationCallback options.
184203
/// </remarks>

Tests/VaultSharp.Extensions.Configuration.Test/IntegrationTests.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public async Task Success_SimpleTest_TokenAuth()
168168
configurationRoot.GetValue<int>("option3").Should().Be(5);
169169
configurationRoot.GetValue<bool>("option4").Should().Be(true);
170170
configurationRoot.GetValue<string>("option5:0").Should().Be("v1");
171-
configurationRoot.GetValue<string>("option5:1").Should().Be("v2");
171+
configurationRoot.GetValue<string>("option5:1").Should().Be("v2");
172172
configurationRoot.GetValue<string>("option5:2").Should().Be("v3");
173173
var t1 = new TestConfigObject();
174174
configurationRoot.Bind("option6:0", t1);
@@ -228,6 +228,12 @@ public async Task Success_SimpleTestWithKeyPrefix_TokenAuth()
228228
new KeyValuePair<string, object>("option7", "value7"),
229229
}
230230
},
231+
{
232+
"test/otherSubsection__otherSubsection2/otherSubsection3__otherSubsection4__otherSubsection6", new[]
233+
{
234+
new KeyValuePair<string, object>("option9", "value9"),
235+
}
236+
},
231237
{
232238
"test/subsection/testsection", new[]
233239
{
@@ -247,7 +253,7 @@ public async Task Success_SimpleTestWithKeyPrefix_TokenAuth()
247253

248254
var keyPrefix = "MyConfig";
249255
builder.AddVaultConfiguration(
250-
() => new VaultOptions("http://localhost:8200", "root", additionalCharactersForConfigurationPath: new[] { '.' }, keyPrefix: keyPrefix),
256+
() => new VaultOptions("http://localhost:8200", "root", additionalCharactersForConfigurationPath: new[] { '.' }, additionalStringsForConfigurationPath: ["__"], keyPrefix: keyPrefix),
251257
"test",
252258
"secret",
253259
this.logger);
@@ -258,7 +264,7 @@ public async Task Success_SimpleTestWithKeyPrefix_TokenAuth()
258264
configurationRoot.GetValue<int>($"{keyPrefix}:option3").Should().Be(5);
259265
configurationRoot.GetValue<bool>($"{keyPrefix}:option4").Should().Be(true);
260266
configurationRoot.GetValue<string>($"{keyPrefix}:option5:0").Should().Be("v1");
261-
configurationRoot.GetValue<string>($"{keyPrefix}:option5:1").Should().Be("v2");
267+
configurationRoot.GetValue<string>($"{keyPrefix}:option5:1").Should().Be("v2");
262268
configurationRoot.GetValue<string>($"{keyPrefix}:option5:2").Should().Be("v3");
263269
var t1 = new TestConfigObject();
264270
configurationRoot.Bind($"{keyPrefix}:option6:0", t1);
@@ -270,11 +276,17 @@ public async Task Success_SimpleTestWithKeyPrefix_TokenAuth()
270276
t2.OptionB.Should().Be("b2");
271277
configurationRoot.GetSection($"{keyPrefix}:subsection").GetValue<string>("option2").Should().Be("value2");
272278
configurationRoot.GetSection($"{keyPrefix}:otherSubsection")
273-
.GetSection($"otherSubsection2")
279+
.GetSection("otherSubsection2")
274280
.GetSection("otherSubsection3")
275281
.GetSection("otherSubsection4")
276282
.GetSection("otherSubsection5")
277283
.GetValue<string>("option7").Should().Be("value7");
284+
configurationRoot.GetSection($"{keyPrefix}:otherSubsection")
285+
.GetSection("otherSubsection2")
286+
.GetSection("otherSubsection3")
287+
.GetSection("otherSubsection4")
288+
.GetSection("otherSubsection6")
289+
.GetValue<string>("option9").Should().Be("value9");
278290
configurationRoot.GetSection($"{keyPrefix}:subsection").GetSection("testsection").GetValue<string>("option8").Should().Be("value8");
279291
}
280292
finally
@@ -754,7 +766,7 @@ public async Task Failure_PermissionDenied()
754766
Action act = () => builder.Build();
755767
act.Should().Throw<VaultApiException>().And.HttpStatusCode.Should().Be(HttpStatusCode.Forbidden);
756768

757-
}
769+
}
758770
finally
759771
{
760772
await cts.CancelAsync();

0 commit comments

Comments
 (0)