Skip to content

Commit

Permalink
Prevent envvar prefix normalization. Fixes dotnet#40911
Browse files Browse the repository at this point in the history
The fix implementation works like so:
- The environment variable prefix is stripped from a variable name.
- The variable name is then normalized.
- The prefix is then prepended to the variable name.
- Additionally, the filtering now occurs at the same time as
parsing/transformation.
  • Loading branch information
Emzi0767 committed Sep 30, 2020
1 parent 94515f7 commit bea66b6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ internal void Load(IDictionary envVariables)

IEnumerable<DictionaryEntry> filteredEnvVariables = envVariables
.Cast<DictionaryEntry>()
.SelectMany(AzureEnvToAppEnv)
.Where(entry => ((string)entry.Key).StartsWith(_prefix, StringComparison.OrdinalIgnoreCase));
.SelectMany(x => AzureEnvToAppEnv(x, _prefix));

foreach (DictionaryEntry envVariable in filteredEnvVariables)
{
string key = ((string)envVariable.Key).Substring(_prefix.Length);
string key = envVariable.Key as string;
if (key.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase))
key = key.Substring(_prefix.Length);

data[key] = (string)envVariable.Value;
}

Expand All @@ -69,7 +71,7 @@ private static string NormalizeKey(string key)
return key.Replace("__", ConfigurationPath.KeyDelimiter);
}

private static IEnumerable<DictionaryEntry> AzureEnvToAppEnv(DictionaryEntry entry)
private static IEnumerable<DictionaryEntry> AzureEnvToAppEnv(DictionaryEntry entry, string envPrefix = default)
{
string key = (string)entry.Key;
string prefix = string.Empty;
Expand All @@ -94,12 +96,21 @@ private static IEnumerable<DictionaryEntry> AzureEnvToAppEnv(DictionaryEntry ent
{
prefix = CustomPrefix;
}
else
else if (key.StartsWith(envPrefix, StringComparison.OrdinalIgnoreCase))
{
entry.Key = NormalizeKey(key);
// This prevents the prefix from being normalized.
// We can also do a fast path branch, I guess? No point in reallocating if the prefix is empty.
entry.Key = !string.IsNullOrEmpty(envPrefix)
? envPrefix + NormalizeKey(key.Substring(envPrefix.Length))
: NormalizeKey(key);

yield return entry;
yield break;
}
else
{
yield break;
}

// Return the key-value pair for connection string
yield return new DictionaryEntry(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,38 @@ public void ReplaceDoubleUnderscoreInEnvironmentVariables()
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:_db1_ProviderName"));
}

[Fact]
public void ReplaceDoubleUnderscoreInEnvironmentVariablesButNotPrefix()
{
var dict = new Hashtable()
{
{"test__prefix__with__double__underscores__data__ConnectionString", "connection"},
{"SQLCONNSTR__db1", "connStr"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider("test__prefix__with__double__underscores__");

envConfigSrc.Load(dict);

Assert.Equal("connection", envConfigSrc.Get("data:ConnectionString"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:_db1_ProviderName"));
}

[Fact]
public void ReplaceDoubleUnderscoreInEnvironmentVariablesWithDuplicatedPrefix()
{
var dict = new Hashtable()
{
{"test__test__ConnectionString", "connection"},
{"SQLCONNSTR__db1", "connStr"}
};
var envConfigSrc = new EnvironmentVariablesConfigurationProvider("test__");

envConfigSrc.Load(dict);

Assert.Equal("connection", envConfigSrc.Get("test:ConnectionString"));
Assert.Equal("System.Data.SqlClient", envConfigSrc.Get("ConnectionStrings:_db1_ProviderName"));
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public void BindingDoesNotThrowIfReloadedDuringBinding()
{
Expand Down

0 comments on commit bea66b6

Please sign in to comment.