private async ValueTask <AccessToken> RequestCliAccessTokenAsync(bool async, TokenRequestContext context, CancellationToken cancellationToken) { string resource = ScopeUtilities.ScopesToResource(context.Scopes); string tenantId = TenantIdResolver.Resolve(_tenantId, context, _allowMultiTenantAuthentication); ScopeUtilities.ValidateScope(resource); GetFileNameAndArguments(resource, tenantId, out string fileName, out string argument); ProcessStartInfo processStartInfo = GetAzureCliProcessStartInfo(fileName, argument); using var processRunner = new ProcessRunner(_processService.Create(processStartInfo), TimeSpan.FromMilliseconds(CliProcessTimeoutMs), cancellationToken); string output; try { output = async ? await processRunner.RunAsync().ConfigureAwait(false) : processRunner.Run(); } catch (OperationCanceledException) when(!cancellationToken.IsCancellationRequested) { throw new AuthenticationFailedException(AzureCliTimeoutError); } catch (InvalidOperationException exception) { bool isWinError = exception.Message.StartsWith(WinAzureCLIError, StringComparison.CurrentCultureIgnoreCase); bool isOtherOsError = AzNotFoundPattern.IsMatch(exception.Message); if (isWinError || isOtherOsError) { throw new CredentialUnavailableException(AzureCLINotInstalled); } bool isLoginError = exception.Message.IndexOf("az login", StringComparison.OrdinalIgnoreCase) != -1 || exception.Message.IndexOf("az account set", StringComparison.OrdinalIgnoreCase) != -1; if (isLoginError) { throw new CredentialUnavailableException(AzNotLogIn); } bool isRefreshTokenFailedError = exception.Message.IndexOf(AzureCliFailedError, StringComparison.OrdinalIgnoreCase) != -1 && exception.Message.IndexOf(RefreshTokeExpired, StringComparison.OrdinalIgnoreCase) != -1 || exception.Message.IndexOf("CLIInternalError", StringComparison.OrdinalIgnoreCase) != -1; if (isRefreshTokenFailedError) { throw new CredentialUnavailableException(InteractiveLoginRequired); } throw new AuthenticationFailedException($"{AzureCliFailedError} {exception.Message}"); } return(DeserializeOutput(output)); }
private async ValueTask <AccessToken> RequestAzurePowerShellAccessTokenAsync(bool async, TokenRequestContext context, CancellationToken cancellationToken) { string resource = ScopeUtilities.ScopesToResource(context.Scopes); ScopeUtilities.ValidateScope(resource); var tenantId = TenantIdResolver.Resolve(_tenantId, context, _allowMultiTenantAuthentication); GetFileNameAndArguments(resource, tenantId, out string fileName, out string argument); ProcessStartInfo processStartInfo = GetAzurePowerShellProcessStartInfo(fileName, argument); using var processRunner = new ProcessRunner( _processService.Create(processStartInfo), TimeSpan.FromMilliseconds(PowerShellProcessTimeoutMs), _logPII, cancellationToken); string output; try { output = async ? await processRunner.RunAsync().ConfigureAwait(false) : processRunner.Run(); CheckForErrors(output); } catch (OperationCanceledException) when(!cancellationToken.IsCancellationRequested) { throw new AuthenticationFailedException(AzurePowerShellTimeoutError); } catch (InvalidOperationException exception) { bool noPowerShell = exception.Message.IndexOf("not found", StringComparison.OrdinalIgnoreCase) != -1 || exception.Message.IndexOf("is not recognized", StringComparison.OrdinalIgnoreCase) != -1; if (noPowerShell) { throw new CredentialUnavailableException(PowerShellNotInstalledError); } bool noLogin = exception.Message.IndexOf("Run Connect-AzAccount to login", StringComparison.OrdinalIgnoreCase) != -1; if (noLogin) { throw new CredentialUnavailableException(AzurePowerShellNotLogInError); } throw new AuthenticationFailedException($"{AzurePowerShellFailedError} {exception.Message}"); } return(DeserializeOutput(output)); }
private async Task <AccessToken> RunProcessesAsync(List <ProcessStartInfo> processStartInfos, bool async, CancellationToken cancellationToken) { var exceptions = new List <Exception>(); foreach (ProcessStartInfo processStartInfo in processStartInfos) { string output = string.Empty; try { var processRunner = new ProcessRunner(_processService.Create(processStartInfo), TimeSpan.FromSeconds(30), cancellationToken); output = async ? await processRunner.RunAsync().ConfigureAwait(false) : processRunner.Run(); JsonElement root = JsonDocument.Parse(output).RootElement; string accessToken = root.GetProperty("access_token").GetString(); DateTimeOffset expiresOn = root.GetProperty("expires_on").GetDateTimeOffset(); return(new AccessToken(accessToken, expiresOn)); } catch (OperationCanceledException) when(!cancellationToken.IsCancellationRequested) { exceptions.Add(new CredentialUnavailableException($"Process \"{processStartInfo.FileName}\" has failed to get access token in 30 seconds.")); } catch (JsonException exception) { exceptions.Add(new CredentialUnavailableException($"Process \"{processStartInfo.FileName}\" has non-json output: {output}.", exception)); } catch (Exception exception) { exceptions.Add(exception); } } switch (exceptions.Count) { case 0: throw new CredentialUnavailableException("No installed instance of Visual Studio was able to get credentials."); case 1: ExceptionDispatchInfo.Capture(exceptions[0]).Throw(); return(default); default: throw new AggregateException(exceptions); } }
private async ValueTask <AccessToken> RequestAzurePowerShellAccessTokenAsync(bool async, TokenRequestContext context, CancellationToken cancellationToken) { string resource = ScopeUtilities.ScopesToResource(context.Scopes); ScopeUtilities.ValidateScope(resource); var tenantId = TenantIdResolver.Resolve(_tenantId, context); GetFileNameAndArguments(resource, tenantId, out string fileName, out string argument); ProcessStartInfo processStartInfo = GetAzurePowerShellProcessStartInfo(fileName, argument); using var processRunner = new ProcessRunner( _processService.Create(processStartInfo), TimeSpan.FromMilliseconds(PowerShellProcessTimeoutMs), _logPII, cancellationToken); string output; try { output = async ? await processRunner.RunAsync().ConfigureAwait(false) : processRunner.Run(); CheckForErrors(output); ValidateResult(output); } catch (OperationCanceledException) when(!cancellationToken.IsCancellationRequested) { throw new AuthenticationFailedException(AzurePowerShellTimeoutError); } catch (InvalidOperationException exception) { CheckForErrors(exception.Message); throw new AuthenticationFailedException($"{AzurePowerShellFailedError} {exception.Message}"); } return(DeserializeOutput(output)); }