public static Credential QueryCredentials(Program program, OperationArguments operationArguments) { if (program is null) { throw new ArgumentNullException(nameof(program)); } if (operationArguments is null) { throw new ArgumentNullException(nameof(operationArguments)); } if (operationArguments.TargetUri is null) { var innerException = new NullReferenceException($"{operationArguments.TargetUri} cannot be null."); throw new ArgumentException(innerException.Message, nameof(operationArguments), innerException); } var task = Task.Run(async() => { return(await program.CreateAuthentication(operationArguments)); }); BaseAuthentication authentication = task.Result; Credential credentials = null; switch (operationArguments.Authority) { default: case AuthorityType.Basic: { var basicAuth = authentication as BasicAuthentication; Task.Run(async() => { // Attempt to get cached credentials or acquire credentials if interactivity is allowed. if ((operationArguments.Interactivity != Interactivity.Always && (credentials = authentication.GetCredentials(operationArguments.TargetUri)) != null) || (operationArguments.Interactivity != Interactivity.Never && (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null)) { Git.Trace.WriteLine("credentials found."); // No need to save the credentials explicitly, as Git will call back // with a store command if the credentials are valid. } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.AzureDirectory: { var aadAuth = authentication as VstsAadAuthentication; var patOptions = new PersonalAccessTokenOptions() { RequireCompactToken = true, TokenDuration = operationArguments.TokenDuration, TokenScope = null, }; Task.Run(async() => { // Attempt to get cached credentials -> non-interactive logon -> interactive // logon note that AAD "credentials" are always scoped access tokens. if (((operationArguments.Interactivity != Interactivity.Always && ((credentials = aadAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) || (operationArguments.Interactivity != Interactivity.Always && ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, patOptions)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); program.LogEvent($"Azure Directory credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.MicrosoftAccount: { var msaAuth = authentication as VstsMsaAuthentication; var patOptions = new PersonalAccessTokenOptions() { RequireCompactToken = true, TokenDuration = operationArguments.TokenDuration, TokenScope = null, }; Task.Run(async() => { // Attempt to get cached credentials -> interactive logon note that MSA // "credentials" are always scoped access tokens. if (((operationArguments.Interactivity != Interactivity.Always && ((credentials = msaAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null) && (!operationArguments.ValidateCredentials || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); program.LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.GitHub: { var ghAuth = authentication as Github.Authentication; Task.Run(async() => { if ((operationArguments.Interactivity != Interactivity.Always && ((credentials = ghAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); program.LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); program.LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.Bitbucket: { var bbcAuth = authentication as Bitbucket.Authentication; Task.Run(async() => { if (((operationArguments.Interactivity != Interactivity.Always) && ((credentials = bbcAuth.GetCredentials(operationArguments.TargetUri, operationArguments.CredUsername)) != null) && (!operationArguments.ValidateCredentials || ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.CredUsername, credentials)) != null))) || ((operationArguments.Interactivity != Interactivity.Never) && ((credentials = await bbcAuth.InteractiveLogon(operationArguments.TargetUri, operationArguments.CredUsername)) != null) && (!operationArguments.ValidateCredentials || ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.CredUsername, credentials)) != null)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); // Bitbucket relies on a username + secret, so make sure there is a // username to return. if (operationArguments.CredUsername != null) { credentials = new Credential(operationArguments.CredUsername, credentials.Password); } program.LogEvent($"Bitbucket credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { program.LogEvent($"Failed to retrieve Bitbucket credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.Ntlm: { Git.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM."); credentials = BasicAuthentication.NtlmCredentials; } break; } if (credentials != null) { operationArguments.SetCredentials(credentials); } return(credentials); }
internal void Askpass(string[] args) { if (args == null || args.Length == 0) { throw new ArgumentException("Arguments cannot be empty."); } Gui.UserPromptKind promptKind = Gui.UserPromptKind.SshPassphrase; Match match; if ((match = AskPasswordRegex.Match(args[0])).Success) { promptKind = Gui.UserPromptKind.CredentialsPassword; } else if ((match = AskPassphraseRegex.Match(args[0])).Success) { promptKind = Gui.UserPromptKind.SshPassphrase; } if (match.Success) { _context.Trace.WriteLine("querying for passphrase key."); if (match.Groups.Count < 2) { throw new ArgumentException("Unable to understand command."); } // string request = match.Groups[0].Value; string resource = match.Groups[1].Value; _context.Trace.WriteLine($"open dialog for '{resource}'."); System.Windows.Application application = new System.Windows.Application(); Gui.UserPromptDialog prompt = new Gui.UserPromptDialog(promptKind, resource); application.Run(prompt); if (!prompt.Failed && !string.IsNullOrEmpty(prompt.Response)) { string passphase = prompt.Response; _context.Trace.WriteLine("passphase acquired."); Out.Write(passphase + "\n"); return; } Die("failed to interactively acquire credentials."); } if ((match = AskCredentialRegex.Match(args[0])).Success) { _context.Trace.WriteLine("querying for basic credentials."); if (match.Groups.Count < 3) { throw new ArgumentException("Unable to understand command."); } string seeking = match.Groups[1].Value; string targetUrl = match.Groups[2].Value; string username = string.Empty; string password = string.Empty; Uri targetUri = null; // Since we're looking for HTTP(s) credentials, we can use NetFx `Uri` class. if (Uri.TryCreate(targetUrl, UriKind.Absolute, out targetUri)) { _context.Trace.WriteLine($"success parsing URL, targetUri = '{targetUri}'."); if (TryParseUrlCredentials(targetUrl, out username, out password)) { if (password != null && seeking.Equals("Password", StringComparison.OrdinalIgnoreCase)) { Out.Write(password + '\n'); return; } // print the username if it sought if (seeking.Equals("Username", StringComparison.OrdinalIgnoreCase)) { Out.Write(username + '\n'); return; } } // create a target Url with the credential portion stripped, because Git doesn't // report hosts with credentials targetUrl = targetUri.Scheme + "://"; // Add the username@ portion of the url if it exists if (username != null) { targetUrl += Uri.EscapeDataString(username); targetUrl += '@'; } targetUrl += targetUri.Host; // retain the port if specified if (!targetUri.IsDefaultPort) { targetUrl += $":{targetUri.Port}"; } // retain the path if specified if (!string.IsNullOrWhiteSpace(targetUri.LocalPath)) { targetUrl += targetUri.LocalPath; } if (Uri.TryCreate(targetUrl, UriKind.Absolute, out targetUri)) { _context.Trace.WriteLine($"success parsing URL, targetUri = '{targetUri}'."); OperationArguments operationArguments = new OperationArguments(_context, targetUri); operationArguments.SetCredentials(username ?? string.Empty, password ?? string.Empty); // Load up the operation arguments, enable tracing, and query for credentials. Task.Run(async() => { await LoadOperationArguments(operationArguments); EnableTraceLogging(operationArguments); Credential credentials; if ((credentials = await QueryCredentials(operationArguments)) != null) { if (seeking.Equals("Username", StringComparison.OrdinalIgnoreCase)) { _context.Trace.WriteLine($"username for '{targetUrl}' asked for and found."); Out.Write(credentials.Username + '\n'); return; } if (seeking.Equals("Password", StringComparison.OrdinalIgnoreCase)) { _context.Trace.WriteLine($"password for '{targetUrl}' asked for and found."); Out.Write(credentials.Password + '\n'); return; } } else { _context.Trace.WriteLine($"user cancelled credential dialog."); return; } }).Wait(); } else { _context.Trace.WriteLine("error: unable to parse target URL."); } } else { _context.Trace.WriteLine("error: unable to parse supplied URL."); } Die($"failed to detect {seeking} in target URL."); } if ((match = AskAuthenticityRegex.Match(args[0])).Success) { string host = match.Groups[1].Value; string fingerprint = match.Groups[2].Value; _context.Trace.WriteLine($"requesting authorization to add {host} ({fingerprint}) to known hosts."); System.Windows.Application application = new System.Windows.Application(); Gui.UserPromptDialog prompt = new Gui.UserPromptDialog(host, fingerprint); application.Run(prompt); if (prompt.Failed) { _context.Trace.WriteLine("denied authorization of host."); Out.Write("no\n"); } else { _context.Trace.WriteLine("approved authorization of host."); Out.Write("yes\n"); } return; } Die("failed to acquire credentials."); }
private static bool QueryCredentials(OperationArguments operationArguments) { const string AadMsaAuthFailureMessage = "Logon failed, use ctrl+c to cancel basic credential prompt."; const string BasicAuthFaulureMessage = "Logon failed, use ctrl+c to cancel basic credential prompt."; const string GitHubAuthFailureMessage = "Logon failed, use ctrl+c to cancel basic credential prompt."; if (ReferenceEquals(operationArguments, null)) throw new ArgumentNullException("operationArguments"); if (ReferenceEquals(operationArguments.TargetUri, null)) throw new ArgumentNullException("operationArguments.TargetUri"); bool credentialsFound = false; BaseAuthentication authentication = CreateAuthentication(operationArguments); Credential credentials = null; switch (operationArguments.Authority) { default: case AuthorityType.Basic: { BasicAuthentication basicAuth = authentication as BasicAuthentication; Task.Run(async () => { // attempt to get cached creds or acquire creds if interactivity is allowed if ((operationArguments.Interactivity != Interactivity.Always && (credentials = authentication.GetCredentials(operationArguments.TargetUri)) != null) || (operationArguments.Interactivity != Interactivity.Never && (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null)) { Git.Trace.WriteLine("credentials found."); // set the credentials object // no need to save the credentials explicitly, as Git will call back // with a store command if the credentials are valid. operationArguments.SetCredentials(credentials); credentialsFound = true; } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); Program.WriteLine(BasicAuthFaulureMessage); LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.AzureDirectory: { VstsAadAuthentication aadAuth = authentication as VstsAadAuthentication; Task.Run(async () => { // attempt to get cached creds -> non-interactive logon -> interactive logon // note that AAD "credentials" are always scoped access tokens if (((operationArguments.Interactivity != Interactivity.Always && ((credentials = aadAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) || (operationArguments.Interactivity != Interactivity.Always && ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, true)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, true)) != null) && (!operationArguments.ValidateCredentials || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); operationArguments.SetCredentials(credentials); credentialsFound = true; LogEvent($"Azure Directory credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); Program.WriteLine(AadMsaAuthFailureMessage); LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.MicrosoftAccount: { VstsMsaAuthentication msaAuth = authentication as VstsMsaAuthentication; Task.Run(async () => { // attempt to get cached creds -> interactive logon // note that MSA "credentials" are always scoped access tokens if (((operationArguments.Interactivity != Interactivity.Always && ((credentials = msaAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, true)) != null) && (!operationArguments.ValidateCredentials || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); operationArguments.SetCredentials(credentials); credentialsFound = true; LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); Program.WriteLine(AadMsaAuthFailureMessage); LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.GitHub: { GitHubAuthentication ghAuth = authentication as GitHubAuthentication; Task.Run(async () => { if ((operationArguments.Interactivity != Interactivity.Always && ((credentials = ghAuth.GetCredentials(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) || (operationArguments.Interactivity != Interactivity.Never && ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null) && (!operationArguments.ValidateCredentials || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found."); operationArguments.SetCredentials(credentials); credentialsFound = true; LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit); } else { Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found."); Program.WriteLine(GitHubAuthFailureMessage); LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit); } }).Wait(); } break; case AuthorityType.Ntlm: { Git.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM."); operationArguments.SetCredentials(BasicAuthentication.NtlmCredentials); credentialsFound = true; } break; } return credentialsFound; }