Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Added support for reading auth mode from the environment variable `AZUREAUTH_MODE` for aad subcommands.

## [0.9.1] - 2024-12-09
### Changed
Expand Down
67 changes: 67 additions & 0 deletions src/AzureAuth.Test/CommandAadTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ public void TestEvaluateOptionsProvidedAliasWithEnvVarConfig()

// Specify config via env var
this.envMock.Setup(e => e.Get("AZUREAUTH_CONFIG")).Returns(configFile);
this.envMock.Setup(env => env.Get(It.Is<string>(key => key != "AZUREAUTH_CONFIG"))).Returns<string>(key => null);

// Specify a client override on the command line.
subject.Client = clientOverride;
Expand Down Expand Up @@ -444,6 +445,72 @@ public void TestEvaluateOptionsWithoutAliasValidCommandLineOptions()
subject.TokenFetcherOptions.Should().BeEquivalentTo(expected);
}

[Test]
public void TestEvaluateOptionsWithAuthModeFromCommandLineOptions()
{
CommandAad subject = this.serviceProvider.GetService<CommandAad>();
subject.Resource = "f0e8d801-3a50-48fd-b2da-6476d6e832a2";
subject.Client = "e19f71ed-3b14-448d-9346-9eff9753646b";
subject.Tenant = "9f6227ee-3d14-473e-8bed-1281171ef8c9";
subject.AuthModes = new List<AuthMode>() { AuthMode.DeviceCode };

this.envMock.Setup(env => env.Get(EnvVars.AuthMode)).Returns("Web,DeviceCode");
Comment thread
mvanchaa marked this conversation as resolved.
subject.EvaluateOptions().Should().BeTrue();
subject.AuthModes.Should().Contain(new[] { AuthMode.DeviceCode });
}

[Test]
public void TestEvaluateOptionsWithAuthModeFromEnvVar()
{
CommandAad subject = this.serviceProvider.GetService<CommandAad>();
subject.Resource = "f0e8d801-3a50-48fd-b2da-6476d6e832a2";
subject.Client = "e19f71ed-3b14-448d-9346-9eff9753646b";
subject.Tenant = "9f6227ee-3d14-473e-8bed-1281171ef8c9";

this.envMock.Setup(env => env.Get("AZUREAUTH_MODE")).Returns("Web,DeviceCode");
subject.EvaluateOptions().Should().BeTrue();
subject.AuthModes.Should().Contain(new[] { AuthMode.Web, AuthMode.DeviceCode });
}

[Test]
public void TestEvaluateOptionsWithNoAuthModeInEnvVarOrOptions()
{
CommandAad subject = this.serviceProvider.GetService<CommandAad>();
subject.Resource = "f0e8d801-3a50-48fd-b2da-6476d6e832a2";
subject.Client = "e19f71ed-3b14-448d-9346-9eff9753646b";
subject.Tenant = "9f6227ee-3d14-473e-8bed-1281171ef8c9";

this.envMock.Setup(env => env.Get(It.IsAny<string>())).Returns((string)null);
subject.EvaluateOptions().Should().BeTrue();
subject.AuthModes.Should().Contain(new[] { AuthMode.Default });
}

[Test]
public void TestEvaluateOptionsWithAuthModeFromInvalidEnvVars()
{
CommandAad subject = this.serviceProvider.GetService<CommandAad>();
subject.Resource = "f0e8d801-3a50-48fd-b2da-6476d6e832a2";
subject.Client = "e19f71ed-3b14-448d-9346-9eff9753646b";
subject.Tenant = "9f6227ee-3d14-473e-8bed-1281171ef8c9";

this.envMock.Setup(env => env.Get(EnvVars.AuthMode)).Returns("Invalid");
subject.EvaluateOptions().Should().BeFalse();
this.logTarget.Logs.Should().ContainMatch($"Invalid value specified for environment variable {EnvVars.AuthMode}*");
}

[Test]
public void TestEvaluateOptionsWithAuthModeFromEmptyEnvVars()
{
CommandAad subject = this.serviceProvider.GetService<CommandAad>();
subject.Resource = "f0e8d801-3a50-48fd-b2da-6476d6e832a2";
subject.Client = "e19f71ed-3b14-448d-9346-9eff9753646b";
subject.Tenant = "9f6227ee-3d14-473e-8bed-1281171ef8c9";

this.envMock.Setup(env => env.Get(EnvVars.AuthMode)).Returns("");
subject.EvaluateOptions().Should().BeTrue();
subject.AuthModes.Should().Contain(new[] { AuthMode.Default });
}

/// <summary>
/// The root path.
/// </summary>
Expand Down
54 changes: 49 additions & 5 deletions src/AzureAuth/Commands/CommandAad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,13 @@ public class CommandAad
/// The help text for the <see cref="ModeOption"/> option.
/// </summary>
#if PlatformWindows
public const string AuthModeHelperText = @"Authentication mode. Repeated invocations allowed.
public const string AuthModeHelperText = $@"Authentication mode. Repeated invocations allowed.
[default: broker, then web]
[possible values: all, iwa, broker, web, devicecode]";
[possible values: {AuthModeAllowedValues}]";
#else
public const string AuthModeHelperText = @"Authentication mode. Repeated invocations allowed. [default: web]
[possible values: all, web, devicecode]";
public const string AuthModeHelperText = $@"Authentication mode. Repeated invocations allowed
[default: web]
[possible values: {AuthModeAllowedValues}]";
#endif

/// <summary>
Expand All @@ -83,6 +84,12 @@ public class CommandAad
/// </summary>
public static readonly TimeSpan GlobalTimeout = TimeSpan.FromMinutes(15);

#if PlatformWindows
private const string AuthModeAllowedValues = "all, iwa, broker, web, devicecode";
#else
private const string AuthModeAllowedValues = "all, web, devicecode";
#endif

private const string ResourceOption = "--resource";
private const string ClientOption = "--client";

Expand Down Expand Up @@ -179,7 +186,7 @@ public CommandAad(CommandExecuteEventData eventData, ITelemetryService telemetry
/// Gets or sets the auth modes.
/// </summary>
[Option(ModeOption, AuthModeHelperText, CommandOptionType.MultipleValue)]
public IEnumerable<AuthMode> AuthModes { get; set; } = new[] { AuthMode.Default };
public IEnumerable<AuthMode> AuthModes { get; set; }
Comment thread
mvanchaa marked this conversation as resolved.

/// <summary>
/// Gets or sets the output.
Expand Down Expand Up @@ -272,6 +279,12 @@ public bool EvaluateOptions()
}
}

if (this.AuthModes is null && !this.TrySetAuthModeFromEnvOrDefault())
{
this.logger.LogError($"Invalid value specified for environment variable {EnvVars.AuthMode}. Allowed values are: {AuthModeAllowedValues}");
return false;
}

// Handle Resource Shorthand for Default Scope
if (evaluatedOptions.Scopes.IsNullOrEmpty() && !string.IsNullOrEmpty(evaluatedOptions.Resource))
{
Expand Down Expand Up @@ -405,5 +418,36 @@ private int GetToken(IPublicClientAuth publicClientAuth)

return 0;
}

/// <summary>
/// Sets the <see cref="AuthMode"/> from the environment variable and sets a default if not set.
/// </summary>
/// <returns>True if authmode is set.</returns>
public bool TrySetAuthModeFromEnvOrDefault()
{
var authModesFromEnv = this.env.Get(EnvVars.AuthMode);
if (string.IsNullOrEmpty(authModesFromEnv))
{
this.AuthModes = new[] { AuthMode.Default };
return true;
}

var result = new List<AuthMode>();
foreach(var val in authModesFromEnv.Split(','))
Comment thread
mvanchaa marked this conversation as resolved.
{
if (Enum.TryParse<AuthMode>(val, ignoreCase: true, out var mode))
{
result.Add(mode);
}
else
{
return false;
}
}

this.AuthModes = result;
this.eventData.Add($"env_{EnvVars.AuthMode}", authModesFromEnv);
return true;
}
}
}
5 changes: 5 additions & 0 deletions src/AzureAuth/EnvVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public static class EnvVars
/// </summary>
public static readonly string AdoPat = $"{EnvVarPrefix}_ADO_PAT";

/// <summary>
/// Name of the env var to get the Auth Mode.
/// </summary>
public static readonly string AuthMode = $"{EnvVarPrefix}_MODE";

/// <summary>
/// Name of the env var used to disable user based authentication modes.
/// NOTE: This is a private variable and it is recommended to not rely on this variable.
Expand Down
Loading