Esempio n. 1
0
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, string userName, AuthenticationModes modes)
        {
            // If we don't have a desktop session/GUI then we cannot offer browser
            if (!Context.SessionManager.IsDesktopSession)
            {
                modes = modes & ~AuthenticationModes.Browser;
            }

            // We need at least one mode!
            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException(@$ "Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (Context.Settings.IsGuiPromptsEnabled && Context.SessionManager.IsDesktopSession &&
                TryFindHelperExecutablePath(out string helperPath))
            {
                var cmdArgs = new StringBuilder("prompt");
                if (!string.IsNullOrWhiteSpace(userName))
                {
                    cmdArgs.AppendFormat(" --username {0}", QuoteCmdArg(userName));
                }

                cmdArgs.AppendFormat(" --url {0}", QuoteCmdArg(targetUri.ToString()));

                if ((modes & AuthenticationModes.Basic) != 0)
                {
                    cmdArgs.Append(" --basic");
                }
                if ((modes & AuthenticationModes.Browser) != 0)
                {
                    cmdArgs.Append(" --browser");
                }
                if ((modes & AuthenticationModes.Pat) != 0)
                {
                    cmdArgs.Append(" --pat");
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, cmdArgs.ToString());

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "pat":
                    if (!resultDict.TryGetValue("pat", out string pat))
                    {
                        throw new Exception("Missing 'pat' in response");
                    }

                    if (!resultDict.TryGetValue("username", out string patUserName))
                    {
                        // Username is optional for PATs
                    }

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Pat, new GitCredential(patUserName, pat)));

                case "browser":
                    return(new AuthenticationPromptResult(AuthenticationModes.Browser));

                case "basic":
                    if (!resultDict.TryGetValue("username", out userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Basic, new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                switch (modes)
                {
                case AuthenticationModes.Basic:
                    ThrowIfUserInteractionDisabled();
                    ThrowIfTerminalPromptsDisabled();
                    Context.Terminal.WriteLine("Enter GitLab credentials for '{0}'...", targetUri);

                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        userName = Context.Terminal.Prompt("Username");
                    }
                    else
                    {
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }

                    string password = Context.Terminal.PromptSecret("Password");
                    return(new AuthenticationPromptResult(AuthenticationModes.Basic, new GitCredential(userName, password)));

                case AuthenticationModes.Pat:
                    ThrowIfUserInteractionDisabled();
                    ThrowIfTerminalPromptsDisabled();
                    Context.Terminal.WriteLine("Enter GitLab credentials for '{0}'...", targetUri);

                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        userName = Context.Terminal.Prompt("Username");
                    }
                    else
                    {
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }

                    string token = Context.Terminal.PromptSecret("Personal access token");
                    return(new AuthenticationPromptResult(AuthenticationModes.Pat, new GitCredential(userName, token)));

                case AuthenticationModes.Browser:
                    return(new AuthenticationPromptResult(AuthenticationModes.Browser));

                case AuthenticationModes.None:
                    throw new ArgumentOutOfRangeException(nameof(modes), @$ "At least one {nameof(AuthenticationModes)} must be supplied");

                default:
                    ThrowIfUserInteractionDisabled();
                    ThrowIfTerminalPromptsDisabled();
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle);

                    TerminalMenuItem browserItem = null;
                    TerminalMenuItem basicItem   = null;
                    TerminalMenuItem patItem     = null;

                    if ((modes & AuthenticationModes.Browser) != 0)
                    {
                        browserItem = menu.Add("Web browser");
                    }
                    if ((modes & AuthenticationModes.Pat) != 0)
                    {
                        patItem = menu.Add("Personal access token");
                    }
                    if ((modes & AuthenticationModes.Basic) != 0)
                    {
                        basicItem = menu.Add("Username/password");
                    }

                    // Default to the 'first' choice in the menu
                    TerminalMenuItem choice = menu.Show(0);

                    if (choice == browserItem)
                    {
                        goto case AuthenticationModes.Browser;
                    }
                    if (choice == basicItem)
                    {
                        goto case AuthenticationModes.Basic;
                    }
                    if (choice == patItem)
                    {
                        goto case AuthenticationModes.Pat;
                    }

                    throw new Exception();
                }
            }
        }
Esempio n. 2
0
        public async Task <CredentialsPromptResult> GetCredentialsAsync(Uri targetUri, string userName, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            string password;

            // If we don't have a desktop session/GUI then we cannot offer OAuth since the only
            // supported grant is authcode (i.e, using a web browser; device code is not supported).
            if (!Context.SessionManager.IsDesktopSession)
            {
                modes = modes & ~AuthenticationModes.OAuth;
            }

            // If the only supported mode is OAuth then just return immediately
            if (modes == AuthenticationModes.OAuth)
            {
                return(new CredentialsPromptResult(AuthenticationModes.OAuth));
            }

            // We need at least one mode!
            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException(@$ "Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            // Shell out to the UI helper and show the Bitbucket u/p prompt
            if (Context.Settings.IsGuiPromptsEnabled && Context.SessionManager.IsDesktopSession &&
                TryFindHelperExecutablePath(out string helperPath))
            {
                var cmdArgs = new StringBuilder("userpass");
                if (!string.IsNullOrWhiteSpace(userName))
                {
                    cmdArgs.AppendFormat(" --username {0}", QuoteCmdArg(userName));
                }

                if ((modes & AuthenticationModes.OAuth) != 0)
                {
                    cmdArgs.Append(" --show-oauth");
                }

                IDictionary <string, string> output = await InvokeHelperAsync(helperPath, cmdArgs.ToString());

                if (output.TryGetValue("mode", out string mode) &&
                    StringComparer.OrdinalIgnoreCase.Equals(mode, "oauth"))
                {
                    return(new CredentialsPromptResult(AuthenticationModes.OAuth));
                }
                else
                {
                    if (!output.TryGetValue("username", out userName))
                    {
                        throw new Exception("Missing username in response");
                    }

                    if (!output.TryGetValue("password", out password))
                    {
                        throw new Exception("Missing password in response");
                    }

                    return(new CredentialsPromptResult(
                               AuthenticationModes.Basic,
                               new GitCredential(userName, password)));
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter Bitbucket credentials for '{0}'...", targetUri);

                    if (!string.IsNullOrWhiteSpace(userName))
                    {
                        // Don't need to prompt for the username if it has been specified already
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }
                    else
                    {
                        // Prompt for username
                        userName = Context.Terminal.Prompt("Username");
                    }

                    // Prompt for password
                    password = Context.Terminal.PromptSecret("Password");

                    return(new CredentialsPromptResult(
                               AuthenticationModes.Basic,
                               new GitCredential(userName, password)));

                case AuthenticationModes.OAuth:
                    return(new CredentialsPromptResult(AuthenticationModes.OAuth));

                case AuthenticationModes.None:
                    throw new ArgumentOutOfRangeException(nameof(modes), @$ "At least one {nameof(AuthenticationModes)} must be supplied");

                default:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle);

                    TerminalMenuItem oauthItem = null;
                    TerminalMenuItem basicItem = null;

                    if ((modes & AuthenticationModes.OAuth) != 0)
                    {
                        oauthItem = menu.Add("OAuth");
                    }
                    if ((modes & AuthenticationModes.Basic) != 0)
                    {
                        basicItem = menu.Add("Username/password");
                    }

                    // Default to the 'first' choice in the menu
                    TerminalMenuItem choice = menu.Show(0);

                    if (choice == oauthItem)
                    {
                        goto case AuthenticationModes.OAuth;
                    }
                    if (choice == basicItem)
                    {
                        goto case AuthenticationModes.Basic;
                    }

                    throw new Exception();
                }
            }
        }
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, string userName, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException($"Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (TryFindHelperExecutablePath(out string helperPath))
            {
                var promptArgs = new StringBuilder("prompt");
                if ((modes & AuthenticationModes.Basic) != 0)
                {
                    promptArgs.Append(" --basic");
                }
                if ((modes & AuthenticationModes.OAuth) != 0)
                {
                    promptArgs.Append(" --oauth");
                }
                if (!GitHubHostProvider.IsGitHubDotCom(targetUri))
                {
                    promptArgs.AppendFormat(" --enterprise-url {0}", targetUri);
                }
                if (!string.IsNullOrWhiteSpace(userName))
                {
                    promptArgs.AppendFormat("--username {0}", userName);
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, promptArgs.ToString(), null);

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "oauth":
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                case "basic":
                    if (!resultDict.TryGetValue("username", out userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic | AuthenticationModes.OAuth:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle)
                    {
                        new TerminalMenuItem(1, "Web browser", isDefault: true),
                        new TerminalMenuItem(2, "Username/password")
                    };

                    int option = menu.Show();

                    if (option == 1)
                    {
                        goto case AuthenticationModes.OAuth;
                    }
                    if (option == 2)
                    {
                        goto case AuthenticationModes.Basic;
                    }

                    throw new Exception();

                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter GitHub credentials for '{0}'...", targetUri);

                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        userName = Context.Terminal.Prompt("Username");
                    }
                    else
                    {
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }

                    string password = Context.Terminal.PromptSecret("Password");

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                case AuthenticationModes.OAuth:
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                default:
                    throw new ArgumentOutOfRangeException(nameof(modes), $"Unknown {nameof(AuthenticationModes)} value");
                }
            }
        }
Esempio n. 4
0
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            // If the GitHub auth stack doesn't support flows such as RFC 8628 and we do not have
            // an interactive desktop session, we cannot offer OAuth authentication.
            if ((modes & AuthenticationModes.OAuth) != 0 &&
                !Context.SessionManager.IsDesktopSession &&
                !GitHubConstants.IsOAuthDeviceAuthSupported)
            {
                Context.Trace.WriteLine("Ignoring OAuth authentication mode because we are not in an interactive desktop session. GitHub does not support RFC 8628.");

                modes &= ~AuthenticationModes.OAuth;
            }

            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException($"Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (TryFindHelperExecutablePath(out string helperPath))
            {
                var promptArgs = new StringBuilder("prompt");
                if ((modes & AuthenticationModes.Basic) != 0)
                {
                    promptArgs.Append(" --basic");
                }
                if ((modes & AuthenticationModes.OAuth) != 0)
                {
                    promptArgs.Append(" --oauth");
                }
                if (!GitHubHostProvider.IsGitHubDotCom(targetUri))
                {
                    promptArgs.AppendFormat(" --enterprise-url {0}", targetUri.ToString());
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, promptArgs.ToString(), null);

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "oauth":
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                case "basic":
                    if (!resultDict.TryGetValue("username", out string userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic | AuthenticationModes.OAuth:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle)
                    {
                        new TerminalMenuItem(1, "Web browser"),
                        new TerminalMenuItem(2, "Username/password", true)
                    };

                    int option = menu.Show();

                    if (option == 1)
                    {
                        goto case AuthenticationModes.OAuth;
                    }
                    if (option == 2)
                    {
                        goto case AuthenticationModes.Basic;
                    }

                    throw new Exception();

                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter GitHub credentials for '{0}'...", targetUri);
                    string userName = Context.Terminal.Prompt("Username");
                    string password = Context.Terminal.PromptSecret("Password");

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                case AuthenticationModes.OAuth:
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                default:
                    throw new ArgumentOutOfRangeException(nameof(modes), $"Unknown {nameof(AuthenticationModes)} value");
                }
            }
        }
Esempio n. 5
0
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, string userName, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException(@$ "Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (TryFindHelperExecutablePath(out string helperPath))
            {
                var promptArgs = new StringBuilder("prompt");
                if (modes == AuthenticationModes.All)
                {
                    promptArgs.Append(" --all");
                }
                else
                {
                    if ((modes & AuthenticationModes.Basic) != 0)
                    {
                        promptArgs.Append(" --basic");
                    }
                    if ((modes & AuthenticationModes.OAuth) != 0)
                    {
                        promptArgs.Append(" --oauth");
                    }
                    if ((modes & AuthenticationModes.Pat) != 0)
                    {
                        promptArgs.Append(" --pat");
                    }
                }
                if (!GitHubHostProvider.IsGitHubDotCom(targetUri))
                {
                    promptArgs.AppendFormat(" --enterprise-url {0}", QuoteCmdArg(targetUri.ToString()));
                }
                if (!string.IsNullOrWhiteSpace(userName))
                {
                    promptArgs.AppendFormat(" --username {0}", QuoteCmdArg(userName));
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, promptArgs.ToString(), null);

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "pat":
                    if (!resultDict.TryGetValue("pat", out string pat))
                    {
                        throw new Exception("Missing 'pat' in response");
                    }

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Pat, new GitCredential(userName, pat)));

                case "oauth":
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                case "basic":
                    if (!resultDict.TryGetValue("username", out userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Basic, new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter GitHub credentials for '{0}'...", targetUri);

                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        userName = Context.Terminal.Prompt("Username");
                    }
                    else
                    {
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }

                    string password = Context.Terminal.PromptSecret("Password");

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Basic, new GitCredential(userName, password)));

                case AuthenticationModes.OAuth:
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                case AuthenticationModes.Pat:
                    Context.Terminal.WriteLine("Enter GitHub personal access token for '{0}'...", targetUri);
                    string pat = Context.Terminal.PromptSecret("Token");
                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Pat, new GitCredential(userName, pat)));

                case AuthenticationModes.None:
                    throw new ArgumentOutOfRangeException(nameof(modes), @$ "At least one {nameof(AuthenticationModes)} must be supplied");

                default:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle);

                    TerminalMenuItem oauthItem = null;
                    TerminalMenuItem basicItem = null;
                    TerminalMenuItem patItem   = null;

                    if ((modes & AuthenticationModes.OAuth) != 0)
                    {
                        oauthItem = menu.Add("Web browser");
                    }
                    if ((modes & AuthenticationModes.Pat) != 0)
                    {
                        patItem = menu.Add("Personal access token");
                    }
                    if ((modes & AuthenticationModes.Basic) != 0)
                    {
                        basicItem = menu.Add("Username/password");
                    }

                    // Default to the 'first' choice in the menu
                    TerminalMenuItem choice = menu.Show(0);

                    if (choice == oauthItem)
                    {
                        goto case AuthenticationModes.OAuth;
                    }
                    if (choice == basicItem)
                    {
                        goto case AuthenticationModes.Basic;
                    }
                    if (choice == patItem)
                    {
                        goto case AuthenticationModes.Pat;
                    }

                    throw new Exception();
                }
            }
        }
        public AuthenticationPromptResult GetAuthentication(Uri targetUri, string userName, AuthenticationModes modes)
        {
            // If we don't have a desktop session/GUI then we cannot offer browser
            if (!Context.SessionManager.IsDesktopSession)
            {
                modes = modes & ~AuthenticationModes.Browser;
            }

            // We need at least one mode!
            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException(@$ "Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            switch (modes)
            {
            case AuthenticationModes.Basic:
                ThrowIfUserInteractionDisabled();
                ThrowIfTerminalPromptsDisabled();
                Context.Terminal.WriteLine("Enter GitLab credentials for '{0}'...", targetUri);

                if (string.IsNullOrWhiteSpace(userName))
                {
                    userName = Context.Terminal.Prompt("Username");
                }
                else
                {
                    Context.Terminal.WriteLine("Username: {0}", userName);
                }

                string password = Context.Terminal.PromptSecret("Password");
                return(new AuthenticationPromptResult(AuthenticationModes.Basic, new GitCredential(userName, password)));

            case AuthenticationModes.Pat:
                ThrowIfUserInteractionDisabled();
                ThrowIfTerminalPromptsDisabled();
                Context.Terminal.WriteLine("Enter GitLab credentials for '{0}'...", targetUri);

                if (string.IsNullOrWhiteSpace(userName))
                {
                    userName = Context.Terminal.Prompt("Username");
                }
                else
                {
                    Context.Terminal.WriteLine("Username: {0}", userName);
                }

                string token = Context.Terminal.PromptSecret("Personal access token");
                return(new AuthenticationPromptResult(AuthenticationModes.Pat, new GitCredential(userName, token)));

            case AuthenticationModes.Browser:
                return(new AuthenticationPromptResult(AuthenticationModes.Browser));

            case AuthenticationModes.None:
                throw new ArgumentOutOfRangeException(nameof(modes), @$ "At least one {nameof(AuthenticationModes)} must be supplied");

            default:
                ThrowIfUserInteractionDisabled();
                ThrowIfTerminalPromptsDisabled();
                var menuTitle = $"Select an authentication method for '{targetUri}'";
                var menu      = new TerminalMenu(Context.Terminal, menuTitle);

                TerminalMenuItem browserItem = null;
                TerminalMenuItem basicItem   = null;
                TerminalMenuItem patItem     = null;

                if ((modes & AuthenticationModes.Browser) != 0)
                {
                    browserItem = menu.Add("Web browser");
                }
                if ((modes & AuthenticationModes.Pat) != 0)
                {
                    patItem = menu.Add("Personal access token");
                }
                if ((modes & AuthenticationModes.Basic) != 0)
                {
                    basicItem = menu.Add("Username/password");
                }

                // Default to the 'first' choice in the menu
                TerminalMenuItem choice = menu.Show(0);

                if (choice == browserItem)
                {
                    goto case AuthenticationModes.Browser;
                }
                if (choice == basicItem)
                {
                    goto case AuthenticationModes.Basic;
                }
                if (choice == patItem)
                {
                    goto case AuthenticationModes.Pat;
                }

                throw new Exception();
            }
        }