diff --git a/CHANGELOG.md b/CHANGELOG.md index f7fdafa..095988c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/AzureAuth.Test/CommandAadTest.cs b/src/AzureAuth.Test/CommandAadTest.cs index 7aaf77f..73df78a 100644 --- a/src/AzureAuth.Test/CommandAadTest.cs +++ b/src/AzureAuth.Test/CommandAadTest.cs @@ -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(key => key != "AZUREAUTH_CONFIG"))).Returns(key => null); // Specify a client override on the command line. subject.Client = clientOverride; @@ -444,6 +445,72 @@ public void TestEvaluateOptionsWithoutAliasValidCommandLineOptions() subject.TokenFetcherOptions.Should().BeEquivalentTo(expected); } + [Test] + public void TestEvaluateOptionsWithAuthModeFromCommandLineOptions() + { + CommandAad subject = this.serviceProvider.GetService(); + 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.DeviceCode }; + + this.envMock.Setup(env => env.Get(EnvVars.AuthMode)).Returns("Web,DeviceCode"); + subject.EvaluateOptions().Should().BeTrue(); + subject.AuthModes.Should().Contain(new[] { AuthMode.DeviceCode }); + } + + [Test] + public void TestEvaluateOptionsWithAuthModeFromEnvVar() + { + CommandAad subject = this.serviceProvider.GetService(); + 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(); + 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())).Returns((string)null); + subject.EvaluateOptions().Should().BeTrue(); + subject.AuthModes.Should().Contain(new[] { AuthMode.Default }); + } + + [Test] + public void TestEvaluateOptionsWithAuthModeFromInvalidEnvVars() + { + CommandAad subject = this.serviceProvider.GetService(); + 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(); + 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 }); + } + /// /// The root path. /// diff --git a/src/AzureAuth/Commands/CommandAad.cs b/src/AzureAuth/Commands/CommandAad.cs index 48130f4..6c88e00 100644 --- a/src/AzureAuth/Commands/CommandAad.cs +++ b/src/AzureAuth/Commands/CommandAad.cs @@ -60,12 +60,13 @@ public class CommandAad /// The help text for the option. /// #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 /// @@ -83,6 +84,12 @@ public class CommandAad /// 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"; @@ -179,7 +186,7 @@ public CommandAad(CommandExecuteEventData eventData, ITelemetryService telemetry /// Gets or sets the auth modes. /// [Option(ModeOption, AuthModeHelperText, CommandOptionType.MultipleValue)] - public IEnumerable AuthModes { get; set; } = new[] { AuthMode.Default }; + public IEnumerable AuthModes { get; set; } /// /// Gets or sets the output. @@ -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)) { @@ -405,5 +418,36 @@ private int GetToken(IPublicClientAuth publicClientAuth) return 0; } + + /// + /// Sets the from the environment variable and sets a default if not set. + /// + /// True if authmode is set. + 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(); + foreach(var val in authModesFromEnv.Split(',')) + { + if (Enum.TryParse(val, ignoreCase: true, out var mode)) + { + result.Add(mode); + } + else + { + return false; + } + } + + this.AuthModes = result; + this.eventData.Add($"env_{EnvVars.AuthMode}", authModesFromEnv); + return true; + } } } diff --git a/src/AzureAuth/EnvVars.cs b/src/AzureAuth/EnvVars.cs index 16f2d82..4b439e0 100644 --- a/src/AzureAuth/EnvVars.cs +++ b/src/AzureAuth/EnvVars.cs @@ -46,6 +46,11 @@ public static class EnvVars /// public static readonly string AdoPat = $"{EnvVarPrefix}_ADO_PAT"; + /// + /// Name of the env var to get the Auth Mode. + /// + public static readonly string AuthMode = $"{EnvVarPrefix}_MODE"; + /// /// 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.