Skip to content

Commit fad77fa

Browse files
authored
[Accounts] Support interactive subscription selection (#24513) (#24549)
* [Accounts] Support interactive subscription selection (#24513) * Support Subscription Selection (#24451) * Readline to get selected subscription * wip * move prompt login to list subscription instead of populating contexts * fix some bugs * add announcements and feedback links * fix comments * skip test cases for WriteInformation * list for single tenant * code refactor * throw error if enter nothing * add change log
1 parent f61c1d1 commit fad77fa

File tree

10 files changed

+306
-74
lines changed

10 files changed

+306
-74
lines changed

src/Accounts/Accounts.Test/AzureRMProfileTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ public void LoadingProfileWorks()
12991299

13001300

13011301
[Fact]
1302-
[Trait(Category.AcceptanceType, Category.CheckIn)]
1302+
[Trait(Category.AcceptanceType, Category.LiveOnly)]
13031303
public void CanRenewTokenLogin()
13041304
{
13051305
var tenants = new List<string> { DefaultTenant.ToString() };

src/Accounts/Accounts.Test/LoginCmdletTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ public void ThrowOnUnknownEnvironment()
516516
}
517517

518518
[Fact]
519-
[Trait(Category.AcceptanceType, Category.CheckIn)]
519+
[Trait(Category.AcceptanceType, Category.LiveOnly)]
520520
public void LoginUsingSkipValidation()
521521
{
522522
var cmdlt = new ConnectAzureRmAccountCommand();

src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,6 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15-
using System;
16-
using System.Collections.Concurrent;
17-
using System.Linq;
18-
using System.Management.Automation;
19-
using System.Runtime.InteropServices;
20-
using System.Security;
21-
using System.Text;
22-
using System.Threading;
23-
using System.Threading.Tasks;
24-
2515
using Azure.Identity;
2616

2717
using Microsoft.Azure.Commands.Common.Authentication;
@@ -30,24 +20,33 @@
3020
using Microsoft.Azure.Commands.Common.Authentication.Factories;
3121
using Microsoft.Azure.Commands.Common.Authentication.Models;
3222
using Microsoft.Azure.Commands.Common.Authentication.ResourceManager.Common;
23+
using Microsoft.Azure.Commands.Common.Authentication.Sanitizer;
3324
using Microsoft.Azure.Commands.Profile.Common;
3425
using Microsoft.Azure.Commands.Profile.Models.Core;
3526
using Microsoft.Azure.Commands.Profile.Properties;
27+
using Microsoft.Azure.Commands.Profile.Utilities;
3628
using Microsoft.Azure.Commands.ResourceManager.Common;
3729
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
3830
using Microsoft.Azure.Commands.Shared.Config;
3931
using Microsoft.Azure.PowerShell.Authenticators;
4032
using Microsoft.Azure.PowerShell.Authenticators.Factories;
4133
using Microsoft.Azure.PowerShell.Common.Config;
34+
using Microsoft.Azure.PowerShell.Common.Share.Survey;
4235
using Microsoft.Identity.Client;
4336
using Microsoft.WindowsAzure.Commands.Common;
37+
using Microsoft.WindowsAzure.Commands.Common.Sanitizer;
4438
using Microsoft.WindowsAzure.Commands.Common.Utilities;
4539
using Microsoft.WindowsAzure.Commands.Utilities.Common;
46-
using Microsoft.Azure.PowerShell.Common.Share.Survey;
47-
using Microsoft.Azure.Commands.Profile.Utilities;
48-
using System.Management.Automation.Runspaces;
49-
using Microsoft.WindowsAzure.Commands.Common.Sanitizer;
50-
using Microsoft.Azure.Commands.Common.Authentication.Sanitizer;
40+
41+
using System;
42+
using System.Collections.Concurrent;
43+
using System.Linq;
44+
using System.Management.Automation;
45+
using System.Runtime.InteropServices;
46+
using System.Security;
47+
using System.Text;
48+
using System.Threading;
49+
using System.Threading.Tasks;
5150

5251
namespace Microsoft.Azure.Commands.Profile
5352
{
@@ -328,6 +327,7 @@ public override void ExecuteCmdlet()
328327
Guid subscriptionIdGuid;
329328
string subscriptionName = null;
330329
string subscriptionId = null;
330+
bool isInteractiveAuthentication = IsInteractiveAuthentication();
331331
if (MyInvocation.BoundParameters.ContainsKey(nameof(Subscription)))
332332
{
333333
if (Guid.TryParse(Subscription, out subscriptionIdGuid))
@@ -506,7 +506,7 @@ public override void ExecuteCmdlet()
506506
commonUtilities = new CommonUtilities();
507507
AzureSession.Instance.RegisterComponent(nameof(CommonUtilities), () => commonUtilities);
508508
}
509-
if (!commonUtilities.IsDesktopSession() && IsUsingInteractiveAuthentication())
509+
if (!commonUtilities.IsDesktopSession() && IsBrowserPopUpInteractiveAuthentication())
510510
{
511511
WriteWarning(Resources.InteractiveAuthNotSupported);
512512
return;
@@ -523,8 +523,10 @@ public override void ExecuteCmdlet()
523523
shouldPopulateContextList = false;
524524
}
525525

526-
profileClient.WarningLog = (message) => _tasks.Enqueue(new Task(() => this.WriteWarning(message)));
526+
profileClient.WarningLog = (message) => _tasks.Enqueue(new Task(() => this.WriteWarning(message)));
527+
profileClient.InformationLog = (message) => _tasks.Enqueue(new Task(() => this.WriteInformation(message, false)));
527528
profileClient.DebugLog = (message) => _tasks.Enqueue(new Task(() => this.WriteDebugWithTimestamp(message)));
529+
528530
var task = new Task<AzureRmProfile>(() => profileClient.Login(
529531
azureAccount,
530532
_environment,
@@ -538,7 +540,9 @@ public override void ExecuteCmdlet()
538540
name,
539541
shouldPopulateContextList,
540542
MaxContextPopulation,
541-
resourceId));
543+
resourceId,
544+
Prompt,
545+
isInteractiveAuthentication));
542546
task.Start();
543547
while (!task.IsCompleted)
544548
{
@@ -569,7 +573,7 @@ public override void ExecuteCmdlet()
569573
}
570574
else
571575
{
572-
if (IsUsingInteractiveAuthentication())
576+
if (IsBrowserPopUpInteractiveAuthentication())
573577
{
574578
//Display only if user is using Interactive auth
575579
WriteWarning(Resources.SuggestToUseDeviceCodeAuth);
@@ -579,9 +583,17 @@ public override void ExecuteCmdlet()
579583
}
580584
}
581585
});
586+
587+
WriteInformation($"[Announcements]{System.Environment.NewLine}Share your feedback regarding your experience with `Connect-AzAccount` at: https://aka.ms/azloginfeedback{System.Environment.NewLine}");
588+
WriteInformation($"If you encounter any problem, please open an issue at: https://aka.ms/azpsissue{System.Environment.NewLine}");
582589
}
583590
}
584591

592+
private bool IsInteractiveAuthentication()
593+
{
594+
return ParameterSetName.Equals(UserParameterSet);
595+
}
596+
585597
private void ValidateActionRequiredMessageCanBePresented()
586598
{
587599
if (UseDeviceAuthentication.IsPresent && IsWriteInformationIgnored())
@@ -608,9 +620,9 @@ private string PreProcessAuthScope()
608620
return mappedScope;
609621
}
610622

611-
private bool IsUsingInteractiveAuthentication()
623+
private bool IsBrowserPopUpInteractiveAuthentication()
612624
{
613-
return ParameterSetName == UserParameterSet && UseDeviceAuthentication == false;
625+
return ParameterSetName.Equals(UserParameterSet) && UseDeviceAuthentication.IsPresent == false;
614626
}
615627

616628
private bool IsUnableToOpenWebPageError(AuthenticationFailedException exception)
@@ -654,6 +666,20 @@ private void WriteWarningEvent(string message)
654666
}
655667
}
656668

669+
private void WriteInformationEvent(string message)
670+
{
671+
EventHandler<StreamEventArgs> writeInformationEvent;
672+
if (AzureSession.Instance.TryGetComponent(WriteInformationKey, out writeInformationEvent))
673+
{
674+
writeInformationEvent(this, new StreamEventArgs() { Message = message });
675+
}
676+
}
677+
private string Prompt(string message)
678+
{
679+
_tasks.Enqueue(new Task(() => this.WriteInformation(message, true)));
680+
return this.Host.UI.ReadLine();
681+
}
682+
657683
private static bool CheckForExistingContext(AzureRmProfile profile, string name)
658684
{
659685
return name != null && profile?.Contexts != null && profile.Contexts.ContainsKey(name);

src/Accounts/Accounts/Accounts.generated.format.ps1xml

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,23 @@
1010
<TableHeaders>
1111
<TableColumnHeader>
1212
<Alignment>Left</Alignment>
13-
<Label>Account</Label>
14-
</TableColumnHeader>
15-
<TableColumnHeader>
16-
<Alignment>Left</Alignment>
17-
<Label>SubscriptionName</Label>
13+
<Label>Subscription name</Label>
1814
</TableColumnHeader>
1915
<TableColumnHeader>
2016
<Alignment>Left</Alignment>
21-
<Label>TenantId</Label>
22-
</TableColumnHeader>
23-
<TableColumnHeader>
24-
<Alignment>Left</Alignment>
25-
<Label>Environment</Label>
17+
<Label>Tenant</Label>
2618
</TableColumnHeader>
2719
</TableHeaders>
2820
<TableRowEntries>
2921
<TableRowEntry>
3022
<TableColumnItems>
3123
<TableColumnItem>
3224
<Alignment>Left</Alignment>
33-
<ScriptBlock>$_.Context.Account.ToString()</ScriptBlock>
34-
</TableColumnItem>
35-
<TableColumnItem>
36-
<Alignment>Left</Alignment>
37-
<ScriptBlock>$_.Context.Subscription.Name</ScriptBlock>
38-
</TableColumnItem>
39-
<TableColumnItem>
40-
<Alignment>Left</Alignment>
41-
<ScriptBlock>$_.Context.Tenant.ToString()</ScriptBlock>
25+
<ScriptBlock>if($null -ne $_.Context.Subscription.Name){$_.Context.Subscription.Name}else{$_.Context.Subscription.Id}</ScriptBlock>
4226
</TableColumnItem>
4327
<TableColumnItem>
4428
<Alignment>Left</Alignment>
45-
<ScriptBlock>$_.Context.Environment.ToString()</ScriptBlock>
29+
<ScriptBlock>if($null -ne $_.Context.Tenant.DefaultDomain){$_.Context.Tenant.DefaultDomain}else{$_.Context.Tenant.Id}</ScriptBlock>
4630
</TableColumnItem>
4731
</TableColumnItems>
4832
</TableRowEntry>

src/Accounts/Accounts/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-->
2020

2121
## Upcoming Release
22+
* Supported interactive subscription selection for user login flow.
2223

2324
## Version 2.17.0
2425
* Enabled globally disabling instance discovery before token acquisition [#22535].

0 commit comments

Comments
 (0)