/// <summary> /// Call the plugin credential provider application to acquire credentials. /// The request will be passed to the plugin on standard input as a json serialized /// PluginCredentialRequest. /// The plugin will return credentials as a json serialized PluginCredentialResponse. /// Valid credentials will be returned, or null if the provide cannot provide credentials /// for the given request. If the plugin returns an Abort message, an exception will be thrown to /// fail the current request. /// </summary> /// <param name="uri">The uri of a web resource for which credentials are needed.</param> /// <param name="proxy">Ignored. Proxy information will not be passed to plugins.</param> /// <param name="type"> /// The type of credential request that is being made. Note that this implementation of /// <see cref="ICredentialProvider"/> does not support providing proxy credenitials and treats /// all other types the same. /// </param> /// <param name="isRetry">If true, credentials were previously supplied by this /// provider for the same uri.</param> /// <param name="message">A message provided by NuGet to show to the user when prompting.</param> /// <param name="nonInteractive">If true, the plugin must not prompt for credentials.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>A credential object. If </returns> public Task <CredentialResponse> GetAsync( Uri uri, IWebProxy proxy, CredentialRequestType type, string message, bool isRetry, bool nonInteractive, CancellationToken cancellationToken) { CredentialResponse taskResponse; if (type == CredentialRequestType.Proxy) { taskResponse = new CredentialResponse(CredentialStatus.ProviderNotApplicable); return(Task.FromResult(taskResponse)); } try { var request = new PluginCredentialRequest { Uri = uri.ToString(), IsRetry = isRetry, NonInteractive = nonInteractive }; // TODO: Extend the plug protocol to pass in the credential request type. var response = Execute(request, cancellationToken); if (response.IsValid) { ICredentials result = new NetworkCredential(response.Username, response.Password); if (response.AuthTypes != null) { result = new AuthTypeFilteredCredentials(result, response.AuthTypes); } taskResponse = new CredentialResponse(result); } else { taskResponse = new CredentialResponse(CredentialStatus.ProviderNotApplicable); } } catch (OperationCanceledException) { throw; } catch (PluginException) { throw; } catch (Exception e) { throw PluginException.Create(Path, e); } return(Task.FromResult(taskResponse)); }
public virtual int Execute(ProcessStartInfo startInfo, CancellationToken cancellationToken, out string stdOut) { var outBuffer = new StringBuilder(); cancellationToken.ThrowIfCancellationRequested(); var process = Process.Start(startInfo); if (process == null) { throw PluginException.CreateNotStartedMessage(Path); } process.OutputDataReceived += (object o, DataReceivedEventArgs e) => { outBuffer.AppendLine(e.Data); }; // Trace and error information may be written to standard error by the provider. // It should be logged at the Information level so it will appear if Verbosity >= Normal. process.ErrorDataReceived += (object o, DataReceivedEventArgs e) => { if (!string.IsNullOrWhiteSpace(e?.Data)) { // This is a workaround for mono issue: https://github.com/NuGet/Home/issues/4004 if (!process.HasExited) { _logger.LogInformation($"{process.ProcessName}: {e.Data}"); } } }; process.BeginOutputReadLine(); process.BeginErrorReadLine(); using (cancellationToken.Register(() => Kill(process))) { if (!process.WaitForExit(TimeoutSeconds * 1000)) { Kill(process); throw PluginException.CreateTimeoutMessage(Path, TimeoutSeconds); } // Give time for the Async event handlers to finish by calling WaitForExit again. // if the first one succeeded // Note: Read remarks from https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx // for reason. process.WaitForExit(); } process.CancelErrorRead(); process.CancelOutputRead(); cancellationToken.ThrowIfCancellationRequested(); stdOut = outBuffer.ToString(); return(process.ExitCode); }
public virtual PluginCredentialResponse Execute(PluginCredentialRequest request, CancellationToken cancellationToken) { var stdOut = new StringBuilder(); var stdError = new StringBuilder(); var argumentString = $"-uri {request.Uri}" + (request.IsRetry ? " -isRetry" : string.Empty) + (request.NonInteractive ? " -nonInteractive" : string.Empty); var startInfo = new ProcessStartInfo { FileName = Path, Arguments = argumentString, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8, ErrorDialog = false }; cancellationToken.ThrowIfCancellationRequested(); var process = Process.Start(startInfo); if (process == null) { throw PluginException.CreateNotStartedMessage(Path); } process.OutputDataReceived += (object o, DataReceivedEventArgs e) => { stdOut.AppendLine(e.Data); }; process.ErrorDataReceived += (object o, DataReceivedEventArgs e) => { stdError.AppendLine(e.Data); }; process.BeginOutputReadLine(); process.BeginErrorReadLine(); using (cancellationToken.Register(() => Kill(process))) { if (!process.WaitForExit(TimeoutSeconds * 1000)) { Kill(process); throw PluginException.CreateTimeoutMessage(Path, TimeoutSeconds); } // Give time for the Async event handlers to finish by calling WaitForExit again. // if the first one succeeded // Note: Read remarks from https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx // for reason. process.WaitForExit(); } process.CancelErrorRead(); process.CancelOutputRead(); var exitCode = process.ExitCode; if (Enum.GetValues(typeof(PluginCredentialResponseExitCode)).Cast <int>().Contains(exitCode)) { var status = (PluginCredentialResponseExitCode)exitCode; var responseJson = stdOut.ToString(); PluginCredentialResponse credentialResponse; try { credentialResponse = JsonConvert.DeserializeObject <PluginCredentialResponse>(responseJson); } catch (Exception) { throw PluginException.CreatePayloadExceptionMessage(Path, status, responseJson); } switch (status) { case PluginCredentialResponseExitCode.Success: if (!credentialResponse.IsValid) { throw PluginException.CreatePayloadExceptionMessage(Path, status, responseJson); } return(credentialResponse); case PluginCredentialResponseExitCode.ProviderNotApplicable: credentialResponse.Username = null; credentialResponse.Password = null; return(credentialResponse); case PluginCredentialResponseExitCode.Failure: throw PluginException.CreateAbortMessage(Path, credentialResponse.Message); } } throw PluginException.CreateWrappedExceptionMessage( Path, exitCode, stdOut.ToString(), stdError.ToString()); }
/// <summary> /// Call the plugin credential provider application to acquire credentials. /// The request will be passed to the plugin on standard input as a json serialized /// PluginCredentialRequest. /// The plugin will return credentials as a json serialized PluginCredentialResponse. /// Valid credentials will be returned, or null if the provide cannot provide credentials /// for the given request. If the plugin returns an Abort message, an exception will be thrown to /// fail the current request. /// </summary> /// <param name="uri">The uri of a web resource for which credentials are needed.</param> /// <param name="proxy">Ignored. Proxy information will not be passed to plugins.</param> /// <param name="type"> /// The type of credential request that is being made. Note that this implementation of /// <see cref="ICredentialProvider"/> does not support providing proxy credenitials and treats /// all other types the same. /// </param> /// <param name="isRetry">If true, credentials were previously supplied by this /// provider for the same uri.</param> /// <param name="message">A message provided by NuGet to show to the user when prompting.</param> /// <param name="nonInteractive">If true, the plugin must not prompt for credentials.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>A credential object.</returns> public Task <CredentialResponse> GetAsync( Uri uri, IWebProxy proxy, CredentialRequestType type, string message, bool isRetry, bool nonInteractive, CancellationToken cancellationToken) { CredentialResponse taskResponse; if (type == CredentialRequestType.Proxy) { taskResponse = new CredentialResponse(CredentialStatus.ProviderNotApplicable); return(Task.FromResult(taskResponse)); } try { var request = new PluginCredentialRequest { Uri = uri.AbsoluteUri, IsRetry = isRetry, NonInteractive = nonInteractive, Verbosity = _verbosity }; PluginCredentialResponse response; if (Interlocked.CompareExchange(ref _deprecationMessageWarningLogged, 1, 0) == 0) { _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Resources.PluginWarning_PluginIsBeingDeprecated, Path, CrossPlatformPluginLink)); } try { response = GetPluginResponse(request, cancellationToken); } catch (PluginUnexpectedStatusException) when(PassVerbosityFlag(request)) { // older providers may throw if the verbosity flag is sent, // so retry without it request.Verbosity = null; response = GetPluginResponse(request, cancellationToken); } if (response.IsValid) { var result = new AuthTypeFilteredCredentials( new NetworkCredential(response.Username, response.Password), response.AuthTypes ?? Enumerable.Empty <string>()); taskResponse = new CredentialResponse(result); } else { taskResponse = new CredentialResponse(CredentialStatus.ProviderNotApplicable); } } catch (OperationCanceledException) { throw; } catch (PluginException) { throw; } catch (Exception e) { throw PluginException.Create(Path, e); } return(Task.FromResult(taskResponse)); }
private PluginCredentialResponse GetPluginResponse(PluginCredentialRequest request, CancellationToken cancellationToken) { var argumentString = $"-uri {request.Uri}" + (request.IsRetry ? " -isRetry" : string.Empty) + (request.NonInteractive ? " -nonInteractive" : string.Empty); // only apply -verbosity flag if set and != Normal // since normal is default if (PassVerbosityFlag(request)) { argumentString += $" -verbosity {request.Verbosity.ToLower()}"; } var startInfo = new ProcessStartInfo { FileName = Path, Arguments = argumentString, #if IS_DESKTOP WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false, #endif UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8, }; string stdOut = null; var exitCode = Execute(startInfo, cancellationToken, out stdOut); var status = (PluginCredentialResponseExitCode)exitCode; PluginCredentialResponse credentialResponse; try { // Mono will add utf-16 byte order mark to the start of stdOut, remove it here. credentialResponse = JsonConvert.DeserializeObject <PluginCredentialResponse>(stdOut.Trim(new char[] { '\uFEFF' })) ?? new PluginCredentialResponse(); } catch (Exception) { // Do not expose stdout message, since it may contain credentials throw PluginException.CreateUnreadableResponseExceptionMessage(Path, status); } switch (status) { case PluginCredentialResponseExitCode.Success: if (!credentialResponse.IsValid) { throw PluginException.CreateInvalidResponseExceptionMessage( Path, status, credentialResponse); } return(credentialResponse); case PluginCredentialResponseExitCode.ProviderNotApplicable: credentialResponse.Username = null; credentialResponse.Password = null; return(credentialResponse); case PluginCredentialResponseExitCode.Failure: throw PluginException.CreateAbortMessage(Path, credentialResponse.Message); default: throw PluginUnexpectedStatusException.CreateUnexpectedStatusMessage(Path, status); } }
/// <summary> /// Call the plugin credential provider application to acquire credentials. /// The request will be passed to the plugin on standard input as a json serialized /// PluginCredentialRequest. /// The plugin will return credentials as a json serialized PluginCredentialResponse. /// Valid credentials will be returned, or null if the provide cannot provide credentials /// for the given request. If the plugin returns an Abort message, an exception will be thrown to /// fail the current request. /// </summary> /// <param name="uri">The uri of a web resource for which credentials are needed.</param> /// <param name="proxy">Ignored. Proxy information will not be passed to plugins.</param> /// <param name="type"> /// The type of credential request that is being made. Note that this implementation of /// <see cref="ICredentialProvider"/> does not support providing proxy credenitials and treats /// all other types the same. /// </param> /// <param name="isRetry">If true, credentials were previously supplied by this /// provider for the same uri.</param> /// <param name="message">A message provided by NuGet to show to the user when prompting.</param> /// <param name="nonInteractive">If true, the plugin must not prompt for credentials.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>A credential object. If </returns> public Task <CredentialResponse> GetAsync( Uri uri, IWebProxy proxy, CredentialRequestType type, string message, bool isRetry, bool nonInteractive, CancellationToken cancellationToken) { CredentialResponse taskResponse; if (type == CredentialRequestType.Proxy) { taskResponse = new CredentialResponse(CredentialStatus.ProviderNotApplicable); return(Task.FromResult(taskResponse)); } try { var request = new PluginCredentialRequest { Uri = uri.AbsoluteUri, IsRetry = isRetry, NonInteractive = nonInteractive, Verbosity = _verbosity }; PluginCredentialResponse response; // TODO: Extend the plug protocol to pass in the credential request type. try { response = GetPluginResponse(request, cancellationToken); } catch (PluginUnexpectedStatusException) when(PassVerbosityFlag(request)) { // older providers may throw if the verbosity flag is sent, // so retry without it request.Verbosity = null; response = GetPluginResponse(request, cancellationToken); } if (response.IsValid) { ICredentials result = new NetworkCredential(response.Username, response.Password); if (response.AuthTypes != null) { result = new AuthTypeFilteredCredentials(result, response.AuthTypes); } taskResponse = new CredentialResponse(result); } else { taskResponse = new CredentialResponse(CredentialStatus.ProviderNotApplicable); } } catch (OperationCanceledException) { throw; } catch (PluginException) { throw; } catch (Exception e) { throw PluginException.Create(Path, e); } return(Task.FromResult(taskResponse)); }