Skip to content

Commit 425b5fe

Browse files
authored
ctrl+c to abort login (#13396)
1 parent 8e3b705 commit 425b5fe

File tree

5 files changed

+36
-13
lines changed

5 files changed

+36
-13
lines changed

src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,13 @@ protected override void BeginProcessing()
227227
AzureSession.Instance.TryGetComponent(WriteWarningKey, out _originalWriteWarning);
228228
AzureSession.Instance.UnregisterComponent<EventHandler<StreamEventArgs>>(WriteWarningKey);
229229
AzureSession.Instance.RegisterComponent(WriteWarningKey, () => _writeWarningEvent);
230+
231+
// todo: ideally cancellation token should be passed to authentication factory as a parameter
232+
// however AuthenticationFactory.Authenticate does not support it
233+
// so I store it in AzureSession.Instance as a global variable
234+
// todo: CancellationTokenSource should be visiable only in cmdlet class
235+
// CancellationTokenSource.Token should be passed to other classes
236+
AzureSession.Instance.RegisterComponent("LoginCancellationToken", () => new CancellationTokenSource(), true);
230237
}
231238

232239
private event EventHandler<StreamEventArgs> _writeWarningEvent;
@@ -237,6 +244,14 @@ private void WriteWarningSender(object sender, StreamEventArgs args)
237244
_tasks.Enqueue(new Task(() => this.WriteWarning(args.Message)));
238245
}
239246

247+
protected override void StopProcessing()
248+
{
249+
if (AzureSession.Instance.TryGetComponent("LoginCancellationToken", out CancellationTokenSource cancellationTokenSource)) {
250+
cancellationTokenSource?.Cancel();
251+
}
252+
base.StopProcessing();
253+
}
254+
240255
public override void ExecuteCmdlet()
241256
{
242257
Guid subscrptionIdGuid;

src/Accounts/Accounts/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- Additional information about change #1
1919
-->
2020
## Upcoming Release
21+
* Supported interrupting login by hitting <kbd>CTRL</kbd>+<kbd>C</kbd>
2122
* Fixed an issue causing `Connect-AzAccount -KeyVaultAccessToken` not working [#13127]
2223
* Fixed null reference and method case insensitive in `Invoke-AzRestMethod`
2324

src/Accounts/Authentication/Authentication/DelegatingAuthenticator.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,31 @@ public abstract class DelegatingAuthenticator : IAuthenticator
2626
protected const string AdfsTenant = "adfs";
2727
protected const string OrganizationsTenant = "organizations";
2828

29+
protected CancellationToken AuthenticationCancellationToken
30+
{
31+
get
32+
{
33+
// todo: move "LoginCancellationToken" to common repo as a const
34+
if (AzureSession.Instance.TryGetComponent("LoginCancellationToken", out CancellationTokenSource cancellationTokenSource))
35+
{
36+
return cancellationTokenSource.Token;
37+
}
38+
return new CancellationTokenSource().Token;
39+
}
40+
}
41+
2942
public IAuthenticator Next { get; set; }
3043
public abstract bool CanAuthenticate(AuthenticationParameters parameters);
3144
public abstract Task<IAccessToken> Authenticate(AuthenticationParameters parameters, CancellationToken cancellationToken);
3245

3346
public Task<IAccessToken> Authenticate(AuthenticationParameters parameters)
3447
{
35-
var source = new CancellationTokenSource();
36-
return Authenticate(parameters, source.Token);
48+
return Authenticate(parameters, AuthenticationCancellationToken);
3749
}
3850

3951
public bool TryAuthenticate(AuthenticationParameters parameters, out Task<IAccessToken> token)
4052
{
41-
var source = new CancellationTokenSource();
42-
return TryAuthenticate(parameters, source.Token, out token);
53+
return TryAuthenticate(parameters, AuthenticationCancellationToken, out token);
4354
}
4455

4556
public bool TryAuthenticate(AuthenticationParameters parameters, CancellationToken cancellationToken, out Task<IAccessToken> token)

src/Accounts/Authenticators/DeviceCodeAuthenticator.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public override Task<IAccessToken> Authenticate(AuthenticationParameters paramet
3131
var deviceCodeParameters = parameters as DeviceCodeParameters;
3232
var tokenCacheProvider = parameters.TokenCacheProvider;
3333
var onPremise = parameters.Environment.OnPremise;
34-
//null instead of "organizations" should be passed to Azure.Identity to support MSA account
34+
//null instead of "organizations" should be passed to Azure.Identity to support MSA account
3535
var tenantId = onPremise ? AdfsTenant :
3636
(string.Equals(parameters.TenantId, OrganizationsTenant, StringComparison.OrdinalIgnoreCase) ? null : parameters.TenantId);
3737
var resource = parameters.Environment.GetEndpoint(parameters.ResourceId) ?? parameters.ResourceId;
@@ -51,15 +51,13 @@ public override Task<IAccessToken> Authenticate(AuthenticationParameters paramet
5151
TokenCache = tokenCache.TokenCache,
5252
};
5353
var codeCredential = new DeviceCodeCredential(options);
54-
var source = new CancellationTokenSource();
55-
source.CancelAfter(TimeSpan.FromMinutes(5));
5654

57-
var authTask = codeCredential.AuthenticateAsync(requestContext, source.Token);
55+
var authTask = codeCredential.AuthenticateAsync(requestContext, cancellationToken);
5856
return MsalAccessToken.GetAccessTokenAsync(
5957
authTask,
6058
codeCredential,
6159
requestContext,
62-
source.Token);
60+
cancellationToken);
6361
}
6462

6563
private Task DeviceCodeFunc(DeviceCodeInfo info, CancellationToken cancellation)

src/Accounts/Authenticators/InteractiveUserAuthenticator.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,13 @@ public override Task<IAccessToken> Authenticate(AuthenticationParameters paramet
6565
RedirectUri = GetReplyUrl(onPremise, interactiveParameters),
6666
};
6767
var browserCredential = new InteractiveBrowserCredential(options);
68-
var source = new CancellationTokenSource();
69-
source.CancelAfter(TimeSpan.FromMinutes(5));
70-
var authTask = browserCredential.AuthenticateAsync(requestContext, source.Token);
68+
var authTask = browserCredential.AuthenticateAsync(requestContext, cancellationToken);
7169

7270
return MsalAccessToken.GetAccessTokenAsync(
7371
authTask,
7472
browserCredential,
7573
requestContext,
76-
source.Token);
74+
cancellationToken);
7775
}
7876

7977
private Uri GetReplyUrl(bool onPremise, InteractiveParameters interactiveParameters)

0 commit comments

Comments
 (0)