Skip to content

Commit 139963f

Browse files
authored
Update Az CLI Cred flow to redirect stdin (Azure#49582)
1 parent c7e5251 commit 139963f

File tree

6 files changed

+30
-1
lines changed

6 files changed

+30
-1
lines changed

sdk/identity/Azure.Identity/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
### Breaking Changes
88

99
### Bugs Fixed
10+
- Fixed an issue where Azure CLI credential could hang or delay due to I/O contention when standard input/output was shared with the host process ([#49582](https://github.com/Azure/azure-sdk-for-net/pull/49582)).
1011

1112
### Other Changes
1213

sdk/identity/Azure.Identity/src/Credentials/AzureCliCredential.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private async ValueTask<AccessToken> RequestCliAccessTokenAsync(bool async, Toke
132132

133133
GetFileNameAndArguments(resource, tenantId, Subscription, out string fileName, out string argument);
134134
ProcessStartInfo processStartInfo = GetAzureCliProcessStartInfo(fileName, argument);
135-
using var processRunner = new ProcessRunner(_processService.Create(processStartInfo), ProcessTimeout, _logPII, cancellationToken);
135+
using var processRunner = new ProcessRunner(_processService.Create(processStartInfo), ProcessTimeout, _logPII, redirectStandardInput: true, cancellationToken);
136136

137137
string output;
138138
try

sdk/identity/Azure.Identity/src/IProcess.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Diagnostics;
6+
using System.IO;
67

78
namespace Azure.Identity
89
{
@@ -20,5 +21,6 @@ internal interface IProcess : IDisposable
2021
void Kill();
2122
void BeginOutputReadLine();
2223
void BeginErrorReadLine();
24+
StreamWriter StandardInput { get; }
2325
}
2426
}

sdk/identity/Azure.Identity/src/ProcessRunner.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ internal sealed class ProcessRunner : IDisposable
1818
private readonly TaskCompletionSource<ICollection<string>> _errorTcs;
1919
private readonly ICollection<string> _outputData;
2020
private readonly ICollection<string> _errorData;
21+
private readonly bool _redirectStandardInput;
2122

2223
private readonly CancellationToken _cancellationToken;
2324
private readonly CancellationTokenSource _timeoutCts;
@@ -26,10 +27,15 @@ internal sealed class ProcessRunner : IDisposable
2627
public int ExitCode => _process.ExitCode;
2728

2829
public ProcessRunner(IProcess process, TimeSpan timeout, bool logPII, CancellationToken cancellationToken)
30+
: this(process, timeout, logPII, false, cancellationToken)
31+
{ }
32+
33+
public ProcessRunner(IProcess process, TimeSpan timeout, bool logPII, bool redirectStandardInput, CancellationToken cancellationToken)
2934
{
3035
_logPII = logPII;
3136
_process = process;
3237
_timeout = timeout;
38+
_redirectStandardInput = redirectStandardInput;
3339

3440
if (_logPII)
3541
{
@@ -77,6 +83,7 @@ private void StartProcess()
7783
_process.StartInfo.UseShellExecute = false;
7884
_process.StartInfo.RedirectStandardOutput = true;
7985
_process.StartInfo.RedirectStandardError = true;
86+
_process.StartInfo.RedirectStandardInput = _redirectStandardInput;
8087

8188
_process.OutputDataReceived += (sender, args) => OnDataReceived(args, _outputData, _outputTcs);
8289
_process.ErrorDataReceived += (sender, args) => OnDataReceived(args, _errorData, _errorTcs);
@@ -92,6 +99,21 @@ private void StartProcess()
9299
_process.BeginOutputReadLine();
93100
_process.BeginErrorReadLine();
94101
_ctRegistration = _cancellationToken.Register(HandleCancel, false);
102+
103+
if (_redirectStandardInput)
104+
{
105+
try
106+
{
107+
_process.StandardInput.Close();
108+
}
109+
catch (Exception ex)
110+
{
111+
if (_logPII)
112+
{
113+
AzureIdentityEventSource.Singleton.ProcessRunnerError($"Failed to close StandardInput: {ex}");
114+
}
115+
}
116+
}
95117
}
96118

97119
private async ValueTask HandleExitAsync()

sdk/identity/Azure.Identity/src/ProcessService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public ProcessStartInfo StartInfo
3636
get => _process.StartInfo;
3737
set => _process.StartInfo = value;
3838
}
39+
public StreamWriter StandardInput => _process.StandardInput;
3940

4041
public event EventHandler Exited
4142
{

sdk/identity/Azure.Identity/tests/TestProcess.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Diagnostics;
6+
using System.IO;
67
using System.Linq.Expressions;
78
using System.Reflection;
89
using System.Threading;
@@ -71,6 +72,8 @@ public int ExitCode
7172
}
7273
}
7374

75+
public StreamWriter StandardInput => throw new NotImplementedException();
76+
7477
public event EventHandler Exited;
7578
public event EventHandler Started;
7679
public event DataReceivedEventHandler OutputDataReceived;

0 commit comments

Comments
 (0)