diff --git a/src/AutoMapper/Licensing/LicenseAccessor.cs b/src/AutoMapper/Licensing/LicenseAccessor.cs
index ba4bfa152c..8ee939b1e1 100644
--- a/src/AutoMapper/Licensing/LicenseAccessor.cs
+++ b/src/AutoMapper/Licensing/LicenseAccessor.cs
@@ -52,11 +52,22 @@ private License Initialize()
/// Resolves the license key from, in order of precedence: the explicitly configured value,
/// the product-specific AUTOMAPPER_LICENSE_KEY environment variable, then the shared
/// LUCKYPENNY_LICENSE_KEY environment variable (usable across Lucky Penny products).
+ /// Whitespace is removed from each value, and empty values are treated as unset.
///
internal static string ResolveLicenseKey(string explicitKey) =>
- explicitKey
- ?? Environment.GetEnvironmentVariable(AutoMapperLicenseKeyEnvVariable)
- ?? Environment.GetEnvironmentVariable(SharedLicenseKeyEnvVariable);
+ NormalizeLicenseKey(explicitKey)
+ ?? NormalizeLicenseKey(Environment.GetEnvironmentVariable(AutoMapperLicenseKeyEnvVariable))
+ ?? NormalizeLicenseKey(Environment.GetEnvironmentVariable(SharedLicenseKeyEnvVariable));
+
+ private static string NormalizeLicenseKey(string key)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ {
+ return null;
+ }
+
+ return new string(key.Where(c => !char.IsWhiteSpace(c)).ToArray());
+ }
private Claim[] ValidateKey(string licenseKey)
{
@@ -105,4 +116,4 @@ private Claim[] ValidateKey(string licenseKey)
}
}
-}
\ No newline at end of file
+}
diff --git a/src/UnitTests/Licensing/LicenseKeyEnvironmentVariableTests.cs b/src/UnitTests/Licensing/LicenseKeyEnvironmentVariableTests.cs
index 4d1bbad3f3..5d93ef86ac 100644
--- a/src/UnitTests/Licensing/LicenseKeyEnvironmentVariableTests.cs
+++ b/src/UnitTests/Licensing/LicenseKeyEnvironmentVariableTests.cs
@@ -10,6 +10,76 @@ public class LicenseKeyEnvironmentVariableTests
{
private const string AutoMapperEnvVar = LicenseAccessor.AutoMapperLicenseKeyEnvVariable;
private const string SharedEnvVar = LicenseAccessor.SharedLicenseKeyEnvVariable;
+ private const string CleanKey = "header.pay-load.sign_ature";
+
+ public static TheoryData KeysWithWhitespace => new()
+ {
+ CleanKey + "\n",
+ CleanKey + "\r\n",
+ CleanKey + " ",
+ CleanKey + "\t",
+ " \t" + CleanKey,
+ "header.\r\npay-\nload.sign_\tature",
+ "\u00a0header.\u2003pay-load.sign_ature\u2028"
+ };
+
+ [Theory]
+ [MemberData(nameof(KeysWithWhitespace))]
+ public void ExplicitKey_StripsWhitespace_AndTakesPrecedence(string key)
+ {
+ WithEnvironment(autoMapper: "env-automapper-key", shared: "env-shared-key", () =>
+ LicenseAccessor.ResolveLicenseKey(key).ShouldBe(CleanKey));
+ }
+
+ [Theory]
+ [MemberData(nameof(KeysWithWhitespace))]
+ public void AutoMapperEnvironmentVariable_StripsWhitespace_AndTakesPrecedence(string key)
+ {
+ WithEnvironment(autoMapper: key, shared: "env-shared-key", () =>
+ LicenseAccessor.ResolveLicenseKey(null).ShouldBe(CleanKey));
+ }
+
+ [Theory]
+ [MemberData(nameof(KeysWithWhitespace))]
+ public void SharedEnvironmentVariable_StripsWhitespace(string key)
+ {
+ WithEnvironment(autoMapper: null, shared: key, () =>
+ LicenseAccessor.ResolveLicenseKey(null).ShouldBe(CleanKey));
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("\t\r\n")]
+ [InlineData("\u00a0\u2003\u2028")]
+ public void BlankExplicitKey_FallsBackToAutoMapperEnvironmentVariable(string key)
+ {
+ WithEnvironment(autoMapper: " env-automapper-key\n", shared: "env-shared-key", () =>
+ LicenseAccessor.ResolveLicenseKey(key).ShouldBe("env-automapper-key"));
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("\t\r\n")]
+ [InlineData("\u00a0\u2003\u2028")]
+ public void BlankHigherPrecedenceKeys_FallBackToSharedEnvironmentVariable(string key)
+ {
+ WithEnvironment(autoMapper: key, shared: " env-shared-key\n", () =>
+ LicenseAccessor.ResolveLicenseKey(key).ShouldBe("env-shared-key"));
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("\t\r\n")]
+ [InlineData("\u00a0\u2003\u2028")]
+ public void ReturnsNull_WhenAllKeysAreBlank(string key)
+ {
+ WithEnvironment(autoMapper: key, shared: key, () =>
+ LicenseAccessor.ResolveLicenseKey(key).ShouldBeNull());
+ }
[Fact]
public void ExplicitKey_TakesPrecedence_OverBothEnvironmentVariables()