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: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

## [0.9.1] - 2024-12-09
### Changed
Expand Down
49 changes: 47 additions & 2 deletions src/AzureAuth.Test/IEnvExtensionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@ namespace AzureAuth.Test
using FluentAssertions;

using Microsoft.Authentication.AzureAuth;
using Microsoft.Authentication.MSALWrapper;
using Microsoft.Authentication.TestHelper;
using Microsoft.Extensions.Logging;
using Microsoft.Office.Lasso.Interfaces;

using Microsoft.Office.Lasso.Telemetry;
using Moq;

using NLog.Targets;
using NUnit.Framework;

public class IEnvExtensionsTest
{
private Mock<IEnv> envMock;
private ILogger logger;
private MemoryTarget logTarget;

[SetUp]
public void SetUp()
{
this.envMock = new Mock<IEnv>();
(this.logger, this.logTarget) = MemoryLogger.Create();
}

[TestCase("1", true)]
Expand Down Expand Up @@ -51,5 +57,44 @@ public void InteractiveAuth_IsEnabledIfEnvVarsAreNotSet()
this.envMock.Setup(env => env.Get(It.IsAny<string>())).Returns((string)null);
IEnvExtensions.InteractiveAuthDisabled(this.envMock.Object).Should().BeFalse();
}

[Test]
public void ReadAuthModeFromEnvOrSetDefault_ReturnsDefault_WhenEnvVarIsEmpty()
{
// Arrange
envMock.Setup(e => e.Get(It.IsAny<string>())).Returns(string.Empty);

// Act
var result = IEnvExtensions.ReadAuthModeFromEnvOrSetDefault(envMock.Object);

// Assert
result.Should().BeEquivalentTo(new[] { AuthMode.Default });
}

[Test]
public void ReadAuthModeFromEnvOrSetDefault_ReturnsParsedAuthModes_WhenEnvVarIsValid()
{
// Arrange
envMock.Setup(e => e.Get(It.IsAny<string>())).Returns("Web,DeviceCode");

// Act
var result = IEnvExtensions.ReadAuthModeFromEnvOrSetDefault(envMock.Object);

// Assert
result.Should().BeEquivalentTo(new[] { AuthMode.Web, AuthMode.DeviceCode });
}

[Test]
public void ReadAuthModeFromEnvOrSetDefault_ReturnsEmpty_WhenEnvVarIsInvalid()
{
// Arrange
envMock.Setup(e => e.Get(It.IsAny<string>())).Returns("InvalidMode");

// Act
var result = IEnvExtensions.ReadAuthModeFromEnvOrSetDefault(envMock.Object);

// Assert
result.Should().BeEmpty();
}
}
}
15 changes: 13 additions & 2 deletions src/AzureAuth/Commands/Ado/CommandPat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ namespace Microsoft.Authentication.AzureAuth.Commands.Ado
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using McMaster.Extensions.CommandLineUtils;

using Microsoft.Authentication.AdoPat;
using Microsoft.Authentication.AzureAuth.Ado;
using Microsoft.Authentication.MSALWrapper;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client.Extensions.Msal;
using Microsoft.Office.Lasso.Interfaces;
using Microsoft.Office.Lasso.Telemetry;
using Microsoft.VisualStudio.Services.DelegatedAuthorization;
using Microsoft.VisualStudio.Services.OAuth;
Expand Down Expand Up @@ -92,7 +94,7 @@ private enum OutputMode
private string Tenant { get; set; } = AzureAuth.Ado.Constants.Tenant.Microsoft;

[Option(CommandAad.ModeOption, CommandAad.AuthModeHelperText, CommandOptionType.MultipleValue)]
private IEnumerable<AuthMode> AuthModes { get; set; } = new[] { AuthMode.Default };
private IEnumerable<AuthMode> AuthModes { get; set; }

[Option(CommandAad.DomainOption, $"{CommandAad.DomainHelpText}\n[default: {AzureAuth.Ado.Constants.PreferredDomain}]", CommandOptionType.SingleValue)]
private string Domain { get; set; } = AzureAuth.Ado.Constants.PreferredDomain;
Expand Down Expand Up @@ -120,14 +122,23 @@ private ImmutableSortedSet<string> Scopes
/// <param name="logger">The <see cref="ILogger{T}"/> instance that is used for logging.</param>
/// <param name="publicClientAuth">An <see cref="IPublicClientAuth"/>.</param>
/// <param name="eventData">Lasso injected command event data.</param>
/// <param name="env">An <see cref="IEnv"/> to use.</param>
/// <returns>An integer status code. 0 for success and non-zero for failure.</returns>
public int OnExecute(ILogger<CommandPat> logger, IPublicClientAuth publicClientAuth, CommandExecuteEventData eventData)
public int OnExecute(ILogger<CommandPat> logger, IPublicClientAuth publicClientAuth, CommandExecuteEventData eventData, IEnv env)
{
if (!this.ValidOptions(logger))
{
return 1;
}

// If command line options for mode are not specified, then use the environment variables.
this.AuthModes ??= env.ReadAuthModeFromEnvOrSetDefault();
if (!this.AuthModes.Any())
{
logger.LogError($"Invalid value specified for environment variable {EnvVars.AuthMode}. Allowed values are: {CommandAad.AuthModeHelperText}");
return 1;
}

var accessToken = this.AccessToken(publicClientAuth, eventData);
if (accessToken == null)
{
Expand Down
12 changes: 10 additions & 2 deletions src/AzureAuth/Commands/Ado/CommandToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Microsoft.Authentication.AzureAuth.Commands.Ado
{
using System;
using System.Collections.Generic;

using System.Linq;
using McMaster.Extensions.CommandLineUtils;

using Microsoft.Authentication.AzureAuth.Ado;
Expand Down Expand Up @@ -52,7 +52,7 @@ public enum OutputMode
private string Tenant { get; set; } = AzureAuth.Ado.Constants.Tenant.Microsoft;

[Option(CommandAad.ModeOption, CommandAad.AuthModeHelperText, CommandOptionType.MultipleValue)]
private IEnumerable<AuthMode> AuthModes { get; set; } = new[] { AuthMode.Default };
private IEnumerable<AuthMode> AuthModes { get; set; }

[Option(CommandAad.DomainOption, Description = DomainOptionDescription)]
private string Domain { get; set; } = AzureAuth.Ado.Constants.PreferredDomain;
Expand Down Expand Up @@ -98,6 +98,14 @@ public int OnExecute(ILogger<CommandToken> logger, IEnv env, ITelemetryService t
return 0;
}

// If command line options for mode are not specified, then use the environment variables.
this.AuthModes ??= env.ReadAuthModeFromEnvOrSetDefault();
if (!this.AuthModes.Any())
{
logger.LogError($"Invalid value specified for environment variable {EnvVars.AuthMode}. Allowed values are: {CommandAad.AuthModeHelperText}");
return 1;
}

// If no PAT then use AAD AT.
TokenResult token = publicClientAuth.Token(
AzureAuth.Ado.AuthParameters.AdoParameters(this.Tenant),
Expand Down
44 changes: 9 additions & 35 deletions src/AzureAuth/Commands/CommandAad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@ public class CommandAad
/// </summary>
public static readonly TimeSpan GlobalTimeout = TimeSpan.FromMinutes(15);

/// <summary>
/// The allowed values for the <see cref="AuthMode"/> option.
/// </summary>
#if PlatformWindows
private const string AuthModeAllowedValues = "all, iwa, broker, web, devicecode";
public const string AuthModeAllowedValues = "all, iwa, broker, web, devicecode";
#else
private const string AuthModeAllowedValues = "all, web, devicecode";
public const string AuthModeAllowedValues = "all, web, devicecode";
#endif

private const string ResourceOption = "--resource";
Expand Down Expand Up @@ -279,9 +282,11 @@ public bool EvaluateOptions()
}
}

if (this.AuthModes is null && !this.TrySetAuthModeFromEnvOrDefault())
// If command line options for mode are not specified, then use the environment variables.
this.AuthModes ??= env.ReadAuthModeFromEnvOrSetDefault();
if (!this.AuthModes.Any())
{
this.logger.LogError($"Invalid value specified for environment variable {EnvVars.AuthMode}. Allowed values are: {AuthModeAllowedValues}");
this.logger.LogError($"Invalid value specified for environment variable {EnvVars.AuthMode}. Allowed values are: {CommandAad.AuthModeHelperText}");
return false;
}

Expand Down Expand Up @@ -418,36 +423,5 @@ 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(','))
{
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;
}
}
}
37 changes: 37 additions & 0 deletions src/AzureAuth/IEnvExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

namespace Microsoft.Authentication.AzureAuth
{
using Microsoft.Authentication.MSALWrapper;
using Microsoft.Office.Lasso.Interfaces;
using Microsoft.Office.Lasso.Telemetry;
using System.Collections.Generic;
using System;

/// <summary>
/// Extension methods to Lasso's <see cref="IEnv"/> interface.
Expand All @@ -22,5 +26,38 @@
return !string.IsNullOrEmpty(env.Get(EnvVars.NoUser)) ||
string.Equals(CorextPositiveValue, env.Get(EnvVars.CorextNonInteractive));
}

/// <summary>
/// Get the auth modes from the environment or set the default.
/// </summary>
/// <param name="env">The <see cref="IEnv"/> to use.</param>
/// <param name="eventData">Event data to add the auth mode to.</param>

Check warning on line 34 in src/AzureAuth/IEnvExtensions.cs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

XML comment has a param tag for 'eventData', but there is no parameter by that name

Check warning on line 34 in src/AzureAuth/IEnvExtensions.cs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

XML comment has a param tag for 'eventData', but there is no parameter by that name

Check warning on line 34 in src/AzureAuth/IEnvExtensions.cs

View workflow job for this annotation

GitHub Actions / test (windows-latest)

XML comment has a param tag for 'eventData', but there is no parameter by that name

Check warning on line 34 in src/AzureAuth/IEnvExtensions.cs

View workflow job for this annotation

GitHub Actions / test (windows-latest)

XML comment has a param tag for 'eventData', but there is no parameter by that name

Check warning on line 34 in src/AzureAuth/IEnvExtensions.cs

View workflow job for this annotation

GitHub Actions / test (macos-latest)

XML comment has a param tag for 'eventData', but there is no parameter by that name

Check warning on line 34 in src/AzureAuth/IEnvExtensions.cs

View workflow job for this annotation

GitHub Actions / test (macos-latest)

XML comment has a param tag for 'eventData', but there is no parameter by that name
/// <returns>AuthModes.</returns>
public static IEnumerable<AuthMode> ReadAuthModeFromEnvOrSetDefault(this IEnv env)
{
var authModesFromEnv = env.Get(EnvVars.AuthMode);

// If auth modes are not specified in the environment, then return the default.
if (string.IsNullOrEmpty(authModesFromEnv))
{
return new[] { AuthMode.Default };
}

var result = new List<AuthMode>();
foreach (var val in authModesFromEnv.Split(','))
{
if (Enum.TryParse<AuthMode>(val, ignoreCase: true, out var mode))
{
result.Add(mode);
}
else
{
// If the environment variable is not a valid auth mode, then return an empty list.
return new List<AuthMode>();
}
}

return result;
}
}
}
1 change: 1 addition & 0 deletions src/AzureAuth/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private static void Main(string[] args)
EnvVars.CloudBuild,
EnvVars.NoUser,
EnvVars.CorextNonInteractive,
EnvVars.AuthMode,
};

TelemetryConfig telemetryConfig = new TelemetryConfig(
Expand Down
Loading