From f38148626c984dce809758bd8c059c32b338c466 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Tue, 5 Dec 2023 16:55:24 +0800 Subject: [PATCH 1/6] Redirct DeviceCode Info from warning stream to information stream --- .../Accounts/Account/ConnectAzureRmAccount.cs | 33 +++++++++++++++++++ .../Accounts/Properties/Resources.Designer.cs | 9 +++++ .../Accounts/Properties/Resources.resx | 3 ++ .../Authenticators/DeviceCodeAuthenticator.cs | 13 +++++++- 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs index 74177f30f4f4..732cde016f76 100644 --- a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs +++ b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs @@ -45,6 +45,7 @@ using Microsoft.WindowsAzure.Commands.Utilities.Common; using Microsoft.Azure.PowerShell.Common.Share.Survey; using Microsoft.Azure.Commands.Profile.Utilities; +using System.Management.Automation.Runspaces; namespace Microsoft.Azure.Commands.Profile { @@ -249,6 +250,7 @@ protected override IAzureContext DefaultContext protected override void BeginProcessing() { base.BeginProcessing(); + Validate(); if (AzureEnvironment.PublicEnvironments.ContainsKey(EnvironmentName.AzureCloud)) { _environment = AzureEnvironment.PublicEnvironments[EnvironmentName.AzureCloud]; @@ -273,11 +275,19 @@ protected override void BeginProcessing() _writeWarningEvent -= WriteWarningSender; _writeWarningEvent += WriteWarningSender; + _writeInformationEvent -= WriteInformationSender; + _writeInformationEvent += WriteInformationSender; + // store the original write warning handler, register a thread safe one AzureSession.Instance.TryGetComponent(WriteWarningKey, out _originalWriteWarning); AzureSession.Instance.UnregisterComponent>(WriteWarningKey); AzureSession.Instance.RegisterComponent(WriteWarningKey, () => _writeWarningEvent); + // store the original write information handler, register a thread safe one + AzureSession.Instance.TryGetComponent(WriteInformationKey, out _originalWriteInformation); + AzureSession.Instance.UnregisterComponent>(WriteInformationKey); + AzureSession.Instance.RegisterComponent(WriteInformationKey, () => _writeInformationEvent); + // todo: ideally cancellation token should be passed to authentication factory as a parameter // however AuthenticationFactory.Authenticate does not support it // so I store it in AzureSession.Instance as a global variable @@ -289,11 +299,19 @@ protected override void BeginProcessing() private event EventHandler _writeWarningEvent; private event EventHandler _originalWriteWarning; + private event EventHandler _writeInformationEvent; + private event EventHandler _originalWriteInformation; + private void WriteWarningSender(object sender, StreamEventArgs args) { _tasks.Enqueue(new Task(() => this.WriteWarning(args.Message))); } + private void WriteInformationSender(object sender, StreamEventArgs args) + { + _tasks.Enqueue(new Task(() => this.WriteInformation(args.Message))); + } + protected override void StopProcessing() { if (AzureSession.Instance.TryGetComponent("LoginCancellationToken", out CancellationTokenSource cancellationTokenSource)) @@ -562,6 +580,21 @@ public override void ExecuteCmdlet() } } + private void Validate() + { + if (MyInvocation.BoundParameters.ContainsKey(nameof(UseDeviceAuthentication)) + && IsWriteInformationIgnored()) + { + throw new ActionPreferenceStopException(Resources.DoNotIgnoreInformationIfUserDeviceAuth); + } + } + + private bool IsWriteInformationIgnored() + { + return !MyInvocation.BoundParameters.ContainsKey("InformationAction") && ActionPreference.Ignore.ToString().Equals(SessionState?.PSVariable?.GetValue("InformationPreference", ActionPreference.SilentlyContinue)?.ToString() ?? "") || + MyInvocation.BoundParameters.TryGetValue("InformationAction", out var value) && ActionPreference.Ignore.ToString().Equals(value?.ToString() ?? "", StringComparison.InvariantCultureIgnoreCase); + } + private string PreProcessAuthScope() { string mappedScope = AuthScope; diff --git a/src/Accounts/Accounts/Properties/Resources.Designer.cs b/src/Accounts/Accounts/Properties/Resources.Designer.cs index 2298c200f30a..1e31ef0f240a 100644 --- a/src/Accounts/Accounts/Properties/Resources.Designer.cs +++ b/src/Accounts/Accounts/Properties/Resources.Designer.cs @@ -537,6 +537,15 @@ internal static string DisableDataCollection { } } + /// + /// Looks up a localized string similar to Please do not set InformationAction or $InformationPreference to Ignore if you want to use device code authentication.. + /// + internal static string DoNotIgnoreInformationIfUserDeviceAuth { + get { + return ResourceManager.GetString("DoNotIgnoreInformationIfUserDeviceAuth", resourceCulture); + } + } + /// /// Looks up a localized string similar to Allow Azure PowerShell cmdlets to send data to Microsoft to improve the customer experience. /// diff --git a/src/Accounts/Accounts/Properties/Resources.resx b/src/Accounts/Accounts/Properties/Resources.resx index a8b3f3f8e0cd..f3d5dceb694b 100644 --- a/src/Accounts/Accounts/Properties/Resources.resx +++ b/src/Accounts/Accounts/Properties/Resources.resx @@ -595,4 +595,7 @@ Personally identifiable information and confidential data may be written to the file located at '{0}'. Please ensure that appropriate access controls are assigned to the saved file. + + Please do not set InformationAction or $InformationPreference to Ignore if you want to use device code authentication. + \ No newline at end of file diff --git a/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs b/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs index 3e1ac79a8fb0..64747854c758 100644 --- a/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs +++ b/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs @@ -23,6 +23,7 @@ using Microsoft.Azure.Commands.Common.Authentication; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; +using Microsoft.Azure.Commands.Common.Compute.Version2016_04_preview.Models; using Microsoft.Azure.Commands.ResourceManager.Common; namespace Microsoft.Azure.PowerShell.Authenticators @@ -64,7 +65,7 @@ public override Task Authenticate(AuthenticationParameters paramet private Task DeviceCodeFunc(DeviceCodeInfo info, CancellationToken cancellation) { - WriteWarning(info.Message); + WriteInfomartion(info.Message); return Task.CompletedTask; } @@ -73,6 +74,15 @@ public override bool CanAuthenticate(AuthenticationParameters parameters) return (parameters as DeviceCodeParameters) != null; } + private void WriteInfomartion(string message) + { + EventHandler writeInforamtionEvent; + if (AzureSession.Instance.TryGetComponent(AzureRMCmdlet.WriteInformationKey, out writeInforamtionEvent)) + { + writeInforamtionEvent(this, new StreamEventArgs() { Message = message }); + } + } + private void WriteWarning(string message) { EventHandler writeWarningEvent; @@ -81,5 +91,6 @@ private void WriteWarning(string message) writeWarningEvent(this, new StreamEventArgs() { Message = message }); } } + } } From e6f7c5a32c4414fa1a269fdfd663c55815fb4c30 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Tue, 5 Dec 2023 17:01:07 +0800 Subject: [PATCH 2/6] add change log --- src/Accounts/Accounts/ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Accounts/Accounts/ChangeLog.md b/src/Accounts/Accounts/ChangeLog.md index b33a818dd9fc..51227460ed1f 100644 --- a/src/Accounts/Accounts/ChangeLog.md +++ b/src/Accounts/Accounts/ChangeLog.md @@ -19,6 +19,7 @@ --> ## Upcoming Release +* Redirected device code login details from warning stream to information stream if use device authentication in `Connect-AzAccount`. * Added upcoming breaking change warning for deprecation of config parameter `DisableErrorRecordsPersistence`. ## Version 2.13.2 From e37f1afff9eea727f5e16712ce08f4245c7b70fc Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Thu, 11 Jan 2024 15:46:55 +0800 Subject: [PATCH 3/6] writehighlightedinformation --- src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs index 732cde016f76..8e6f0119ba99 100644 --- a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs +++ b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs @@ -309,7 +309,7 @@ private void WriteWarningSender(object sender, StreamEventArgs args) private void WriteInformationSender(object sender, StreamEventArgs args) { - _tasks.Enqueue(new Task(() => this.WriteInformation(args.Message))); + _tasks.Enqueue(new Task(() => this.WriteHighlightedInformation(args.Message))); } protected override void StopProcessing() @@ -806,6 +806,9 @@ protected override void EndProcessing() // unregister the thread-safe write warning, because it won't work out of this cmdlet AzureSession.Instance.UnregisterComponent>(WriteWarningKey); AzureSession.Instance.RegisterComponent(WriteWarningKey, () => _originalWriteWarning); + // unregister the thread-safe write information, because it won't work out of this cmdlet + AzureSession.Instance.UnregisterComponent>(WriteInformationKey); + AzureSession.Instance.RegisterComponent(WriteInformationKey, () => _originalWriteInformation); } } } From d9d5d009a794112a9a8d7d101dc52ce616fc5712 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Wed, 24 Jan 2024 12:24:47 +0800 Subject: [PATCH 4/6] Formmat device code login message --- .../Accounts/Account/ConnectAzureRmAccount.cs | 2 +- .../Authenticators/DeviceCodeAuthenticator.cs | 32 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs index 8e6f0119ba99..04e145c6e22a 100644 --- a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs +++ b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs @@ -309,7 +309,7 @@ private void WriteWarningSender(object sender, StreamEventArgs args) private void WriteInformationSender(object sender, StreamEventArgs args) { - _tasks.Enqueue(new Task(() => this.WriteHighlightedInformation(args.Message))); + _tasks.Enqueue(new Task(() => this.WriteStringInformation(args.Message))); } protected override void StopProcessing() diff --git a/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs b/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs index 64747854c758..21bb39046fdd 100644 --- a/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs +++ b/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs @@ -13,6 +13,7 @@ // ---------------------------------------------------------------------------------- using System; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -25,6 +26,7 @@ using Microsoft.Azure.Commands.Common.Authentication.Abstractions; using Microsoft.Azure.Commands.Common.Compute.Version2016_04_preview.Models; using Microsoft.Azure.Commands.ResourceManager.Common; +using Microsoft.WindowsAzure.Commands.Common; namespace Microsoft.Azure.PowerShell.Authenticators { @@ -65,7 +67,7 @@ public override Task Authenticate(AuthenticationParameters paramet private Task DeviceCodeFunc(DeviceCodeInfo info, CancellationToken cancellation) { - WriteInfomartion(info.Message); + WriteInfomartion(info.Message, info.UserCode); return Task.CompletedTask; } @@ -74,23 +76,29 @@ public override bool CanAuthenticate(AuthenticationParameters parameters) return (parameters as DeviceCodeParameters) != null; } - private void WriteInfomartion(string message) + private static string LoginToAzurePhrase = $"{PSStyle.Bold}{PSStyle.BackgroundColor.Blue}[Login to Azure]{PSStyle.Reset} "; + + private void WriteInfomartion(string message, string userCode) { - EventHandler writeInforamtionEvent; - if (AzureSession.Instance.TryGetComponent(AzureRMCmdlet.WriteInformationKey, out writeInforamtionEvent)) + var loginInfo = new StringBuilder(); + loginInfo.Append(LoginToAzurePhrase); + + if (!string.IsNullOrEmpty(userCode)) { - writeInforamtionEvent(this, new StreamEventArgs() { Message = message }); + var formattedUserCode = $"{PSStyle.Underline}{userCode}{PSStyle.Reset}"; + var formattedMessage = message.Replace(userCode, formattedUserCode); + loginInfo.Append(formattedMessage); + } + else + { + loginInfo.Append(message); } - } - private void WriteWarning(string message) - { - EventHandler writeWarningEvent; - if (AzureSession.Instance.TryGetComponent(AzureRMCmdlet.WriteWarningKey, out writeWarningEvent)) + EventHandler writeInforamtionEvent; + if (AzureSession.Instance.TryGetComponent(AzureRMCmdlet.WriteInformationKey, out writeInforamtionEvent)) { - writeWarningEvent(this, new StreamEventArgs() { Message = message }); + writeInforamtionEvent(this, new StreamEventArgs() { Message = loginInfo.ToString() }); } } - } } From dacf92dd92d4d1ec5053ae442bd59d2a974e72d0 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Mon, 29 Jan 2024 12:56:30 +0800 Subject: [PATCH 5/6] rename writeinformation --- src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs index 04e145c6e22a..f53204514caa 100644 --- a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs +++ b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs @@ -309,7 +309,7 @@ private void WriteWarningSender(object sender, StreamEventArgs args) private void WriteInformationSender(object sender, StreamEventArgs args) { - _tasks.Enqueue(new Task(() => this.WriteStringInformation(args.Message))); + _tasks.Enqueue(new Task(() => this.WriteInformation(args.Message))); } protected override void StopProcessing() From 4b8d9d775ea50eb0eff262e3408d7acd16cddb4b Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Tue, 30 Jan 2024 10:47:18 +0800 Subject: [PATCH 6/6] polish code --- .../Accounts/Account/ConnectAzureRmAccount.cs | 7 +++---- src/Accounts/Accounts/ChangeLog.md | 7 +++---- .../Authenticators/DeviceCodeAuthenticator.cs | 14 +++++++------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs index 5adde17143f0..4492ca84f1ff 100644 --- a/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs +++ b/src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs @@ -250,7 +250,7 @@ protected override IAzureContext DefaultContext protected override void BeginProcessing() { base.BeginProcessing(); - Validate(); + ValidateActionRequiredMessageCanBePresented(); if (AzureEnvironment.PublicEnvironments.ContainsKey(EnvironmentName.AzureCloud)) { _environment = AzureEnvironment.PublicEnvironments[EnvironmentName.AzureCloud]; @@ -580,10 +580,9 @@ public override void ExecuteCmdlet() } } - private void Validate() + private void ValidateActionRequiredMessageCanBePresented() { - if (MyInvocation.BoundParameters.ContainsKey(nameof(UseDeviceAuthentication)) - && IsWriteInformationIgnored()) + if (UseDeviceAuthentication.IsPresent && IsWriteInformationIgnored()) { throw new ActionPreferenceStopException(Resources.DoNotIgnoreInformationIfUserDeviceAuth); } diff --git a/src/Accounts/Accounts/ChangeLog.md b/src/Accounts/Accounts/ChangeLog.md index 04394bcb054e..84e90958eb29 100644 --- a/src/Accounts/Accounts/ChangeLog.md +++ b/src/Accounts/Accounts/ChangeLog.md @@ -20,15 +20,14 @@ ## Upcoming Release * Redirected device code login messages from warning stream to information stream if use device authentication in `Connect-AzAccount`. -* Fixed the multiple `x-ms-unique-id` values issue +* Adjusted output format to be more user-friendly for `Get-AzContext/Tenant/Subscription` and `Invoke-AzRestMethod`, including + - ordering and grouping output items to make items easy to find. + - re-prioritizing positions for output properties to highlight valuable properties. * Upgraded the reference of Azure PowerShell Common to 1.3.90-preview. * Upgraded Azure.Identity to 1.10.3 [#23018]. - Renamed token cache from `msal.cache` to `msal.cache.cae` or `masl.cache.nocae`. * Enabled Continue Access Evaluation (CAE) for all Service Principals login methods. * Supported signing in with Microsoft Account (MSA) via Web Account Manager (WAM). Enable it by `Set-AzConfig -EnableLoginByWam $true`. -* Adjusted output format to be more user-friendly for `Get-AzContext/Tenant/Subscription` and `Invoke-AzRestMethod`, including - - ordering and grouping output items to make items easy to find. - - re-prioritizing positions for output properties to highlight valuable properties. * Fixed the multiple `x-ms-unique-id` values issue. ## Version 2.15.0 diff --git a/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs b/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs index 81c2e9cda0d2..4bba654f0262 100644 --- a/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs +++ b/src/Accounts/Authenticators/DeviceCodeAuthenticator.cs @@ -12,11 +12,6 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - using Azure.Core; using Azure.Identity; @@ -24,10 +19,14 @@ using Microsoft.Azure.Commands.Common.Authentication; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; -using Microsoft.Azure.Commands.Common.Compute.Version2016_04_preview.Models; using Microsoft.Azure.Commands.ResourceManager.Common; using Microsoft.WindowsAzure.Commands.Common; +using System; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + namespace Microsoft.Azure.PowerShell.Authenticators { public class DeviceCodeAuthenticator : DelegatingAuthenticator @@ -76,11 +75,12 @@ public override bool CanAuthenticate(AuthenticationParameters parameters) return (parameters as DeviceCodeParameters) != null; } - private static string LoginToAzurePhrase = $"{PSStyle.Bold}{PSStyle.BackgroundColor.Blue}[Login to Azure]{PSStyle.Reset} "; private void WriteInfomartion(string message, string userCode) { + var loginInfo = new StringBuilder(); + string LoginToAzurePhrase = $"{PSStyle.Bold}{PSStyle.BackgroundColor.Blue}[Login to Azure]{PSStyle.Reset} "; loginInfo.Append(LoginToAzurePhrase); if (!string.IsNullOrEmpty(userCode))