diff --git a/src/Etcd.Microsoft.Extensions.Configuration/Auth/Credentials.cs b/src/Etcd.Microsoft.Extensions.Configuration/Auth/Credentials.cs
index 297e3db..5085c68 100644
--- a/src/Etcd.Microsoft.Extensions.Configuration/Auth/Credentials.cs
+++ b/src/Etcd.Microsoft.Extensions.Configuration/Auth/Credentials.cs
@@ -3,30 +3,52 @@
namespace Etcd.Microsoft.Extensions.Configuration.Auth;
///
-/// Provides credentials
+/// Provides credentials.
///
///
public class Credentials : ICredentials
{
+ private const string DefaultUserNameEnvironmentVariableName = "ETCD_CLIENT_USER_NAME";
+ private const string DefaultPasswordEnvironmentVariableName = "ETCD_CLIENT_PASSWORD";
+
///
/// Initializes a new instance of the class.
///
/// Name of the user.
/// The password.
+ /// The source of the username.
+ /// The source of the password.
+ /// The information about the credentials.
///
/// Value cannot be null or empty. - userName
/// or
/// Value cannot be null or empty. - password
///
- public Credentials(string userName, string password)
+ public Credentials(string userName, string password,
+ CredentialsSource userNameSource = CredentialsSource.Code,
+ CredentialsSource passwordSource = CredentialsSource.Code,
+ string? information = null)
{
if (string.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", nameof(userName));
if (string.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", nameof(password));
UserName = userName;
Password = password;
+ UserNameSource = userNameSource;
+ PasswordSource = passwordSource;
+ Information = information;
}
+ ///
+ /// Gets the source of the user name.
+ ///
+ public CredentialsSource UserNameSource { get; }
+
+ ///
+ /// Gets the source of the password.
+ ///
+ public CredentialsSource PasswordSource { get; }
+
///
/// Gets the name of the user.
///
@@ -42,4 +64,158 @@ public Credentials(string userName, string password)
/// The password.
///
public string Password { get; }
+
+ ///
+ /// Gets the information about the credentials.
+ ///
+ public string? Information { get; private set; }
+
+ ///
+ /// Gets the string representation of the credentials.
+ ///
+ override public string ToString() => Information ?? "etcd code based credentials";
+
+ ///
+ /// Creates a new credentials instance overriding values from environment variables if they are exists.
+ ///
+ /// The user name.
+ /// The password.
+ /// The name of the user name environment variable.
+ /// The name of the password environment variable.
+ /// The etcd user name or password are not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.
+ public static ICredentials WithOverrideFromEnvironmentVariables(
+ string userName,
+ string password,
+ string userNameEnvironmentVariableName = DefaultUserNameEnvironmentVariableName,
+ string passwordEnvironmentVariableName = DefaultPasswordEnvironmentVariableName)
+ {
+ var userNameSource = CredentialsSource.Code;
+ var passwordSource = CredentialsSource.Code;
+
+ var environmentUserName = Environment.GetEnvironmentVariable(userNameEnvironmentVariableName);
+ var environmentPassword = Environment.GetEnvironmentVariable(passwordEnvironmentVariableName);
+
+ if (!string.IsNullOrEmpty(environmentUserName))
+ {
+ userName = environmentUserName;
+
+ userNameSource = CredentialsSource.EnvironmentVariables;
+ }
+
+ if (string.IsNullOrEmpty(userName))
+ throw new EtcdException($"Etcd user name is not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.");
+
+ if (!string.IsNullOrEmpty(environmentPassword))
+ {
+ password = environmentPassword;
+
+ passwordSource = CredentialsSource.EnvironmentVariables;
+ }
+
+ if (string.IsNullOrEmpty(password))
+ throw new EtcdException($"Etcd password is not provided via code and not found in the environment variable `{passwordEnvironmentVariableName}`.");
+
+ return new Credentials(userName, password, userNameSource, passwordSource,
+ FormatInformation(
+ userNameSource,
+ passwordSource,
+ userNameEnvironmentVariableName,
+ passwordEnvironmentVariableName));
+ }
+
+ ///
+ /// Creates a new credentials instance overriding values from environment variables if they are exists.
+ ///
+ /// The user name.
+ /// The password.
+ /// The name of the password environment variable.
+ /// The etcd user name or password are not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.
+ public static ICredentials WithOverrideFromEnvironmentVariables(
+ string userName,
+ string password,
+ string passwordEnvironmentVariableName = DefaultPasswordEnvironmentVariableName)
+ {
+ var userNameSource = CredentialsSource.Code;
+ var passwordSource = CredentialsSource.Code;
+
+ var environmentPassword = Environment.GetEnvironmentVariable(passwordEnvironmentVariableName);
+
+ if (string.IsNullOrEmpty(userName))
+ throw new EtcdException($"Etcd user name is not provided.");
+
+ if (!string.IsNullOrEmpty(environmentPassword))
+ {
+ password = environmentPassword;
+
+ passwordSource = CredentialsSource.EnvironmentVariables;
+ }
+
+ if (string.IsNullOrEmpty(password))
+ throw new EtcdException($"Etcd password is not provided via code and not found in the environment variable `{passwordEnvironmentVariableName}`.");
+
+ return new Credentials(userName, password, userNameSource, passwordSource,
+ FormatInformation(
+ userNameSource,
+ passwordSource,
+ null,
+ passwordEnvironmentVariableName));
+ }
+
+
+ ///
+ /// Creates a new credentials instance from environment variables.
+ ///
+ /// The name of the user name environment variable.
+ /// The name of the password environment variable.
+ /// The etcd user name or password are not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.
+ public static ICredentials FromEnvironmentVariables(
+ string userNameEnvironmentVariableName = DefaultUserNameEnvironmentVariableName,
+ string passwordEnvironmentVariableName = DefaultPasswordEnvironmentVariableName)
+ {
+ var userNameSource = CredentialsSource.EnvironmentVariables;
+ var passwordSource = CredentialsSource.EnvironmentVariables;
+
+ var userName = Environment.GetEnvironmentVariable(userNameEnvironmentVariableName);
+ var password = Environment.GetEnvironmentVariable(passwordEnvironmentVariableName);
+
+ if (string.IsNullOrEmpty(userName))
+ throw new EtcdException($"Etcd user name is not found in the environment variable `{userNameEnvironmentVariableName}`.");
+
+ if (string.IsNullOrEmpty(password))
+ throw new EtcdException($"Etcd password is not found in the environment variable `{passwordEnvironmentVariableName}`.");
+
+ return new Credentials(userName, password, userNameSource, passwordSource,
+ FormatInformation(
+ userNameSource,
+ passwordSource,
+ userNameEnvironmentVariableName,
+ passwordEnvironmentVariableName));
+ }
+
+ private static string FormatInformation(
+ CredentialsSource userNameSource,
+ CredentialsSource passwordSource,
+ string? userNameEnvironmentVariableName = null,
+ string? passwordEnvironmentVariableName = null) =>
+ FormatUserNameInformation(userNameSource, userNameEnvironmentVariableName) + ", " + FormatPassword(passwordSource, passwordEnvironmentVariableName);
+
+ private static string FormatUserNameInformation(CredentialsSource userNameSource, string? userNameEnvironmentVariableName = null)
+ {
+ var result = $"etcd user name source: {userNameSource}";
+
+ if (userNameSource == CredentialsSource.EnvironmentVariables)
+ result += $" ({userNameEnvironmentVariableName})";
+
+ return result;
+ }
+
+ private static string FormatPassword(CredentialsSource passwordSource, string? passwordEnvironmentVariableName = null)
+ {
+ var result = $"etcd password source: {passwordSource}";
+
+ if (passwordSource == CredentialsSource.EnvironmentVariables)
+ result += $" ({passwordEnvironmentVariableName})";
+
+ return result;
+ }
}
\ No newline at end of file
diff --git a/src/Etcd.Microsoft.Extensions.Configuration/Auth/CredentialsSource.cs b/src/Etcd.Microsoft.Extensions.Configuration/Auth/CredentialsSource.cs
new file mode 100644
index 0000000..4bf9aff
--- /dev/null
+++ b/src/Etcd.Microsoft.Extensions.Configuration/Auth/CredentialsSource.cs
@@ -0,0 +1,17 @@
+namespace Etcd.Microsoft.Extensions.Configuration.Auth
+{
+ ///
+ /// Possible sources for credentials.
+ ///
+ public enum CredentialsSource
+ {
+ ///
+ /// Credentials provided via code.
+ ///
+ Code = 0,
+ ///
+ /// Credentials provided via environment variables.
+ ///
+ EnvironmentVariables = 1
+ }
+}
\ No newline at end of file
diff --git a/src/Etcd.Microsoft.Extensions.Configuration/CHANGELOG.md b/src/Etcd.Microsoft.Extensions.Configuration/CHANGELOG.md
index eb340b0..8464e1c 100644
--- a/src/Etcd.Microsoft.Extensions.Configuration/CHANGELOG.md
+++ b/src/Etcd.Microsoft.Extensions.Configuration/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## [3.1.0] - 2025-10-22
+
+### Added
+
+- Possibility to load credentials from environment variables
+
## [3.0.0] - 2025-06-26
### Removed
diff --git a/src/Etcd.Microsoft.Extensions.Configuration/Etcd.Microsoft.Extensions.Configuration.csproj b/src/Etcd.Microsoft.Extensions.Configuration/Etcd.Microsoft.Extensions.Configuration.csproj
index 3805fb9..499aff8 100644
--- a/src/Etcd.Microsoft.Extensions.Configuration/Etcd.Microsoft.Extensions.Configuration.csproj
+++ b/src/Etcd.Microsoft.Extensions.Configuration/Etcd.Microsoft.Extensions.Configuration.csproj
@@ -8,7 +8,7 @@
snupkg
true
- 3.0
+ 3.1
Etcd based configuration provider for Microsoft.Extensions.Configuration
Simplify community
diff --git a/src/Etcd.Microsoft.Extensions.Configuration/EtcdApplicationEnvironment.cs b/src/Etcd.Microsoft.Extensions.Configuration/EtcdApplicationEnvironment.cs
index e3ef278..950798f 100644
--- a/src/Etcd.Microsoft.Extensions.Configuration/EtcdApplicationEnvironment.cs
+++ b/src/Etcd.Microsoft.Extensions.Configuration/EtcdApplicationEnvironment.cs
@@ -20,7 +20,7 @@ public static class EtcdApplicationEnvironment
///
/// The connection string.
///
- /// value
+ /// value
public static string? ConnectionString
{
get
diff --git a/tests/Integration/Etcd.Microsoft.Extensions.Configuration.IntegrationTests/ConfigurationBuilderTests.cs b/tests/Integration/Etcd.Microsoft.Extensions.Configuration.IntegrationTests/ConfigurationBuilderTests.cs
index 4c1041b..46ad9b5 100644
--- a/tests/Integration/Etcd.Microsoft.Extensions.Configuration.IntegrationTests/ConfigurationBuilderTests.cs
+++ b/tests/Integration/Etcd.Microsoft.Extensions.Configuration.IntegrationTests/ConfigurationBuilderTests.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using Etcd.Microsoft.Extensions.Configuration.Auth;
using Etcd.Microsoft.Extensions.Configuration.Settings;
@@ -26,7 +27,38 @@ public void Build_WithSettingsFromEtcd_ValuesLoaded()
.Build();
// Act
+ PerformTest(config);
+ }
+
+ [Test]
+ public void Build_WithSettingsFromEtcdAndCredentialsFromEnvironment_ValuesLoaded()
+ {
+ // Arrange
+
+ Environment.SetEnvironmentVariable("ETCD_TEST_USERNAME", "MyUserName");
+ Environment.SetEnvironmentVariable("ETCD_TEST_PASSWORD", "passw");
+
+ var credentials = new Credentials("MyUserName", "passw");
+ var envCredentials = Credentials.WithOverrideFromEnvironmentVariables("foo", "bar", "ETCD_TEST_USERNAME", "ETCD_TEST_PASSWORD");
+ var envCredentials2 = Credentials.WithOverrideFromEnvironmentVariables("MyUserName", "bar", "ETCD_TEST_PASSWORD");
+
+ var etcdSettings = new EtcdSettings("http://localhost:2379");
+ var config = new ConfigurationBuilder()
+ .AddEtcd(credentials, etcdSettings)
+ .AddEtcd(envCredentials, etcdSettings, "MyPrefix")
+ .AddEtcd(envCredentials2, etcdSettings, "MYCOMPLEX/prefix", "/")
+ .Build();
+
+ // Act
+ PerformTest(config);
+
+ // Assert
+ Assert.Pass("Credentials info: " + envCredentials.ToString());
+ }
+
+ private static void PerformTest(IConfigurationRoot config)
+ {
var testSection = config.GetSection("TestSection");
var testSubSection = testSection.GetSection("SubSection");
var list = testSection.GetSection("ArraySection").Get>();