Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 178 additions & 2 deletions src/Etcd.Microsoft.Extensions.Configuration/Auth/Credentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,52 @@
namespace Etcd.Microsoft.Extensions.Configuration.Auth;

/// <summary>
/// Provides credentials
/// Provides credentials.
/// </summary>
/// <seealso cref="ICredentials" />
public class Credentials : ICredentials
{
private const string DefaultUserNameEnvironmentVariableName = "ETCD_CLIENT_USER_NAME";
private const string DefaultPasswordEnvironmentVariableName = "ETCD_CLIENT_PASSWORD";

/// <summary>
/// Initializes a new instance of the <see cref="Credentials"/> class.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="password">The password.</param>
/// <param name="userNameSource">The source of the username.</param>
/// <param name="passwordSource">The source of the password.</param>
/// <param name="information">The information about the credentials.</param>
/// <exception cref="ArgumentException">
/// Value cannot be null or empty. - userName
/// or
/// Value cannot be null or empty. - password
/// </exception>
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;
}

/// <summary>
/// Gets the source of the user name.
/// </summary>
public CredentialsSource UserNameSource { get; }

/// <summary>
/// Gets the source of the password.
/// </summary>
public CredentialsSource PasswordSource { get; }

/// <summary>
/// Gets the name of the user.
/// </summary>
Expand All @@ -42,4 +64,158 @@ public Credentials(string userName, string password)
/// The password.
/// </value>
public string Password { get; }

/// <summary>
/// Gets the information about the credentials.
/// </summary>
public string? Information { get; private set; }

/// <summary>
/// Gets the string representation of the credentials.
/// </summary>
override public string ToString() => Information ?? "etcd code based credentials";

/// <summary>
/// Creates a new credentials instance overriding values from environment variables if they are exists.
/// </summary>
/// <param name="userName">The user name.</param>
/// <param name="password">The password.</param>
/// <param name="userNameEnvironmentVariableName">The name of the user name environment variable.</param>
/// <param name="passwordEnvironmentVariableName">The name of the password environment variable.</param>
/// <exception cref="EtcdException">The etcd user name or password are not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.</exception>
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));
}

/// <summary>
/// Creates a new credentials instance overriding values from environment variables if they are exists.
/// </summary>
/// <param name="userName">The user name.</param>
/// <param name="password">The password.</param>
/// <param name="passwordEnvironmentVariableName">The name of the password environment variable.</param>
/// <exception cref="EtcdException">The etcd user name or password are not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.</exception>
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));
}


/// <summary>
/// Creates a new credentials instance from environment variables.
/// </summary>
/// <param name="userNameEnvironmentVariableName">The name of the user name environment variable.</param>
/// <param name="passwordEnvironmentVariableName">The name of the password environment variable.</param>
/// <exception cref="EtcdException">The etcd user name or password are not provided via code and not found in the environment variable `{userNameEnvironmentVariableName}`.</exception>
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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Etcd.Microsoft.Extensions.Configuration.Auth
{
/// <summary>
/// Possible sources for credentials.
/// </summary>
public enum CredentialsSource
{
/// <summary>
/// Credentials provided via code.
/// </summary>
Code = 0,
/// <summary>
/// Credentials provided via environment variables.
/// </summary>
EnvironmentVariables = 1
}
}
6 changes: 6 additions & 0 deletions src/Etcd.Microsoft.Extensions.Configuration/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

<Version>3.0</Version>
<Version>3.1</Version>

<Description>Etcd based configuration provider for Microsoft.Extensions.Configuration</Description>
<Authors>Simplify community</Authors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class EtcdApplicationEnvironment
/// <value>
/// The connection string.
/// </value>
/// <exception cref="System.ArgumentNullException">value</exception>
/// <exception cref="ArgumentNullException">value</exception>
public static string? ConnectionString
{
get
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<List<string>>();
Expand Down