Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit bd880b2

Browse files
author
Isaiah Williams
authored
Updating the way users are prompted to take action (#207)
1 parent 2de4e1e commit bd880b2

3 files changed

Lines changed: 81 additions & 23 deletions

File tree

src/PowerShell/Authenticators/DeviceCodeAuthenticator.cs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Authenticators
1414
/// </summary>
1515
internal class DeviceCodeAuthenticator : DelegatingAuthenticator
1616
{
17+
/// <summary>
18+
/// The message that will be written utilizing the prompt action.
19+
/// </summary>
20+
private string message;
21+
1722
/// <summary>
1823
/// Apply this authenticator to the given authentication parameters.
1924
/// </summary>
@@ -23,15 +28,32 @@ internal class DeviceCodeAuthenticator : DelegatingAuthenticator
2328
/// <returns>
2429
/// An instance of <see cref="AuthenticationToken" /> that represents the access token generated as result of a successful authenication.
2530
/// </returns>
26-
public override Task<AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, Action<string> promptAction = null, CancellationToken cancellationToken = default)
31+
public override async Task<AuthenticationResult> AuthenticateAsync(AuthenticationParameters parameters, Action<string> promptAction = null, CancellationToken cancellationToken = default)
2732
{
2833
IPublicClientApplication app = GetClient(parameters.Account, parameters.Environment).AsPublicClient();
2934

30-
return app.AcquireTokenWithDeviceCode(parameters.Scopes, deviceCodeResult =>
35+
Task<AuthenticationResult> task = Task<AuthenticationResult>.Factory.StartNew(() =>
36+
app.AcquireTokenWithDeviceCode(parameters.Scopes, deviceCodeResult =>
37+
{
38+
message = deviceCodeResult.Message;
39+
return Task.CompletedTask;
40+
}).ExecuteAsync(cancellationToken).GetAwaiter().GetResult());
41+
42+
while (true)
3143
{
32-
Console.WriteLine(deviceCodeResult.Message);
33-
return Task.CompletedTask;
34-
}).ExecuteAsync(cancellationToken);
44+
if (!string.IsNullOrEmpty(message))
45+
{
46+
promptAction(message);
47+
break;
48+
}
49+
50+
cancellationToken.ThrowIfCancellationRequested();
51+
Thread.Sleep(1000);
52+
}
53+
54+
await Task.CompletedTask;
55+
56+
return task.Result;
3557
}
3658

3759
/// <summary>

src/PowerShell/Authenticators/InteractiveUserAuthenticator.cs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace Microsoft.Store.PartnerCenter.PowerShell.Authenticators
55
{
66
using System;
7+
using System.Collections.Generic;
78
using System.Collections.Specialized;
89
using System.Net;
910
using System.Net.Sockets;
@@ -34,9 +35,13 @@ public override async Task<AuthenticationResult> AuthenticateAsync(Authenticatio
3435
AuthenticationResult authResult;
3536
IClientApplicationBase app;
3637
InteractiveParameters interactiveParameters = parameters as InteractiveParameters;
38+
Task<Task<AuthenticationResult>> task;
3739
TcpListener listener = null;
40+
int count = 0;
3841
string redirectUri = null;
3942

43+
Queue<string> messages;
44+
4045
int port = 8399;
4146

4247
while (++port < 9000)
@@ -51,36 +56,62 @@ public override async Task<AuthenticationResult> AuthenticateAsync(Authenticatio
5156
}
5257
catch (Exception ex)
5358
{
54-
Console.WriteLine($"Port {port} is taken with exception '{ex.Message}'; trying to connect to the next port.");
59+
promptAction($"Port {port} is taken with exception '{ex.Message}'; trying to connect to the next port.");
5560
listener?.Stop();
5661
}
5762
}
5863

5964
app = GetClient(parameters.Account, parameters.Environment, redirectUri);
65+
messages = new Queue<string>();
6066

6167
if (app is IConfidentialClientApplication)
6268
{
63-
ICustomWebUi customWebUi = new DefaultOsBrowserWebUi(interactiveParameters.Message);
69+
ICustomWebUi customWebUi = new DefaultOsBrowserWebUi(messages, interactiveParameters.Message);
6470

65-
Uri authCodeUrl = await customWebUi.AcquireAuthorizationCodeAsync(
66-
await app.AsConfidentialClient().GetAuthorizationRequestUrl(parameters.Scopes).ExecuteAsync(cancellationToken).ConfigureAwait(false),
67-
new Uri(redirectUri),
68-
cancellationToken).ConfigureAwait(false);
71+
task = Task<Task<AuthenticationResult>>.Factory.StartNew(async () =>
72+
{
73+
Uri authCodeUrl = await customWebUi.AcquireAuthorizationCodeAsync(
74+
await app.AsConfidentialClient().GetAuthorizationRequestUrl(parameters.Scopes).ExecuteAsync(cancellationToken).ConfigureAwait(false),
75+
new Uri(redirectUri),
76+
cancellationToken).ConfigureAwait(false);
6977

70-
NameValueCollection queryStringParameters = HttpUtility.ParseQueryString(authCodeUrl.Query);
78+
NameValueCollection queryStringParameters = HttpUtility.ParseQueryString(authCodeUrl.Query);
7179

72-
authResult = await app.AsConfidentialClient().AcquireTokenByAuthorizationCode(
73-
parameters.Scopes,
74-
queryStringParameters["code"]).ExecuteAsync(cancellationToken).ConfigureAwait(false);
80+
return await app.AsConfidentialClient().AcquireTokenByAuthorizationCode(
81+
parameters.Scopes,
82+
queryStringParameters["code"]).ExecuteAsync(cancellationToken).ConfigureAwait(false);
83+
});
7584
}
7685
else
7786
{
78-
authResult = await app.AsPublicClient().AcquireTokenInteractive(parameters.Scopes)
79-
.WithCustomWebUi(new DefaultOsBrowserWebUi(interactiveParameters.Message))
80-
.WithPrompt(Prompt.ForceLogin)
81-
.ExecuteAsync(cancellationToken).ConfigureAwait(false);
87+
task = Task<Task<AuthenticationResult>>.Factory.StartNew(async () =>
88+
{
89+
return await app.AsPublicClient().AcquireTokenInteractive(parameters.Scopes)
90+
.WithCustomWebUi(new DefaultOsBrowserWebUi(messages, interactiveParameters.Message))
91+
.WithPrompt(Prompt.ForceLogin)
92+
.ExecuteAsync(cancellationToken).ConfigureAwait(false);
93+
});
94+
}
95+
96+
while (true)
97+
{
98+
while (messages.Count > 0)
99+
{
100+
promptAction(messages.Dequeue());
101+
count++;
102+
}
103+
104+
if (count >= 2)
105+
{
106+
break;
107+
}
108+
109+
cancellationToken.ThrowIfCancellationRequested();
110+
Thread.Sleep(1000);
82111
}
83112

113+
authResult = await task.Result.ConfigureAwait(false);
114+
84115
return authResult;
85116
}
86117

src/PowerShell/Network/DefaultOsBrowserWebUi.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace Microsoft.Store.PartnerCenter.PowerShell.Network
55
{
66
using System;
7+
using System.Collections.Generic;
78
using System.Collections.Specialized;
89
using System.Diagnostics;
910
using System.Globalization;
@@ -46,15 +47,19 @@ internal class DefaultOsBrowserWebUi : ICustomWebUi
4647
/// </summary>
4748
private readonly string message;
4849

50+
private readonly Queue<string> messages;
51+
4952
/// <summary>
5053
/// Initializes a new instance of the <see cref="DefaultOsBrowserWebUi" /> class.
5154
/// </summary>
5255
/// <param name="message">The message written to the console.</param>
53-
public DefaultOsBrowserWebUi(string message)
56+
public DefaultOsBrowserWebUi(Queue<string> messages, string message)
5457
{
5558
message.AssertNotEmpty(nameof(message));
59+
messages.AssertNotNull(nameof(messages));
5660

5761
this.message = message;
62+
this.messages = messages;
5863
}
5964

6065
/// <summary>
@@ -66,14 +71,14 @@ public DefaultOsBrowserWebUi(string message)
6671
/// <returns>The URI returned back from the STS authorization endpoint. This URI contains a code=CODE parameter that MSAL.NET will extract and redeem.</returns>
6772
public async Task<Uri> AcquireAuthorizationCodeAsync(Uri authorizationUri, Uri redirectUri, CancellationToken cancellationToken)
6873
{
69-
Console.WriteLine("Attempting to launch a browser for authorization code login.");
74+
messages.Enqueue("Attempting to launch a browser for authorization code login.");
7075

7176
if (!OpenBrowser(authorizationUri.ToString()))
7277
{
73-
Console.WriteLine("Unable to launch a browser for authorization code login. Reverting to device code login.");
78+
messages.Enqueue("Unable to launch a browser for authorization code login. Reverting to device code login.");
7479
}
7580

76-
Console.WriteLine(message);
81+
messages.Enqueue(message);
7782

7883
using (SingleMessageTcpListener listener = new SingleMessageTcpListener(redirectUri.Port))
7984
{

0 commit comments

Comments
 (0)