From db6f773c1557548c1bba85886805c3efbb9a2d36 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Thu, 6 Apr 2023 07:19:34 -0700 Subject: [PATCH 01/18] WAM Implementation --- .../Interfaces/IAuthContext.cs | 7 ++++++ ...Microsoft.Graph.Authentication.Core.csproj | 16 +++++++++--- .../Utilities/AuthenticationHelpers.cs | 25 +++++++++++++------ .../Authentication/Cmdlets/ConnectMgGraph.cs | 4 +++ .../Authentication/Constants.cs | 1 + .../Microsoft.Graph.Authentication.nuspec | 8 ++++++ .../Microsoft.Graph.Authentication.psm1 | 19 ++++++++++++++ .../Authentication/Models/AuthContext.cs | 1 + .../Authentication/build-module.ps1 | 8 +++--- 9 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs index a76f9812b72..bf116db0e41 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs @@ -34,6 +34,12 @@ public enum TokenCredentialType EnvironmentVariable } + public enum SigninUi + { + Browser, + Native + } + public interface IAuthContext { string ManagedIdentityId { get; set; } @@ -50,5 +56,6 @@ public interface IAuthContext ContextScope ContextScope { get; set; } Version PSHostVersion { get; set; } SecureString ClientSecret { get; set; } + SigninUi SigninUi { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index 032053228f2..518f0327f5e 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -1,6 +1,7 @@ + 9.0 netstandard2.0;net6.0;net472 Microsoft.Graph.PowerShell.Authentication.Core 2.0.0 @@ -12,14 +13,21 @@ - - + + + - + + + + + + + - + diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 86bda5def4e..2a92483e0a3 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -4,14 +4,18 @@ using Azure.Core; using Azure.Core.Diagnostics; using Azure.Identity; +using Azure.Identity.BrokeredAuthentication; using Microsoft.Graph.PowerShell.Authentication.Core.Extensions; using Microsoft.Identity.Client; +using Microsoft.Identity.Client.Broker; using Microsoft.Identity.Client.Extensions.Msal; using System; using System.Diagnostics.Tracing; using System.Globalization; using System.IO; using System.Linq; +using System.Net; +using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -105,16 +109,23 @@ private static async Task GetManagedIdentityCredentialAsync(IAu private static async Task GetInteractiveBrowserCredentialAsync(IAuthContext authContext, CancellationToken cancellationToken = default) { + using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger(); if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); - - var interactiveOptions = new InteractiveBrowserCredentialOptions + InteractiveBrowserCredentialOptions interactiveOptions; + if (authContext.SigninUi == SigninUi.Native) { - ClientId = authContext.ClientId, - TenantId = authContext.TenantId, - AuthorityHost = new Uri(GetAuthorityUrl(authContext)), - TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext) - }; + [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); + IntPtr parentWindowHandle = GetForegroundWindow(); + interactiveOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle); + } else { + interactiveOptions = new InteractiveBrowserCredentialOptions(); + } + + interactiveOptions.ClientId = authContext.ClientId; + interactiveOptions.TenantId = authContext.TenantId ?? "common"; + interactiveOptions.AuthorityHost = new Uri(GetAuthorityUrl(authContext)); + interactiveOptions.TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext); if (!File.Exists(Constants.AuthRecordPath)) { diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index ae6442d4c54..6bef4b0c3cf 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -100,6 +100,9 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem [Parameter(ParameterSetName = Constants.EnvironmentVariableParameterSet, Mandatory = false, HelpMessage = HelpMessages.EnvironmentVariable)] public SwitchParameter EnvironmentVariable { get; set; } + [Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SigninUi)] + public SigninUi SigninUi { get; set; } + [Parameter(Mandatory = false, DontShow = true, HelpMessage = "Wait for .NET debugger to attach")] public SwitchParameter Break { get; set; } @@ -190,6 +193,7 @@ private async Task ProcessRecordAsync() authContext.ContextScope = this.IsParameterBound(nameof(ContextScope)) ? ContextScope : ContextScope.CurrentUser; } authContext.TokenCredentialType = UseDeviceCode ? TokenCredentialType.DeviceCode : TokenCredentialType.InteractiveBrowser; + authContext.SigninUi = this.IsParameterBound(nameof(SigninUi)) ? SigninUi : SigninUi.Browser; } break; case Constants.AppCertificateParameterSet: diff --git a/src/Authentication/Authentication/Constants.cs b/src/Authentication/Authentication/Constants.cs index 906b7b6786b..d055e3ee946 100644 --- a/src/Authentication/Authentication/Constants.cs +++ b/src/Authentication/Authentication/Constants.cs @@ -42,6 +42,7 @@ public static class HelpMessages public const string Identity = "Login using a Managed Identity."; public const string EnvironmentVariable = "Allows for authentication using environment variables configured on the host machine. See https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#environment-variables."; public const string ManagedIdentityClientId = "The client id to authenticate for a user assigned managed identity. For more information on user assigned managed identities see: https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview#how-a-user-assigned-managed-identity-works-with-an-azure-vmId. To use the SystemAssigned identity, leave this field blank."; + public const string SigninUi = "Sets the authentication module between Web Account Manager (WAM) and the web browser"; } } } diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec index 81b6a386f5c..0e7f2255c87 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec @@ -28,6 +28,14 @@ + + + + + + + + diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 b/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 index ecce2d0516a..4b018febb0b 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 @@ -2,6 +2,25 @@ # Load the module dll $ModulePath = (Join-Path $PSScriptRoot 'Microsoft.Graph.Authentication.dll') $null = Import-Module -Name $ModulePath +function Import-Assembly { + param ( + [string] + $AssemblyDirectory + ) + if (Test-Path $AssemblyDirectory -ErrorAction Ignore) { + try { + Get-ChildItem -ErrorAction Stop -Path $AssemblyDirectory -Filter "*.dll" | ForEach-Object { + try { + Add-Type -Path $_.FullName -ErrorAction Ignore | Out-Null + } + catch { + Write-Verbose $_ + } + } + } + catch {} + } +} # Export nothing to clear implicit exports. Export-ModuleMember diff --git a/src/Authentication/Authentication/Models/AuthContext.cs b/src/Authentication/Authentication/Models/AuthContext.cs index 408b540ed6b..501f8906c05 100644 --- a/src/Authentication/Authentication/Models/AuthContext.cs +++ b/src/Authentication/Authentication/Models/AuthContext.cs @@ -30,5 +30,6 @@ public AuthContext() { ClientId = PowerShellClientId; } + public SigninUi SigninUi { get ; set ; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication/build-module.ps1 b/src/Authentication/Authentication/build-module.ps1 index 98861457d40..13f12ff3881 100644 --- a/src/Authentication/Authentication/build-module.ps1 +++ b/src/Authentication/Authentication/build-module.ps1 @@ -104,19 +104,19 @@ $Deps = [System.Collections.Generic.HashSet[string]]::new() Get-ChildItem -Path "$coreSrc/bin/$Configuration/$netStandard/publish/" | Where-Object { $_.Extension -in $copyExtensions } | Where-Object { -not $CoreAssemblies.Contains($_.BaseName) } | -ForEach-Object { [void]$Deps.Add($_.Name); Copy-Item -Path $_.FullName -Destination $outDeps } +ForEach-Object { [void]$Deps.Add($_.Name); Copy-Item -Path $_.FullName -Destination $outDeps -Recurse } Get-ChildItem -Path "$coreSrc/bin/$Configuration/$netApp/publish/" | Where-Object { -not $CoreAssemblies.Contains($_.BaseName) } | -ForEach-Object { [void]$Deps.Add($_.Name); Copy-Item -Path $_.FullName -Destination $outCore } +ForEach-Object { [void]$Deps.Add($_.Name); Copy-Item -Path $_.FullName -Destination $outCore -Recurse } Get-ChildItem -Path "$coreSrc/bin/$Configuration/$netFx/publish/" | Where-Object { -not $CoreAssemblies.Contains($_.BaseName) } | -ForEach-Object { [void]$Deps.Add($_.Name); Copy-Item -Path $_.FullName -Destination $outDesktop } +ForEach-Object { [void]$Deps.Add($_.Name); Copy-Item -Path $_.FullName -Destination $outDesktop -Recurse } # Now copy each authentication asset, not taking any found in authentication.core. Get-ChildItem -Path "$cmdletsSrc/bin/$Configuration/$netStandard/publish/" | Where-Object { -not $Deps.Contains($_.Name) -and $_.Extension -in $copyExtensions } | -ForEach-Object { Copy-Item -Path $_.FullName -Destination $outDir } +ForEach-Object { Copy-Item -Path $_.FullName -Destination $outDir -Recurse } Write-Host -ForegroundColor Green '-------------Done-------------' From 5b7e8394c18097c570934962b3fd4c8c8733f709 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Mon, 1 May 2023 13:50:18 -0700 Subject: [PATCH 02/18] fix the bug experienced with concurrent sign ins --- .../Microsoft.Graph.Authentication.Core.csproj | 2 +- .../Utilities/AuthenticationHelpers.cs | 10 +++++++++- .../Microsoft.Graph.Authentication.nuspec | 5 +++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index 518f0327f5e..3f4c49372e6 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 2a92483e0a3..2861e4b99b3 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -129,8 +129,16 @@ private static async Task GetInteractiveBrowserCre if (!File.Exists(Constants.AuthRecordPath)) { + AuthenticationRecord authRecord; var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); - var authRecord = await interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(authContext.Scopes), cancellationToken).ConfigureAwait(false); + if (authContext.SigninUi == SigninUi.Native) + { + authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); + } + else + { + authRecord = await interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(authContext.Scopes), cancellationToken).ConfigureAwait(false); + } await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); return interactiveBrowserCredential; } diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec index 0e7f2255c87..545179f2ce4 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec @@ -35,7 +35,6 @@ - @@ -48,6 +47,8 @@ + + @@ -56,7 +57,7 @@ - + From e0e78aa4887bdb4546b9afa9076d746ff0c59073 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Wed, 3 May 2023 11:48:59 -0700 Subject: [PATCH 03/18] final changes to WAM --- .../Utilities/AuthenticationHelpers.cs | 1 - .../Utilities/DependencyAssemblyResolver.cs | 125 ++++++++---------- 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 2861e4b99b3..8a8fbfdcd64 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -109,7 +109,6 @@ private static async Task GetManagedIdentityCredentialAsync(IAu private static async Task GetInteractiveBrowserCredentialAsync(IAuthContext authContext, CancellationToken cancellationToken = default) { - using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger(); if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); InteractiveBrowserCredentialOptions interactiveOptions; diff --git a/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs b/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs index 84a1bbbe89d..855a6299717 100644 --- a/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs +++ b/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs @@ -11,22 +11,54 @@ namespace Microsoft.Graph.PowerShell.Authentication.Utilities { public static class DependencyAssemblyResolver { - private static readonly Assembly Self = typeof(DependencyAssemblyResolver).Assembly; - private static readonly AssemblyLoadContextProxy Proxy = AssemblyLoadContextProxy.CreateLoadContext("msgraph-load-context"); - // Catalog our dependencies here to ensure we don't load anything else. - private static readonly HashSet Dependencies = new HashSet(StringComparer.Ordinal); + private static IReadOnlyDictionary Dependencies = new Dictionary + { + { "Azure.Core", new Version("1.25.0") }, + { "Azure.Identity", new Version("1.7.0") }, + { "Azure.Identity.BrokeredAuthentication", new Version("1.0.0") }, + { "Microsoft.Bcl.AsyncInterfaces", new Version("6.0.0") }, + { "Microsoft.Graph.Core", new Version("2.0.14") }, + { "Microsoft.Identity.Client", new Version("4.47.2") }, + { "Microsoft.Identity.Client.Broker", new Version("4.47.2") }, + { "Microsoft.Identity.Client.NativeInterop", new Version("0.13.0")}, + { "Microsoft.Identity.Client.Extensions.Msal", new Version("2.24.0") }, + { "Microsoft.IdentityModel.Abstractions", new Version("6.27.0") }, + { "Microsoft.IdentityModel.JsonWebTokens", new Version("6.27.0") }, + { "Microsoft.IdentityModel.Logging", new Version("6.27.0") }, + { "Microsoft.IdentityModel.Tokens", new Version("6.27.0") }, + { "System.IdentityModel.Tokens.Jwt", new Version("6.27.0") }, + { "System.Security.Cryptography.ProtectedData", new Version("6.0.0") }, + { "Newtonsoft.Json", new Version("13.0.1") }, + { "System.Text.Json", new Version("7.0.1") }, + { "System.Text.Encodings.Web", new Version("6.0.0") }, + { "System.Threading.Tasks.Extensions", new Version("4.5.4") }, + { "System.Diagnostics.DiagnosticSource", new Version("4.0.4") }, + { "System.Runtime.CompilerServices.Unsafe", new Version("4.0.4") }, + { "System.Memory", new Version("4.0.1") }, + { "System.Buffers", new Version("4.0.2") }, + { "System.Numerics.Vectors", new Version("4.1.3") }, + { "System.Net.Http.WinHttpHandler", new Version("6.0.0") } + }; - // Dependencies that need to be loaded per framework. - private static readonly HashSet MultiFrameworkDependencies = new HashSet(StringComparer.Ordinal); + /// + /// Dependencies that need to be loaded per framework. + /// + private static readonly IList MultiFrameworkDependencies = new List { + "Microsoft.Identity.Client", + "System.Security.Cryptography.ProtectedData", + "Microsoft.Graph.Core", + "System.Net.Http.WinHttpHandler" + }; // Set up the path to our dependency directory within the module. - private static readonly string DependencyFolder = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Self.Location), "Dependencies")); + private static readonly string DependenciesDirPath = Path.GetFullPath(Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Dependencies")); /// /// Framework dependency path. /Desktop for PS 5.1, and /Core for PS 6+. /// - private static string PSEdition; + private static string FrameworkDependenciesDirPath; /// /// Initializes our custom assembly resolve event handler. This should be called on module import. @@ -34,20 +66,16 @@ public static class DependencyAssemblyResolver /// public static void Initialize(bool isDesktopEdition = false) { - PSEdition = isDesktopEdition ? "Desktop" : "Core"; - - foreach (string filePath in Directory.EnumerateFiles(DependencyFolder, "*.dll", SearchOption.TopDirectoryOnly)) + if (isDesktopEdition) { - Dependencies.Add(AssemblyName.GetAssemblyName(filePath).Name); + FrameworkDependenciesDirPath = "Desktop"; } - - foreach (string filePath in Directory.EnumerateFiles(Path.Combine(DependencyFolder, PSEdition), "*.dll", SearchOption.TopDirectoryOnly)) + else { - MultiFrameworkDependencies.Add(AssemblyName.GetAssemblyName(filePath).Name); + FrameworkDependenciesDirPath = "Core"; } - // Set up our event handler when the module is loaded. - AppDomain.CurrentDomain.AssemblyResolve += ResolvingHandler; + AppDomain.CurrentDomain.AssemblyResolve += HandleResolveEvent; } /// @@ -57,34 +85,28 @@ public static void Initialize(bool isDesktopEdition = false) internal static void Reset() { // Remove our event hander when the module is unloaded. - AppDomain.CurrentDomain.AssemblyResolve -= ResolvingHandler; + AppDomain.CurrentDomain.AssemblyResolve -= HandleResolveEvent; } - private static bool IsRequiredAssembly(AssemblyName assemblyName) - { - return Dependencies.Contains(assemblyName.Name) || MultiFrameworkDependencies.Contains(assemblyName.Name); - } - - private static Assembly ResolvingHandler(object sender, ResolveEventArgs args) + private static Assembly HandleResolveEvent(object sender, ResolveEventArgs args) { try { - AssemblyName assemblyName = new AssemblyName(args.Name); + AssemblyName assemblymName = new AssemblyName(args.Name); // We try to resolve our dependencies on our own. - if (IsRequiredAssembly(assemblyName)) + if (Dependencies.TryGetValue(assemblymName.Name, out Version requiredVersion) + && (requiredVersion.Major >= assemblymName.Version.Major || string.Equals(assemblymName.Name, "Newtonsoft.Json", StringComparison.OrdinalIgnoreCase))) { - string requiredAssemblyPath = MultiFrameworkDependencies.Contains(assemblyName.Name) - ? requiredAssemblyPath = Path.Combine(DependencyFolder, PSEdition, $"{assemblyName.Name}.dll") - : requiredAssemblyPath = Path.Combine(DependencyFolder, $"{assemblyName.Name}.dll"); - if (File.Exists(requiredAssemblyPath)) + string requiredAssemblyPath = string.Empty; + if (MultiFrameworkDependencies.Contains(assemblymName.Name)) { - // - In .NET, load the assembly into the custom assembly load context. - // - In .NET Framework, assembly conflict is not a problem, so we load the assembly - // by 'Assembly.LoadFrom', the same as what powershell.exe would do. - return Proxy != null - ? Proxy.LoadFromAssemblyPath(requiredAssemblyPath) - : Assembly.LoadFrom(requiredAssemblyPath); + requiredAssemblyPath = Path.Combine(DependenciesDirPath, FrameworkDependenciesDirPath, $"{assemblymName.Name}.dll"); } + else + { + requiredAssemblyPath = Path.Combine(DependenciesDirPath, $"{assemblymName.Name}.dll"); + } + return Assembly.LoadFile(requiredAssemblyPath); } } catch @@ -94,35 +116,4 @@ private static Assembly ResolvingHandler(object sender, ResolveEventArgs args) return null; } } - - internal class AssemblyLoadContextProxy - { - private readonly object CustomContext; - private readonly MethodInfo loadFromAssemblyPathMethod; - - private AssemblyLoadContextProxy(Type alc, string loadContextName) - { - var ctor = alc.GetConstructor(new[] { typeof(string), typeof(bool) }); - loadFromAssemblyPathMethod = alc.GetMethod("LoadFromAssemblyPath", new[] { typeof(string) }); - CustomContext = ctor.Invoke(new object[] { loadContextName, false }); - } - - internal Assembly LoadFromAssemblyPath(string assemblyPath) - { - return (Assembly)loadFromAssemblyPathMethod.Invoke(CustomContext, new[] { assemblyPath }); - } - - internal static AssemblyLoadContextProxy CreateLoadContext(string name) - { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(nameof(name)); - } - - var alc = typeof(object).Assembly.GetType("System.Runtime.Loader.AssemblyLoadContext"); - return alc != null - ? new AssemblyLoadContextProxy(alc, name) - : null; - } - } } From 09f31d9356fac6737c74becf9a238786b29d8c3f Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Tue, 23 May 2023 13:04:52 -0700 Subject: [PATCH 04/18] revamping WAM --- .../Interfaces/IAuthContext.cs | 6 ++-- .../Utilities/AuthenticationHelpers.cs | 4 +-- .../Authentication/Cmdlets/ConnectMgGraph.cs | 6 ++-- .../Authentication/Constants.cs | 2 +- .../Microsoft.Graph.Authentication.psd1 | 2 +- .../Authentication/Models/AuthContext.cs | 2 +- .../Authentication/custom/GraphState.cs | 14 ++++++++ .../Authentication/custom/SetMgGraphOption.cs | 34 +++++++++++++++++++ .../Microsoft.Graph.Authentication.Tests.ps1 | 3 +- 9 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 src/Authentication/Authentication/custom/GraphState.cs create mode 100644 src/Authentication/Authentication/custom/SetMgGraphOption.cs diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs index bf116db0e41..b14ae289a88 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs @@ -34,11 +34,11 @@ public enum TokenCredentialType EnvironmentVariable } - public enum SigninUi + /*public enum SigninUi { Browser, Native - } + }*/ public interface IAuthContext { @@ -56,6 +56,6 @@ public interface IAuthContext ContextScope ContextScope { get; set; } Version PSHostVersion { get; set; } SecureString ClientSecret { get; set; } - SigninUi SigninUi { get; set; } + //SigninUi SigninUi { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 8a8fbfdcd64..9721f530b85 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -112,7 +112,7 @@ private static async Task GetInteractiveBrowserCre if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); InteractiveBrowserCredentialOptions interactiveOptions; - if (authContext.SigninUi == SigninUi.Native) + if (Microsoft.Graph.PowerShell.Authentication.GraphState.EnableWAMForMSGraph) { [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); IntPtr parentWindowHandle = GetForegroundWindow(); @@ -130,7 +130,7 @@ private static async Task GetInteractiveBrowserCre { AuthenticationRecord authRecord; var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); - if (authContext.SigninUi == SigninUi.Native) + if (Microsoft.Graph.PowerShell.Authentication.GraphState.EnableWAMForMSGraph) { authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); } diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index 6bef4b0c3cf..9ee44b2f90f 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -100,8 +100,8 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem [Parameter(ParameterSetName = Constants.EnvironmentVariableParameterSet, Mandatory = false, HelpMessage = HelpMessages.EnvironmentVariable)] public SwitchParameter EnvironmentVariable { get; set; } - [Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SigninUi)] - public SigninUi SigninUi { get; set; } + //[Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SigninUi)] + //public SigninUi SigninUi { get; set; } [Parameter(Mandatory = false, DontShow = true, HelpMessage = "Wait for .NET debugger to attach")] public SwitchParameter Break { get; set; } @@ -193,7 +193,7 @@ private async Task ProcessRecordAsync() authContext.ContextScope = this.IsParameterBound(nameof(ContextScope)) ? ContextScope : ContextScope.CurrentUser; } authContext.TokenCredentialType = UseDeviceCode ? TokenCredentialType.DeviceCode : TokenCredentialType.InteractiveBrowser; - authContext.SigninUi = this.IsParameterBound(nameof(SigninUi)) ? SigninUi : SigninUi.Browser; + //authContext.SigninUi = this.IsParameterBound(nameof(SigninUi)) ? SigninUi : SigninUi.Browser; } break; case Constants.AppCertificateParameterSet: diff --git a/src/Authentication/Authentication/Constants.cs b/src/Authentication/Authentication/Constants.cs index d055e3ee946..79e9d5837ed 100644 --- a/src/Authentication/Authentication/Constants.cs +++ b/src/Authentication/Authentication/Constants.cs @@ -42,7 +42,7 @@ public static class HelpMessages public const string Identity = "Login using a Managed Identity."; public const string EnvironmentVariable = "Allows for authentication using environment variables configured on the host machine. See https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#environment-variables."; public const string ManagedIdentityClientId = "The client id to authenticate for a user assigned managed identity. For more information on user assigned managed identities see: https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview#how-a-user-assigned-managed-identity-works-with-an-azure-vmId. To use the SystemAssigned identity, leave this field blank."; - public const string SigninUi = "Sets the authentication module between Web Account Manager (WAM) and the web browser"; + //public const string SigninUi = "Sets the authentication module between Web Account Manager (WAM) and the web browser"; } } } diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.psd1 b/src/Authentication/Authentication/Microsoft.Graph.Authentication.psd1 index b978cbf4402..b2284373da9 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.psd1 +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.psd1 @@ -75,7 +75,7 @@ FunctionsToExport = 'Find-MgGraphCommand', 'Find-MgGraphPermission' CmdletsToExport = 'Connect-MgGraph', 'Disconnect-MgGraph', 'Get-MgContext', 'Invoke-MgGraphRequest', 'Add-MgEnvironment', 'Get-MgEnvironment', 'Remove-MgEnvironment', 'Set-MgEnvironment', 'Get-MgRequestContext', - 'Set-MgRequestContext' + 'Set-MgRequestContext', 'Set-MgGraphOption' # Variables to export from this module VariablesToExport = '*' diff --git a/src/Authentication/Authentication/Models/AuthContext.cs b/src/Authentication/Authentication/Models/AuthContext.cs index 501f8906c05..c69552222f9 100644 --- a/src/Authentication/Authentication/Models/AuthContext.cs +++ b/src/Authentication/Authentication/Models/AuthContext.cs @@ -30,6 +30,6 @@ public AuthContext() { ClientId = PowerShellClientId; } - public SigninUi SigninUi { get ; set ; } + //public SigninUi SigninUi { get ; set ; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication/custom/GraphState.cs b/src/Authentication/Authentication/custom/GraphState.cs new file mode 100644 index 00000000000..716c774860e --- /dev/null +++ b/src/Authentication/Authentication/custom/GraphState.cs @@ -0,0 +1,14 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using System.IO; + +namespace Microsoft.Graph.PowerShell.Authentication +{ + public class GraphState + { + public bool EnableWAMForMSGraph = false; + } + +} \ No newline at end of file diff --git a/src/Authentication/Authentication/custom/SetMgGraphOption.cs b/src/Authentication/Authentication/custom/SetMgGraphOption.cs new file mode 100644 index 00000000000..ef92aa8039c --- /dev/null +++ b/src/Authentication/Authentication/custom/SetMgGraphOption.cs @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using Microsoft.Graph.PowerShell.Authentication; + +namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets +{ + [Cmdlet(VerbsCommunications.Set, "MgGraphOption", HelpUri = "")] + public class SetMgGraphOption : PSCmdlet + { + protected override void BeginProcessing() + { + base.BeginProcessing(); + } + + protected override void ProcessRecord() + { + base.ProcessRecord(); + GraphState.EnableWAMForMSGraph = !GraphState.EnableWAMForMSGraph; + WriteObject("WAM Signin currently set to: ", GraphState.EnableWAMForMSGraph); + } + + protected override void EndProcessing() + { + base.EndProcessing(); + } + + protected override void StopProcessing() + { + base.StopProcessing(); + } + } +} \ No newline at end of file diff --git a/src/Authentication/Authentication/test/Microsoft.Graph.Authentication.Tests.ps1 b/src/Authentication/Authentication/test/Microsoft.Graph.Authentication.Tests.ps1 index 86e59ebc10f..6eb4488d04b 100644 --- a/src/Authentication/Authentication/test/Microsoft.Graph.Authentication.Tests.ps1 +++ b/src/Authentication/Authentication/test/Microsoft.Graph.Authentication.Tests.ps1 @@ -50,7 +50,8 @@ Describe "Microsoft.Graph.Authentication module" { "Find-MgGraphPermission", "Invoke-MgRestMethod", "Get-MgRequestContext", - "Set-MgRequestContext" + "Set-MgRequestContext", + "Set-MgGraphOption" ) $PSModuleInfo.ExportedCommands.Keys | Should -BeIn $ExpectedCommands From b6ee01d30b47f218c3fa070ad96dc53126fb1db8 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Wed, 24 May 2023 07:49:56 -0700 Subject: [PATCH 05/18] revamping --- .../Authentication.Core/Common/GraphSession.cs | 5 +++++ .../Interfaces/IGraphOptions.cs | 15 +++++++++++++++ .../Interfaces/IGraphSession.cs | 1 + .../Utilities/AuthenticationHelpers.cs | 4 ++-- .../{custom => Cmdlets}/SetMgGraphOption.cs | 15 +++++++++++---- .../Common/GraphSessionInitializer.cs | 3 ++- .../GraphState.cs => Models/GraphOption.cs} | 4 ++-- 7 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs rename src/Authentication/Authentication/{custom => Cmdlets}/SetMgGraphOption.cs (63%) rename src/Authentication/Authentication/{custom/GraphState.cs => Models/GraphOption.cs} (80%) diff --git a/src/Authentication/Authentication.Core/Common/GraphSession.cs b/src/Authentication/Authentication.Core/Common/GraphSession.cs index 9d9fc08b091..6b893d4d1c4 100644 --- a/src/Authentication/Authentication.Core/Common/GraphSession.cs +++ b/src/Authentication/Authentication.Core/Common/GraphSession.cs @@ -51,6 +51,11 @@ public class GraphSession : IGraphSession /// public IRequestContext RequestContext { get; set; } + /// + /// Stores the user's Graph options. + /// + public IGraphOption GraphOption { get; set; } + /// /// Represents a collection of Microsoft Graph PowerShell meta-info. /// diff --git a/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs b/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs new file mode 100644 index 00000000000..3dd2483694f --- /dev/null +++ b/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs @@ -0,0 +1,15 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using System; +using System.Security; +using System.Security.Cryptography.X509Certificates; + +namespace Microsoft.Graph.PowerShell.Authentication +{ + public interface IGraphOption + { + bool EnableWAMForMSGraph { get; set; } + } +} \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs b/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs index 801860ae38c..c7f8ba48c3d 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs @@ -11,5 +11,6 @@ public interface IGraphSession IAuthContext AuthContext { get; set; } IDataStore DataStore { get; set; } IRequestContext RequestContext { get; set; } + IGraphOption GraphOption { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 9721f530b85..ea521267c88 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -112,7 +112,7 @@ private static async Task GetInteractiveBrowserCre if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); InteractiveBrowserCredentialOptions interactiveOptions; - if (Microsoft.Graph.PowerShell.Authentication.GraphState.EnableWAMForMSGraph) + if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) { [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); IntPtr parentWindowHandle = GetForegroundWindow(); @@ -130,7 +130,7 @@ private static async Task GetInteractiveBrowserCre { AuthenticationRecord authRecord; var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); - if (Microsoft.Graph.PowerShell.Authentication.GraphState.EnableWAMForMSGraph) + if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) { authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); } diff --git a/src/Authentication/Authentication/custom/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs similarity index 63% rename from src/Authentication/Authentication/custom/SetMgGraphOption.cs rename to src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index ef92aa8039c..4e021055998 100644 --- a/src/Authentication/Authentication/custom/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -2,11 +2,11 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ -using Microsoft.Graph.PowerShell.Authentication; +using System.Management.Automation; namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets { - [Cmdlet(VerbsCommunications.Set, "MgGraphOption", HelpUri = "")] + [Cmdlet(VerbsCommon.Set, "MgGraphOption", HelpUri = "")] public class SetMgGraphOption : PSCmdlet { protected override void BeginProcessing() @@ -17,8 +17,15 @@ protected override void BeginProcessing() protected override void ProcessRecord() { base.ProcessRecord(); - GraphState.EnableWAMForMSGraph = !GraphState.EnableWAMForMSGraph; - WriteObject("WAM Signin currently set to: ", GraphState.EnableWAMForMSGraph); + GraphSession.Instance.GraphOption.EnableWAMForMSGraph = !GraphSession.Instance.GraphOption.EnableWAMForMSGraph; + if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph == true) + { + WriteObject("WAM Signin currently enabled"); + } + else + { + WriteObject("WAM Signin disabled"); + } } protected override void EndProcessing() diff --git a/src/Authentication/Authentication/Common/GraphSessionInitializer.cs b/src/Authentication/Authentication/Common/GraphSessionInitializer.cs index d0ec4984e30..56931025eff 100644 --- a/src/Authentication/Authentication/Common/GraphSessionInitializer.cs +++ b/src/Authentication/Authentication/Common/GraphSessionInitializer.cs @@ -29,7 +29,8 @@ internal static GraphSession CreateInstance(IDataStore dataStore = null) return new GraphSession { DataStore = dataStore ?? new DiskDataStore(), - RequestContext = new RequestContext() + RequestContext = new RequestContext(), + GraphOption = new GraphOption() }; } /// diff --git a/src/Authentication/Authentication/custom/GraphState.cs b/src/Authentication/Authentication/Models/GraphOption.cs similarity index 80% rename from src/Authentication/Authentication/custom/GraphState.cs rename to src/Authentication/Authentication/Models/GraphOption.cs index 716c774860e..cf2a693ed9c 100644 --- a/src/Authentication/Authentication/custom/GraphState.cs +++ b/src/Authentication/Authentication/Models/GraphOption.cs @@ -6,9 +6,9 @@ namespace Microsoft.Graph.PowerShell.Authentication { - public class GraphState + public class GraphOption : IGraphOption { - public bool EnableWAMForMSGraph = false; + public bool EnableWAMForMSGraph { get; set; } } } \ No newline at end of file From b5ca48c1a2fdc19a086275ac2b7c189b03cb02f8 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Wed, 24 May 2023 08:52:06 -0700 Subject: [PATCH 06/18] WAM 2.0 --- .../Authentication.Core/Interfaces/IAuthContext.cs | 6 ------ src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs | 4 ---- src/Authentication/Authentication/Constants.cs | 1 - src/Authentication/Authentication/Models/AuthContext.cs | 1 - 4 files changed, 12 deletions(-) diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs index b14ae289a88..c64c15693ea 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs @@ -34,12 +34,6 @@ public enum TokenCredentialType EnvironmentVariable } - /*public enum SigninUi - { - Browser, - Native - }*/ - public interface IAuthContext { string ManagedIdentityId { get; set; } diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index 9ee44b2f90f..ae6442d4c54 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -100,9 +100,6 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem [Parameter(ParameterSetName = Constants.EnvironmentVariableParameterSet, Mandatory = false, HelpMessage = HelpMessages.EnvironmentVariable)] public SwitchParameter EnvironmentVariable { get; set; } - //[Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SigninUi)] - //public SigninUi SigninUi { get; set; } - [Parameter(Mandatory = false, DontShow = true, HelpMessage = "Wait for .NET debugger to attach")] public SwitchParameter Break { get; set; } @@ -193,7 +190,6 @@ private async Task ProcessRecordAsync() authContext.ContextScope = this.IsParameterBound(nameof(ContextScope)) ? ContextScope : ContextScope.CurrentUser; } authContext.TokenCredentialType = UseDeviceCode ? TokenCredentialType.DeviceCode : TokenCredentialType.InteractiveBrowser; - //authContext.SigninUi = this.IsParameterBound(nameof(SigninUi)) ? SigninUi : SigninUi.Browser; } break; case Constants.AppCertificateParameterSet: diff --git a/src/Authentication/Authentication/Constants.cs b/src/Authentication/Authentication/Constants.cs index 79e9d5837ed..906b7b6786b 100644 --- a/src/Authentication/Authentication/Constants.cs +++ b/src/Authentication/Authentication/Constants.cs @@ -42,7 +42,6 @@ public static class HelpMessages public const string Identity = "Login using a Managed Identity."; public const string EnvironmentVariable = "Allows for authentication using environment variables configured on the host machine. See https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#environment-variables."; public const string ManagedIdentityClientId = "The client id to authenticate for a user assigned managed identity. For more information on user assigned managed identities see: https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview#how-a-user-assigned-managed-identity-works-with-an-azure-vmId. To use the SystemAssigned identity, leave this field blank."; - //public const string SigninUi = "Sets the authentication module between Web Account Manager (WAM) and the web browser"; } } } diff --git a/src/Authentication/Authentication/Models/AuthContext.cs b/src/Authentication/Authentication/Models/AuthContext.cs index c69552222f9..408b540ed6b 100644 --- a/src/Authentication/Authentication/Models/AuthContext.cs +++ b/src/Authentication/Authentication/Models/AuthContext.cs @@ -30,6 +30,5 @@ public AuthContext() { ClientId = PowerShellClientId; } - //public SigninUi SigninUi { get ; set ; } } } \ No newline at end of file From a3cc0a0651456b48163b37263bb5c9baeec8d17e Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Fri, 2 Jun 2023 10:38:39 -0700 Subject: [PATCH 07/18] update --- .../Authentication.Core/Interfaces/IAuthContext.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs index c64c15693ea..a76f9812b72 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs @@ -50,6 +50,5 @@ public interface IAuthContext ContextScope ContextScope { get; set; } Version PSHostVersion { get; set; } SecureString ClientSecret { get; set; } - //SigninUi SigninUi { get; set; } } } \ No newline at end of file From 6693931c125d6f9b4ba49b7baa428356316a6a35 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Mon, 5 Jun 2023 13:47:59 -0700 Subject: [PATCH 08/18] updates --- ...Microsoft.Graph.Authentication.Core.csproj | 4 ---- .../Cmdlets/SetMgGraphOption.cs | 21 +++++++++++++++---- .../Microsoft.Graph.Authentication.nuspec | 4 ---- .../Authentication/Models/GraphOption.cs | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index 3f4c49372e6..eee092353d3 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -20,10 +20,6 @@ - - - - diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index 4e021055998..0f1c3797248 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -9,6 +9,9 @@ namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets [Cmdlet(VerbsCommon.Set, "MgGraphOption", HelpUri = "")] public class SetMgGraphOption : PSCmdlet { + [Parameter] + public SwitchParameter EnableLoginByWAM { get; set; } + protected override void BeginProcessing() { base.BeginProcessing(); @@ -17,14 +20,24 @@ protected override void BeginProcessing() protected override void ProcessRecord() { base.ProcessRecord(); - GraphSession.Instance.GraphOption.EnableWAMForMSGraph = !GraphSession.Instance.GraphOption.EnableWAMForMSGraph; - if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph == true) + + bool currentSetting = GraphSession.Instance.GraphOption.EnableWAMForMSGraph; + + if (EnableLoginByWAM.IsPresent) { - WriteObject("WAM Signin currently enabled"); + GraphSession.Instance.GraphOption.EnableWAMForMSGraph = EnableLoginByWAM; + if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) + WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); + else + WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); } else { - WriteObject("WAM Signin disabled"); + GraphSession.Instance.GraphOption.EnableWAMForMSGraph = !currentSetting; + if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) + WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); + else + WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); } } diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec index 545179f2ce4..529041fd196 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec @@ -29,12 +29,8 @@ - - - - diff --git a/src/Authentication/Authentication/Models/GraphOption.cs b/src/Authentication/Authentication/Models/GraphOption.cs index cf2a693ed9c..d8c48d7f70a 100644 --- a/src/Authentication/Authentication/Models/GraphOption.cs +++ b/src/Authentication/Authentication/Models/GraphOption.cs @@ -6,7 +6,7 @@ namespace Microsoft.Graph.PowerShell.Authentication { - public class GraphOption : IGraphOption + internal class GraphOption : IGraphOption { public bool EnableWAMForMSGraph { get; set; } } From 1c551c74495a1c01a23234611911c17f8000bce8 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Tue, 6 Jun 2023 09:53:47 -0700 Subject: [PATCH 09/18] (temp) Dependency Resolver --- .../Utilities/DependencyAssemblyResolver.cs | 158 +++++++++++------- 1 file changed, 99 insertions(+), 59 deletions(-) diff --git a/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs b/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs index 855a6299717..2b31982c769 100644 --- a/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs +++ b/src/Authentication/Authentication/Utilities/DependencyAssemblyResolver.cs @@ -11,54 +11,25 @@ namespace Microsoft.Graph.PowerShell.Authentication.Utilities { public static class DependencyAssemblyResolver { + private static readonly Assembly Self = typeof(DependencyAssemblyResolver).Assembly; + private static readonly AssemblyLoadContextProxy Proxy = AssemblyLoadContextProxy.CreateLoadContext("msgraph-load-context"); + // Catalog our dependencies here to ensure we don't load anything else. - private static IReadOnlyDictionary Dependencies = new Dictionary - { - { "Azure.Core", new Version("1.25.0") }, - { "Azure.Identity", new Version("1.7.0") }, - { "Azure.Identity.BrokeredAuthentication", new Version("1.0.0") }, - { "Microsoft.Bcl.AsyncInterfaces", new Version("6.0.0") }, - { "Microsoft.Graph.Core", new Version("2.0.14") }, - { "Microsoft.Identity.Client", new Version("4.47.2") }, - { "Microsoft.Identity.Client.Broker", new Version("4.47.2") }, - { "Microsoft.Identity.Client.NativeInterop", new Version("0.13.0")}, - { "Microsoft.Identity.Client.Extensions.Msal", new Version("2.24.0") }, - { "Microsoft.IdentityModel.Abstractions", new Version("6.27.0") }, - { "Microsoft.IdentityModel.JsonWebTokens", new Version("6.27.0") }, - { "Microsoft.IdentityModel.Logging", new Version("6.27.0") }, - { "Microsoft.IdentityModel.Tokens", new Version("6.27.0") }, - { "System.IdentityModel.Tokens.Jwt", new Version("6.27.0") }, - { "System.Security.Cryptography.ProtectedData", new Version("6.0.0") }, - { "Newtonsoft.Json", new Version("13.0.1") }, - { "System.Text.Json", new Version("7.0.1") }, - { "System.Text.Encodings.Web", new Version("6.0.0") }, - { "System.Threading.Tasks.Extensions", new Version("4.5.4") }, - { "System.Diagnostics.DiagnosticSource", new Version("4.0.4") }, - { "System.Runtime.CompilerServices.Unsafe", new Version("4.0.4") }, - { "System.Memory", new Version("4.0.1") }, - { "System.Buffers", new Version("4.0.2") }, - { "System.Numerics.Vectors", new Version("4.1.3") }, - { "System.Net.Http.WinHttpHandler", new Version("6.0.0") } - }; + private static readonly HashSet Dependencies = new HashSet(StringComparer.Ordinal); - /// - /// Dependencies that need to be loaded per framework. - /// - private static readonly IList MultiFrameworkDependencies = new List { - "Microsoft.Identity.Client", - "System.Security.Cryptography.ProtectedData", - "Microsoft.Graph.Core", - "System.Net.Http.WinHttpHandler" - }; + // Dependencies that need to be loaded per framework. + private static readonly HashSet MultiFrameworkDependencies = new HashSet(StringComparer.Ordinal); // Set up the path to our dependency directory within the module. - private static readonly string DependenciesDirPath = Path.GetFullPath(Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Dependencies")); + private static readonly string DependencyFolder = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Self.Location), "Dependencies")); /// /// Framework dependency path. /Desktop for PS 5.1, and /Core for PS 6+. /// - private static string FrameworkDependenciesDirPath; + private static string PSEdition; + + // Additional dependencies to be included + private static readonly string[] AdditionalDependencies = { "msalruntime" }; /// /// Initializes our custom assembly resolve event handler. This should be called on module import. @@ -66,16 +37,47 @@ public static class DependencyAssemblyResolver /// public static void Initialize(bool isDesktopEdition = false) { - if (isDesktopEdition) + PSEdition = isDesktopEdition ? "Desktop" : "Core"; + + foreach (string filePath in Directory.EnumerateFiles(DependencyFolder, "*.dll", SearchOption.TopDirectoryOnly)) { - FrameworkDependenciesDirPath = "Desktop"; + string assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(filePath).Name; + } + catch (BadImageFormatException) + { + // Skip files without metadata + continue; + } + + Dependencies.Add(assemblyName); } - else + + foreach (string filePath in Directory.EnumerateFiles(Path.Combine(DependencyFolder, PSEdition), "*.dll", SearchOption.TopDirectoryOnly)) + { + string assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(filePath).Name; + } + catch (BadImageFormatException) + { + // Skip files without metadata + continue; + } + + MultiFrameworkDependencies.Add(assemblyName); + } + + foreach (string additionalDependency in AdditionalDependencies) { - FrameworkDependenciesDirPath = "Core"; + Dependencies.Add(additionalDependency); } + // Set up our event handler when the module is loaded. - AppDomain.CurrentDomain.AssemblyResolve += HandleResolveEvent; + AppDomain.CurrentDomain.AssemblyResolve += ResolvingHandler; } /// @@ -85,28 +87,35 @@ public static void Initialize(bool isDesktopEdition = false) internal static void Reset() { // Remove our event hander when the module is unloaded. - AppDomain.CurrentDomain.AssemblyResolve -= HandleResolveEvent; + AppDomain.CurrentDomain.AssemblyResolve -= ResolvingHandler; } - private static Assembly HandleResolveEvent(object sender, ResolveEventArgs args) + private static bool IsRequiredAssembly(AssemblyName assemblyName) + { + return Dependencies.Contains(assemblyName.Name) || MultiFrameworkDependencies.Contains(assemblyName.Name); + } + + private static Assembly ResolvingHandler(object sender, ResolveEventArgs args) { try { - AssemblyName assemblymName = new AssemblyName(args.Name); + AssemblyName assemblyName = new AssemblyName(args.Name); // We try to resolve our dependencies on our own. - if (Dependencies.TryGetValue(assemblymName.Name, out Version requiredVersion) - && (requiredVersion.Major >= assemblymName.Version.Major || string.Equals(assemblymName.Name, "Newtonsoft.Json", StringComparison.OrdinalIgnoreCase))) + if (IsRequiredAssembly(assemblyName)) { - string requiredAssemblyPath = string.Empty; - if (MultiFrameworkDependencies.Contains(assemblymName.Name)) - { - requiredAssemblyPath = Path.Combine(DependenciesDirPath, FrameworkDependenciesDirPath, $"{assemblymName.Name}.dll"); - } - else + string requiredAssemblyPath = MultiFrameworkDependencies.Contains(assemblyName.Name) + ? Path.Combine(DependencyFolder, PSEdition, $"{assemblyName.Name}.dll") + : Path.Combine(DependencyFolder, $"{assemblyName.Name}.dll"); + + if (File.Exists(requiredAssemblyPath)) { - requiredAssemblyPath = Path.Combine(DependenciesDirPath, $"{assemblymName.Name}.dll"); + // - In .NET, load the assembly into the custom assembly load context. + // - In .NET Framework, assembly conflict is not a problem, so we load the assembly + // by 'Assembly.LoadFrom', the same as what powershell.exe would do. + return Proxy != null + ? Proxy.LoadFromAssemblyPath(requiredAssemblyPath) + : Assembly.LoadFrom(requiredAssemblyPath); } - return Assembly.LoadFile(requiredAssemblyPath); } } catch @@ -116,4 +125,35 @@ private static Assembly HandleResolveEvent(object sender, ResolveEventArgs args) return null; } } -} + + internal class AssemblyLoadContextProxy + { + private readonly object CustomContext; + private readonly MethodInfo loadFromAssemblyPathMethod; + + private AssemblyLoadContextProxy(Type alc, string loadContextName) + { + var ctor = alc.GetConstructor(new[] { typeof(string), typeof(bool) }); + loadFromAssemblyPathMethod = alc.GetMethod("LoadFromAssemblyPath", new[] { typeof(string) }); + CustomContext = ctor.Invoke(new object[] { loadContextName, false }); + } + + internal Assembly LoadFromAssemblyPath(string assemblyPath) + { + return (Assembly)loadFromAssemblyPathMethod.Invoke(CustomContext, new[] { assemblyPath }); + } + + internal static AssemblyLoadContextProxy CreateLoadContext(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + + var alc = typeof(object).Assembly.GetType("System.Runtime.Loader.AssemblyLoadContext"); + return alc != null + ? new AssemblyLoadContextProxy(alc, name) + : null; + } + } +} \ No newline at end of file From 2ec594cb56ad605bd5eb7bb8d6c94e0a56dd3df3 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Fri, 9 Jun 2023 07:25:53 -0700 Subject: [PATCH 10/18] (temp) MSAL.net WAM --- .../Common/GraphSession.cs | 2 + .../Interfaces/IAuthRecord.cs | 22 ++++++++++ ...Microsoft.Graph.Authentication.Core.csproj | 6 +-- .../Utilities/AuthenticationHelpers.cs | 33 ++++++++++++-- .../Authentication/Models/AuthRecord.cs | 44 +++++++++++++++++++ 5 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs create mode 100644 src/Authentication/Authentication/Models/AuthRecord.cs diff --git a/src/Authentication/Authentication.Core/Common/GraphSession.cs b/src/Authentication/Authentication.Core/Common/GraphSession.cs index 6b893d4d1c4..ab008fcbe0f 100644 --- a/src/Authentication/Authentication.Core/Common/GraphSession.cs +++ b/src/Authentication/Authentication.Core/Common/GraphSession.cs @@ -31,6 +31,8 @@ public class GraphSession : IGraphSession /// public IAuthContext AuthContext { get; set; } + public IAuthRecord AuthRecord { get; set; } + /// /// Gets or sets . /// diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs new file mode 100644 index 00000000000..31440973c7c --- /dev/null +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs @@ -0,0 +1,22 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using System; +using System.Threading; +using Microsoft.Identity.Client; + +namespace Microsoft.Graph.PowerShell.Authentication +{ + public interface IAuthRecord + { + AccountId AccountId { get; set; } + string Authority { get; set; } + string ClientId { get; set; } + string HomeAccountId { get; set; } + string TenantId { get; set; } + string Username { get; set; } + string Version { get; set; } + System.Threading.Tasks.Task SerializeAsync(System.IO.Stream stream, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index eee092353d3..54750e59ea5 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -16,10 +16,10 @@ - - + + - + diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index ea521267c88..c15d1853534 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -128,17 +128,34 @@ private static async Task GetInteractiveBrowserCre if (!File.Exists(Constants.AuthRecordPath)) { - AuthenticationRecord authRecord; var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) { - authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); + IAuthRecord authRecord; + //authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); + [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); + IntPtr parentWindowHandle = GetForegroundWindow(); + var pca = PublicClientApplicationBuilder.Create(authContext.ClientId) + .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) + .Build(); + + AuthenticationResult authResult = await Task.Run(() => { + return pca.AcquireTokenInteractive(authContext.Scopes) + .WithParentActivityOrWindow(parentWindowHandle) + .ExecuteAsync(); + }); + authRecord.Username = authResult.Account.Username; + authRecord.Authority = authResult.Account.Environment; + authRecord.AccountId = authResult.Account.HomeAccountId; + authRecord.TenantId = authResult.TenantId; + authRecord.ClientId = authContext.ClientId; + await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); } else { - authRecord = await interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(authContext.Scopes), cancellationToken).ConfigureAwait(false); + var authRecord = await interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(authContext.Scopes), cancellationToken).ConfigureAwait(false); + await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); } - await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); return interactiveBrowserCredential; } @@ -439,6 +456,14 @@ public static async Task WriteAuthRecordAsync(AuthenticationRecord authRecord) await authRecord.SerializeAsync(authRecordStream).ConfigureAwait(false); } + public static async Task WriteAuthRecordAsync(IAuthRecord authRecord) + { + // Try to create directory if it doesn't exist. + Directory.CreateDirectory(Constants.GraphDirectoryPath); + using (FileStream authRecordStream = new FileStream(Constants.AuthRecordPath, FileMode.Create, FileAccess.Write)) + await authRecord.SerializeAsync(authRecordStream).ConfigureAwait(false); + } + public static Task DeleteAuthRecordAsync() { if (File.Exists(Constants.AuthRecordPath)) diff --git a/src/Authentication/Authentication/Models/AuthRecord.cs b/src/Authentication/Authentication/Models/AuthRecord.cs new file mode 100644 index 00000000000..986b317c2c0 --- /dev/null +++ b/src/Authentication/Authentication/Models/AuthRecord.cs @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using System.Text.Json; +using System.Threading; +using Microsoft.Identity.Client; + +namespace Microsoft.Graph.PowerShell.Authentication +{ + public class AuthRecord : IAuthRecord + { + public AccountId AccountId { get; set; } + public string Authority { get; set; } + public string ClientId { get; set; } + public string HomeAccountId { get; set; } + public string TenantId { get; set; } + public string Username { get; set; } + public string Version { get; set; } = "1.0"; + public async System.Threading.Tasks.Task SerializeAsync (System.IO.Stream stream, CancellationToken cancellationToken = default) + { + using (var json = new Utf8JsonWriter(stream)) + { + json.WriteStartObject(); + + json.WriteString(JsonEncodedText.Encode("username"), Username); + + json.WriteString(JsonEncodedText.Encode("authority"), Authority); + + json.WriteString(JsonEncodedText.Encode("homeAccountId"), HomeAccountId); + + json.WriteString(JsonEncodedText.Encode("tenantId"), TenantId); + + json.WriteString(JsonEncodedText.Encode("clientId"), ClientId); + + json.WriteString(JsonEncodedText.Encode("version"), Version); + + json.WriteEndObject(); + + await json.FlushAsync(cancellationToken).ConfigureAwait(false); + } + } + } +} \ No newline at end of file From 22894c5a56ec9902608899d21bf70586a88b8d99 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Mon, 12 Jun 2023 08:14:43 -0700 Subject: [PATCH 11/18] complete --- .../Common/GraphSession.cs | 3 ++ .../Interfaces/IAuthRecord.cs | 3 -- ...Microsoft.Graph.Authentication.Core.csproj | 6 +-- .../Utilities/AuthenticationHelpers.cs | 37 +++++++++------- .../Authentication/Models/AuthRecord.cs | 44 ------------------- 5 files changed, 27 insertions(+), 66 deletions(-) delete mode 100644 src/Authentication/Authentication/Models/AuthRecord.cs diff --git a/src/Authentication/Authentication.Core/Common/GraphSession.cs b/src/Authentication/Authentication.Core/Common/GraphSession.cs index ab008fcbe0f..7c72365b4d2 100644 --- a/src/Authentication/Authentication.Core/Common/GraphSession.cs +++ b/src/Authentication/Authentication.Core/Common/GraphSession.cs @@ -31,6 +31,9 @@ public class GraphSession : IGraphSession /// public IAuthContext AuthContext { get; set; } + /// + /// Gets or Sets . + /// public IAuthRecord AuthRecord { get; set; } /// diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs index 31440973c7c..5ecde647e60 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs @@ -4,19 +4,16 @@ using System; using System.Threading; -using Microsoft.Identity.Client; namespace Microsoft.Graph.PowerShell.Authentication { public interface IAuthRecord { - AccountId AccountId { get; set; } string Authority { get; set; } string ClientId { get; set; } string HomeAccountId { get; set; } string TenantId { get; set; } string Username { get; set; } string Version { get; set; } - System.Threading.Tasks.Task SerializeAsync(System.IO.Stream stream, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index 54750e59ea5..42c674de4af 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -16,10 +16,10 @@ - - + + - + diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index c15d1853534..8b4026c4e57 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -14,9 +14,9 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Net; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -131,7 +131,6 @@ private static async Task GetInteractiveBrowserCre var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) { - IAuthRecord authRecord; //authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); IntPtr parentWindowHandle = GetForegroundWindow(); @@ -144,12 +143,13 @@ private static async Task GetInteractiveBrowserCre .WithParentActivityOrWindow(parentWindowHandle) .ExecuteAsync(); }); - authRecord.Username = authResult.Account.Username; - authRecord.Authority = authResult.Account.Environment; - authRecord.AccountId = authResult.Account.HomeAccountId; - authRecord.TenantId = authResult.TenantId; - authRecord.ClientId = authContext.ClientId; - await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); + AuthRecord authRecord = new() + { + Username = authResult.Account.Username, + Authority = authResult.Account.Environment, + TenantId = authResult.TenantId, + ClientId = authContext.ClientId + }; } else { @@ -456,19 +456,24 @@ public static async Task WriteAuthRecordAsync(AuthenticationRecord authRecord) await authRecord.SerializeAsync(authRecordStream).ConfigureAwait(false); } - public static async Task WriteAuthRecordAsync(IAuthRecord authRecord) - { - // Try to create directory if it doesn't exist. - Directory.CreateDirectory(Constants.GraphDirectoryPath); - using (FileStream authRecordStream = new FileStream(Constants.AuthRecordPath, FileMode.Create, FileAccess.Write)) - await authRecord.SerializeAsync(authRecordStream).ConfigureAwait(false); - } - public static Task DeleteAuthRecordAsync() { if (File.Exists(Constants.AuthRecordPath)) File.Delete(Constants.AuthRecordPath); return Task.CompletedTask; } + + public class AuthRecord : IAuthRecord + { + public AuthRecord() + { + } + public string Authority { get; set; } + public string ClientId { get; set; } + public string HomeAccountId { get; set; } + public string TenantId { get; set; } + public string Username { get; set; } + public string Version { get; set; } = "1.0"; + } } } \ No newline at end of file diff --git a/src/Authentication/Authentication/Models/AuthRecord.cs b/src/Authentication/Authentication/Models/AuthRecord.cs deleted file mode 100644 index 986b317c2c0..00000000000 --- a/src/Authentication/Authentication/Models/AuthRecord.cs +++ /dev/null @@ -1,44 +0,0 @@ -// ------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. -// ------------------------------------------------------------------------------ - -using System.Text.Json; -using System.Threading; -using Microsoft.Identity.Client; - -namespace Microsoft.Graph.PowerShell.Authentication -{ - public class AuthRecord : IAuthRecord - { - public AccountId AccountId { get; set; } - public string Authority { get; set; } - public string ClientId { get; set; } - public string HomeAccountId { get; set; } - public string TenantId { get; set; } - public string Username { get; set; } - public string Version { get; set; } = "1.0"; - public async System.Threading.Tasks.Task SerializeAsync (System.IO.Stream stream, CancellationToken cancellationToken = default) - { - using (var json = new Utf8JsonWriter(stream)) - { - json.WriteStartObject(); - - json.WriteString(JsonEncodedText.Encode("username"), Username); - - json.WriteString(JsonEncodedText.Encode("authority"), Authority); - - json.WriteString(JsonEncodedText.Encode("homeAccountId"), HomeAccountId); - - json.WriteString(JsonEncodedText.Encode("tenantId"), TenantId); - - json.WriteString(JsonEncodedText.Encode("clientId"), ClientId); - - json.WriteString(JsonEncodedText.Encode("version"), Version); - - json.WriteEndObject(); - - await json.FlushAsync(cancellationToken).ConfigureAwait(false); - } - } - } -} \ No newline at end of file From f0ee728908444653d180a67d9c2d2019cb5fcc1f Mon Sep 17 00:00:00 2001 From: Peter Ombwa Date: Tue, 13 Jun 2023 17:05:56 -0700 Subject: [PATCH 12/18] Use Azure.Identity for WAM. --- .../Common/GraphSession.cs | 5 -- .../Interfaces/IAuthRecord.cs | 19 ----- ...Microsoft.Graph.Authentication.Core.csproj | 1 - .../Utilities/AuthenticationHelpers.cs | 83 ++++++------------- .../Utilities/WindowHandleUtlities.cs | 52 ++++++++++++ .../Microsoft.Graph.Authentication.nuspec | 1 + .../Microsoft.Graph.Authentication.psm1 | 19 ----- .../Authentication/ModuleInitializer.cs | 4 +- 8 files changed, 79 insertions(+), 105 deletions(-) delete mode 100644 src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs create mode 100644 src/Authentication/Authentication.Core/Utilities/WindowHandleUtlities.cs diff --git a/src/Authentication/Authentication.Core/Common/GraphSession.cs b/src/Authentication/Authentication.Core/Common/GraphSession.cs index 7c72365b4d2..6b893d4d1c4 100644 --- a/src/Authentication/Authentication.Core/Common/GraphSession.cs +++ b/src/Authentication/Authentication.Core/Common/GraphSession.cs @@ -31,11 +31,6 @@ public class GraphSession : IGraphSession /// public IAuthContext AuthContext { get; set; } - /// - /// Gets or Sets . - /// - public IAuthRecord AuthRecord { get; set; } - /// /// Gets or sets . /// diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs deleted file mode 100644 index 5ecde647e60..00000000000 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthRecord.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. -// ------------------------------------------------------------------------------ - -using System; -using System.Threading; - -namespace Microsoft.Graph.PowerShell.Authentication -{ - public interface IAuthRecord - { - string Authority { get; set; } - string ClientId { get; set; } - string HomeAccountId { get; set; } - string TenantId { get; set; } - string Username { get; set; } - string Version { get; set; } - } -} \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index c18a2813274..6c71886ae2f 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -15,7 +15,6 @@ - diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index a61ef865464..ab51c98964f 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -8,16 +8,13 @@ using Microsoft.Graph.Authentication; using Microsoft.Graph.PowerShell.Authentication.Core.Extensions; using Microsoft.Identity.Client; -using Microsoft.Identity.Client.Broker; using Microsoft.Identity.Client.Extensions.Msal; using System; using System.Diagnostics.Tracing; using System.Globalization; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -45,10 +42,9 @@ public static async Task GetTokenCredentialAsync(IAuthContext a return await GetInteractiveBrowserCredentialAsync(authContext, cancellationToken).ConfigureAwait(false); return await GetDeviceCodeCredentialAsync(authContext, cancellationToken).ConfigureAwait(false); case AuthenticationType.AppOnly: - if (authContext.TokenCredentialType == TokenCredentialType.ClientCertificate) - return await GetClientCertificateCredentialAsync(authContext).ConfigureAwait(false); - else - return await GetClientSecretCredentialAsync(authContext).ConfigureAwait(false); + return authContext.TokenCredentialType == TokenCredentialType.ClientCertificate + ? await GetClientCertificateCredentialAsync(authContext).ConfigureAwait(false) + : await GetClientSecretCredentialAsync(authContext).ConfigureAwait(false); case AuthenticationType.ManagedIdentity: return await GetManagedIdentityCredentialAsync(authContext).ConfigureAwait(false); case AuthenticationType.EnvironmentVariable: @@ -85,6 +81,11 @@ private static bool IsAuthFlowNotSupported() && (string.IsNullOrEmpty(EnvironmentVariables.ClientSecret) && string.IsNullOrEmpty(EnvironmentVariables.ClientCertificatePath))); } + private static bool IsWamSupported() + { + return GraphSession.Instance.GraphOption.EnableWAMForMSGraph && SharedUtilities.IsWindowsPlatform(); + } + private static async Task GetClientSecretCredentialAsync(IAuthContext authContext) { if (authContext is null) @@ -112,16 +113,7 @@ private static async Task GetInteractiveBrowserCre { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); - InteractiveBrowserCredentialOptions interactiveOptions; - if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) - { - [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); - IntPtr parentWindowHandle = GetForegroundWindow(); - interactiveOptions = new InteractiveBrowserCredentialBrokerOptions(parentWindowHandle); - } else { - interactiveOptions = new InteractiveBrowserCredentialOptions(); - } - + var interactiveOptions = IsWamSupported() ? new InteractiveBrowserCredentialBrokerOptions(WindowHandleUtlities.GetConsoleOrTerminalWindow()) : new InteractiveBrowserCredentialOptions(); interactiveOptions.ClientId = authContext.ClientId; interactiveOptions.TenantId = authContext.TenantId ?? "common"; interactiveOptions.AuthorityHost = new Uri(GetAuthorityUrl(authContext)); @@ -129,34 +121,21 @@ private static async Task GetInteractiveBrowserCre if (!File.Exists(Constants.AuthRecordPath)) { + AuthenticationRecord authRecord; var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); - if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) + if (IsWamSupported()) { - //authRecord = interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); - [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); - IntPtr parentWindowHandle = GetForegroundWindow(); - var pca = PublicClientApplicationBuilder.Create(authContext.ClientId) - .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) - .Build(); - - AuthenticationResult authResult = await Task.Run(() => { - return pca.AcquireTokenInteractive(authContext.Scopes) - .WithParentActivityOrWindow(parentWindowHandle) - .ExecuteAsync(); - }); - AuthRecord authRecord = new() + authRecord = await Task.Run(() => { - Username = authResult.Account.Username, - Authority = authResult.Account.Environment, - TenantId = authResult.TenantId, - ClientId = authContext.ClientId - }; + // Run the thread in MTA. + return interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); + }); } else { - var authRecord = await interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(authContext.Scopes), cancellationToken).ConfigureAwait(false); - await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); + authRecord = await interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(authContext.Scopes), cancellationToken).ConfigureAwait(false); } + await WriteAuthRecordAsync(authRecord).ConfigureAwait(false); return interactiveBrowserCredential; } @@ -209,10 +188,9 @@ private static async Task GetClientCertificateCrede private static TokenCachePersistenceOptions GetTokenCachePersistenceOptions(IAuthContext authContext) { - if (authContext.ContextScope == ContextScope.Process) - return GraphSession.Instance.InMemoryTokenCache.GetTokenCachePersistenceOptions(); - - return new TokenCachePersistenceOptions { Name = Constants.CacheName }; + return authContext.ContextScope == ContextScope.Process + ? GraphSession.Instance.InMemoryTokenCache.GetTokenCachePersistenceOptions() + : new TokenCachePersistenceOptions { Name = Constants.CacheName }; } /// @@ -326,10 +304,9 @@ private static string GetAuthorityUrl(IAuthContext authContext) if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); string audience = authContext.TenantId ?? Constants.DefaultTenant; - if (GraphSession.Instance.Environment != null) - return $"{GraphSession.Instance.Environment.AzureADEndpoint}/{audience}"; - - return $"{Constants.DefaultAzureADEndpoint}/{audience}"; + return GraphSession.Instance.Environment != null + ? $"{GraphSession.Instance.Environment.AzureADEndpoint}/{audience}" + : $"{Constants.DefaultAzureADEndpoint}/{audience}"; } /// @@ -338,6 +315,7 @@ private static string GetAuthorityUrl(IAuthContext authContext) /// /// Current context /// A based on provided context + /// A based on provided context private static X509Certificate2 GetCertificate(IAuthContext authContext) { if (authContext is null) @@ -463,18 +441,5 @@ public static Task DeleteAuthRecordAsync() File.Delete(Constants.AuthRecordPath); return Task.CompletedTask; } - - public class AuthRecord : IAuthRecord - { - public AuthRecord() - { - } - public string Authority { get; set; } - public string ClientId { get; set; } - public string HomeAccountId { get; set; } - public string TenantId { get; set; } - public string Username { get; set; } - public string Version { get; set; } = "1.0"; - } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Utilities/WindowHandleUtlities.cs b/src/Authentication/Authentication.Core/Utilities/WindowHandleUtlities.cs new file mode 100644 index 00000000000..6ce5bdfb3bd --- /dev/null +++ b/src/Authentication/Authentication.Core/Utilities/WindowHandleUtlities.cs @@ -0,0 +1,52 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using Microsoft.Identity.Client.Extensions.Msal; +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Graph.PowerShell.Authentication.Core.Utilities +{ + internal static class WindowHandleUtlities + { + enum GetAncestorFlags + { + GetParent = 1, + GetRoot = 2, + /// + /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent. + /// + GetRootOwner = 3 + } + + /// + /// Retrieves the handle to the ancestor of the specified window. + /// See https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token-wam#console-applications. + /// + /// A handle to the window whose ancestor is to be retrieved. + /// If this parameter is the desktop window, the function returns NULL. + /// The ancestor to be retrieved. + /// The return value is the handle to the ancestor window. + [DllImport("user32.dll", ExactSpelling = true)] + static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags); + + [DllImport("kernel32.dll")] + static extern IntPtr GetConsoleWindow(); + + public static IntPtr GetConsoleOrTerminalWindow() + { + if (SharedUtilities.IsWindowsPlatform()) + { + IntPtr consoleHandle = GetConsoleWindow(); + IntPtr handle = GetAncestor(consoleHandle, GetAncestorFlags.GetRootOwner); + return handle; + } + else + { + // can't call Windows native APIs + return (IntPtr)0; + } + } + } +} diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec index e70254455d6..d0da7f9ca91 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec @@ -44,6 +44,7 @@ + diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 b/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 index b3516a2d9be..792636e9907 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.psm1 @@ -2,25 +2,6 @@ # Load the module dll $ModulePath = (Join-Path $PSScriptRoot 'Microsoft.Graph.Authentication.dll') $null = Import-Module -Name $ModulePath -function Import-Assembly { - param ( - [string] - $AssemblyDirectory - ) - if (Test-Path $AssemblyDirectory -ErrorAction Ignore) { - try { - Get-ChildItem -ErrorAction Stop -Path $AssemblyDirectory -Filter "*.dll" | ForEach-Object { - try { - Add-Type -Path $_.FullName -ErrorAction Ignore | Out-Null - } - catch { - Write-Verbose $_ - } - } - } - catch {} - } -} # Export nothing to clear implicit exports. Export-ModuleMember diff --git a/src/Authentication/Authentication/ModuleInitializer.cs b/src/Authentication/Authentication/ModuleInitializer.cs index cd8b4a0bb77..c04d4c4fe46 100644 --- a/src/Authentication/Authentication/ModuleInitializer.cs +++ b/src/Authentication/Authentication/ModuleInitializer.cs @@ -86,7 +86,7 @@ public void OnRemove(PSModuleInfo psModuleInfo) private static bool IsAssemblyMatching(AssemblyName assemblyName, Assembly requestingAssembly) { return requestingAssembly != null - ? requestingAssembly.FullName.StartsWith("Microsoft") && IsAssemblyPresent(assemblyName) + ? (requestingAssembly.FullName.StartsWith("Microsoft") || requestingAssembly.FullName.StartsWith("Azure.Identity")) && IsAssemblyPresent(assemblyName) : IsAssemblyPresent(assemblyName); } @@ -100,7 +100,7 @@ private static bool IsAssemblyPresent(AssemblyName assemblyName) { return s_dependencies.Contains(assemblyName.FullName) || s_psEditionDependencies.Contains(assemblyName.FullName) ? true - : !string.IsNullOrEmpty(s_dependencies.SingleOrDefault((x) => x.StartsWith(assemblyName.Name))) || !string.IsNullOrEmpty(s_psEditionDependencies.SingleOrDefault((x) => x.StartsWith(assemblyName.Name))); + : !string.IsNullOrEmpty(s_dependencies.SingleOrDefault((x) => x.StartsWith($"{assemblyName.Name},"))) || !string.IsNullOrEmpty(s_psEditionDependencies.SingleOrDefault((x) => x.StartsWith($"{assemblyName.Name},"))); } /// From a9457f90ff8e278e108c48c6ad6b4191e5ea8508 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Wed, 14 Jun 2023 08:26:02 -0700 Subject: [PATCH 13/18] Saving user's graphoptions settings onto disk --- .../Authentication/Cmdlets/SetMgGraphOption.cs | 4 ++++ .../Authentication/Common/GraphSessionInitializer.cs | 11 ++++++++++- src/Authentication/Authentication/Constants.cs | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index 0f1c3797248..c2e7e4485ca 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -2,6 +2,8 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ +using Newtonsoft.Json; +using System.IO; using System.Management.Automation; namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets @@ -39,6 +41,8 @@ protected override void ProcessRecord() else WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); } + + File.WriteAllText(Constants.GraphOptionsFilePath, JsonConvert.SerializeObject(GraphSession.Instance.GraphOption, Formatting.Indented)); } protected override void EndProcessing() diff --git a/src/Authentication/Authentication/Common/GraphSessionInitializer.cs b/src/Authentication/Authentication/Common/GraphSessionInitializer.cs index 56931025eff..42910b74087 100644 --- a/src/Authentication/Authentication/Common/GraphSessionInitializer.cs +++ b/src/Authentication/Authentication/Common/GraphSessionInitializer.cs @@ -5,7 +5,9 @@ using Microsoft.Graph.PowerShell.Authentication.Helpers; using Microsoft.Graph.PowerShell.Authentication.Interfaces; using Microsoft.Graph.PowerShell.Authentication.Models; +using Newtonsoft.Json; using System; +using System.IO; using System.Management.Automation; using RequestContext = Microsoft.Graph.PowerShell.Authentication.Models.RequestContext; @@ -26,11 +28,18 @@ public static void InitializeSession() /// internal static GraphSession CreateInstance(IDataStore dataStore = null) { + IGraphOption graphOptions = null; + if (File.Exists(Constants.GraphOptionsFilePath)) + { + // Deserialize the JSON into the GraphOption instance + graphOptions = JsonConvert.DeserializeObject(File.ReadAllText(Constants.GraphOptionsFilePath)); + } + return new GraphSession { DataStore = dataStore ?? new DiskDataStore(), RequestContext = new RequestContext(), - GraphOption = new GraphOption() + GraphOption = graphOptions ?? new GraphOption() }; } /// diff --git a/src/Authentication/Authentication/Constants.cs b/src/Authentication/Authentication/Constants.cs index 906b7b6786b..6bc4d5ec1b3 100644 --- a/src/Authentication/Authentication/Constants.cs +++ b/src/Authentication/Authentication/Constants.cs @@ -24,6 +24,7 @@ public static class Constants internal const int MAX_NUMBER_OF_RETRY = 10; internal const int DEFAULT_RETRY_DELAY = 3; internal const int DEFAULT_MAX_RETRY = 3; + internal static readonly string GraphOptionsFilePath = Path.Combine(Core.Constants.GraphDirectoryPath, "mg.graphoptions.json"); public static class HelpMessages { From 88e840c6f2c805d81e827b70fe694d9d17b001ff Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" <22969702+FehintolaObafemi@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:03:09 -0700 Subject: [PATCH 14/18] Update src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs Co-authored-by: Peter Ombwa --- .../Authentication/Cmdlets/SetMgGraphOption.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index c2e7e4485ca..65751b59432 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -33,14 +33,6 @@ protected override void ProcessRecord() else WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); } - else - { - GraphSession.Instance.GraphOption.EnableWAMForMSGraph = !currentSetting; - if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) - WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); - else - WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); - } File.WriteAllText(Constants.GraphOptionsFilePath, JsonConvert.SerializeObject(GraphSession.Instance.GraphOption, Formatting.Indented)); } From eae747d72c14695e2630a8344d7fb35769544947 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" <22969702+FehintolaObafemi@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:03:29 -0700 Subject: [PATCH 15/18] Update src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs Co-authored-by: Peter Ombwa --- src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index 65751b59432..976898e543f 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -22,9 +22,6 @@ protected override void BeginProcessing() protected override void ProcessRecord() { base.ProcessRecord(); - - bool currentSetting = GraphSession.Instance.GraphOption.EnableWAMForMSGraph; - if (EnableLoginByWAM.IsPresent) { GraphSession.Instance.GraphOption.EnableWAMForMSGraph = EnableLoginByWAM; From 17bb02fc0113e1984b27a26a9e3c6522f27ab2f2 Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Fri, 16 Jun 2023 15:13:46 -0700 Subject: [PATCH 16/18] changing -EnableLoginByWAM to bool --- .../Authentication/Cmdlets/SetMgGraphOption.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index 976898e543f..2c59eae90dd 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -12,7 +12,7 @@ namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets public class SetMgGraphOption : PSCmdlet { [Parameter] - public SwitchParameter EnableLoginByWAM { get; set; } + public Boolean EnableLoginByWAM { get; set; } protected override void BeginProcessing() { @@ -22,14 +22,19 @@ protected override void BeginProcessing() protected override void ProcessRecord() { base.ProcessRecord(); - if (EnableLoginByWAM.IsPresent) + if (EnableLoginByWAM) { GraphSession.Instance.GraphOption.EnableWAMForMSGraph = EnableLoginByWAM; - if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph) - WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); - else - WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); } + else + { + GraphSession.Instance.GraphOption.EnableWAMForMSGraph = false; + } + + if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph == true) + WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); + else + WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); File.WriteAllText(Constants.GraphOptionsFilePath, JsonConvert.SerializeObject(GraphSession.Instance.GraphOption, Formatting.Indented)); } From 8860763fdd59b8a3df35b3988982a05470b8adaa Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" Date: Fri, 16 Jun 2023 15:17:52 -0700 Subject: [PATCH 17/18] updates --- .../Authentication/Cmdlets/SetMgGraphOption.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index 2c59eae90dd..0dc21a53ca0 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -12,7 +12,7 @@ namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets public class SetMgGraphOption : PSCmdlet { [Parameter] - public Boolean EnableLoginByWAM { get; set; } + public bool EnableLoginByWAM { get; set; } protected override void BeginProcessing() { @@ -25,17 +25,13 @@ protected override void ProcessRecord() if (EnableLoginByWAM) { GraphSession.Instance.GraphOption.EnableWAMForMSGraph = EnableLoginByWAM; + WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); } else { GraphSession.Instance.GraphOption.EnableWAMForMSGraph = false; - } - - if (GraphSession.Instance.GraphOption.EnableWAMForMSGraph == true) - WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); - else WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); - + } File.WriteAllText(Constants.GraphOptionsFilePath, JsonConvert.SerializeObject(GraphSession.Instance.GraphOption, Formatting.Indented)); } From 893fe712cd421bb53ee3d99805fd580563fbdc4d Mon Sep 17 00:00:00 2001 From: "Taofeek F. Obafemi-Babatunde" <22969702+FehintolaObafemi@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:56:10 -0700 Subject: [PATCH 18/18] Update src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs Co-authored-by: Peter Ombwa --- .../Authentication/Cmdlets/SetMgGraphOption.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index 0dc21a53ca0..022effd1dd7 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -22,15 +22,11 @@ protected override void BeginProcessing() protected override void ProcessRecord() { base.ProcessRecord(); - if (EnableLoginByWAM) + if (this.IsParameterBound(nameof(EnableLoginByWAM))) { GraphSession.Instance.GraphOption.EnableWAMForMSGraph = EnableLoginByWAM; - WriteObject("[Preview] Signin by Web Account Manager (WAM) is enabled."); - } - else - { - GraphSession.Instance.GraphOption.EnableWAMForMSGraph = false; - WriteObject("[Preview] Signin by Web Account Manager (WAM) is disabled."); + var message = $"Signin by Web Account Manager (WAM) is {(EnableLoginByWAM ? "enabled" : "disabled")}."; + WriteObject(message); } File.WriteAllText(Constants.GraphOptionsFilePath, JsonConvert.SerializeObject(GraphSession.Instance.GraphOption, Formatting.Indented)); }