public async Task GitHubHostProvider_GenerateCredentialAsync_Basic_2FARequired_ReturnsCredential()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "github.com",
            });

            var expectedTargetUri = new Uri("https://github.com/");
            var expectedUserName  = "******";
            var expectedPassword  = "******"; // [SuppressMessage("Microsoft.Security", "CS001:SecretInline", Justification="Fake credential")]
            var expectedAuthCode  = "123456";
            IEnumerable <string> expectedPatScopes = new[]
            {
                GitHubConstants.TokenScopes.Gist,
                GitHubConstants.TokenScopes.Repo,
            };

            var patValue  = "PERSONAL-ACCESS-TOKEN";
            var response1 = new AuthenticationResult(GitHubAuthenticationResultType.TwoFactorApp);
            var response2 = new AuthenticationResult(GitHubAuthenticationResultType.Success, patValue);

            var context = new TestCommandContext();

            var ghAuthMock = new Mock <IGitHubAuthentication>(MockBehavior.Strict);

            ghAuthMock.Setup(x => x.GetAuthenticationAsync(expectedTargetUri, null, It.IsAny <AuthenticationModes>()))
            .ReturnsAsync(new AuthenticationPromptResult(new GitCredential(expectedUserName, expectedPassword)));
            ghAuthMock.Setup(x => x.GetTwoFactorCodeAsync(expectedTargetUri, false))
            .ReturnsAsync(expectedAuthCode);

            var ghApiMock = new Mock <IGitHubRestApi>(MockBehavior.Strict);

            ghApiMock.Setup(x => x.CreatePersonalAccessTokenAsync(expectedTargetUri, expectedUserName, expectedPassword, null, It.IsAny <IEnumerable <string> >()))
            .ReturnsAsync(response1);
            ghApiMock.Setup(x => x.CreatePersonalAccessTokenAsync(expectedTargetUri, expectedUserName, expectedPassword, expectedAuthCode, It.IsAny <IEnumerable <string> >()))
            .ReturnsAsync(response2);
            ghApiMock.Setup(x => x.GetUserInfoAsync(expectedTargetUri, patValue))
            .ReturnsAsync(new GitHubUserInfo {
                Login = expectedUserName
            });

            var provider = new GitHubHostProvider(context, ghApiMock.Object, ghAuthMock.Object);

            ICredential credential = await provider.GenerateCredentialAsync(input);

            Assert.NotNull(credential);
            Assert.Equal(expectedUserName, credential.Account);
            Assert.Equal(patValue, credential.Password);

            ghApiMock.Verify(
                x => x.CreatePersonalAccessTokenAsync(
                    expectedTargetUri, expectedUserName, expectedPassword, null, expectedPatScopes),
                Times.Once);
            ghApiMock.Verify(
                x => x.CreatePersonalAccessTokenAsync(
                    expectedTargetUri, expectedUserName, expectedPassword, expectedAuthCode, expectedPatScopes),
                Times.Once);
        }
Example #2
0
        private async Task <int> ExecuteAsync(CommandOptions options)
        {
            var viewModel = new CredentialsViewModel(Context.Environment)
            {
                ShowBrowserLogin = options.All || options.Browser,
                ShowDeviceLogin  = options.All || options.Device,
                ShowTokenLogin   = options.All || options.Pat,
                ShowBasicLogin   = options.All || options.Basic,
            };

            if (!GitHubHostProvider.IsGitHubDotCom(options.EnterpriseUrl))
            {
                viewModel.EnterpriseUrl = options.EnterpriseUrl;
            }

            if (!string.IsNullOrWhiteSpace(options.UserName))
            {
                viewModel.UserName = options.UserName;
            }

            await ShowAsync(viewModel, CancellationToken.None);

            if (!viewModel.WindowResult)
            {
                throw new Exception("User cancelled dialog.");
            }

            var result = new Dictionary <string, string>();

            switch (viewModel.SelectedMode)
            {
            case AuthenticationModes.Basic:
                result["mode"]     = "basic";
                result["username"] = viewModel.UserName;
                result["password"] = viewModel.Password;
                break;

            case AuthenticationModes.Browser:
                result["mode"] = "browser";
                break;

            case AuthenticationModes.Device:
                result["mode"] = "device";
                break;

            case AuthenticationModes.Pat:
                result["mode"] = "pat";
                result["pat"]  = viewModel.Token;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            WriteResult(result);
            return(0);
        }
        public async Task GitHubHostProvider_GetSupportedAuthenticationModes_GitHubDotCom_ReturnsDotComModes()
        {
            var targetUri     = new Uri("https://github.com");
            var expectedModes = GitHubConstants.DotComAuthenticationModes;

            var provider = new GitHubHostProvider(new TestCommandContext());

            AuthenticationModes actualModes = await provider.GetSupportedAuthenticationModesAsync(targetUri);

            Assert.Equal(expectedModes, actualModes);
        }
        public void GitHubHostProvider_GetCredentialServiceUrl(string protocol, string host, string expectedService)
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = protocol,
                ["host"]     = host,
            });

            var provider = new GitHubHostProvider(new TestCommandContext());

            Assert.Equal(expectedService, provider.GetServiceName(input));
        }
        public void GitHubHostProvider_IsSupported(string protocol, string host, bool expected)
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = protocol,
                ["host"]     = host,
            });

            var provider = new GitHubHostProvider(new TestCommandContext());

            Assert.Equal(expected, provider.IsSupported(input));
        }
Example #6
0
        public void GitHubHostProvider_IsSupported_NonGitHub_ReturnsFalse()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "example.com",
            });

            var provider = new GitHubHostProvider(new TestCommandContext());

            Assert.False(provider.IsSupported(input));
        }
Example #7
0
        public void GitHubHostProvider_IsSupported_GistHost_Https_ReturnsTrue()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "gist.github.com",
            });

            var provider = new GitHubHostProvider(new TestCommandContext());

            Assert.True(provider.IsSupported(input));
        }
        private async Task <int> ExecuteAsync(string enterpriseUrl, string userName, bool basic, bool oauth, bool pat)
        {
            var viewModel = new CredentialsViewModel(Context.Environment)
            {
                ShowBrowserLogin = oauth,
                ShowTokenLogin   = pat,
                ShowBasicLogin   = basic,
            };

            if (!GitHubHostProvider.IsGitHubDotCom(enterpriseUrl))
            {
                viewModel.EnterpriseUrl = enterpriseUrl;
            }

            if (!string.IsNullOrWhiteSpace(userName))
            {
                viewModel.UserName = userName;
            }

            await AvaloniaUi.ShowViewAsync <CredentialsView>(viewModel, GetParentHandle(), CancellationToken.None);

            if (!viewModel.WindowResult)
            {
                throw new Exception("User cancelled dialog.");
            }

            var result = new Dictionary <string, string>();

            switch (viewModel.SelectedMode)
            {
            case AuthenticationModes.Basic:
                result["mode"]     = "basic";
                result["username"] = viewModel.UserName;
                result["password"] = viewModel.Password;
                break;

            case AuthenticationModes.OAuth:
                result["mode"] = "oauth";
                break;

            case AuthenticationModes.Pat:
                result["mode"] = "pat";
                result["pat"]  = viewModel.Token;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            WriteResult(result);
            return(0);
        }
Example #9
0
        public async Task GitHubHostProvider_GenerateCredentialAsync_OAuth_ReturnsCredential()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "github.com",
            });

            var expectedTargetUri = new Uri("https://github.com/");
            IEnumerable <string> expectedOAuthScopes = new[]
            {
                GitHubConstants.OAuthScopes.Repo,
                GitHubConstants.OAuthScopes.Gist,
                GitHubConstants.OAuthScopes.Workflow,
            };

            var expectedUserName = "******";
            var tokenValue       = "OAUTH-TOKEN";
            var response         = new OAuth2TokenResult(tokenValue, "bearer");

            var context = new TestCommandContext();

            var ghAuthMock = new Mock <IGitHubAuthentication>(MockBehavior.Strict);

            ghAuthMock.Setup(x => x.GetAuthenticationAsync(expectedTargetUri, null, It.IsAny <AuthenticationModes>()))
            .ReturnsAsync(new AuthenticationPromptResult(AuthenticationModes.OAuth));

            ghAuthMock.Setup(x => x.GetOAuthTokenAsync(expectedTargetUri, It.IsAny <IEnumerable <string> >()))
            .ReturnsAsync(response);

            var ghApiMock = new Mock <IGitHubRestApi>(MockBehavior.Strict);

            ghApiMock.Setup(x => x.GetUserInfoAsync(expectedTargetUri, tokenValue))
            .ReturnsAsync(new GitHubUserInfo {
                Login = expectedUserName
            });

            var provider = new GitHubHostProvider(context, ghApiMock.Object, ghAuthMock.Object);

            ICredential credential = await provider.GenerateCredentialAsync(input);

            Assert.NotNull(credential);
            Assert.Equal(expectedUserName, credential.Account);
            Assert.Equal(tokenValue, credential.Password);

            ghAuthMock.Verify(
                x => x.GetOAuthTokenAsync(
                    expectedTargetUri, expectedOAuthScopes),
                Times.Once);
        }
Example #10
0
        public void GitHubHostProvider_IsSupported_GistHost_UnencryptedHttp_ReturnsTrue()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "http",
                ["host"]     = "gist.github.com",
            });

            var provider = new GitHubHostProvider(new TestCommandContext());

            // We report that we support unencrypted HTTP here so that we can fail and
            // show a helpful error message in the call to `GenerateCredentialAsync` instead.
            Assert.True(provider.IsSupported(input));
        }
Example #11
0
        public void GitHubHostProvider_GetCredentialKey_GistHost_ReturnsCorrectKey()
        {
            const string expectedKey = "git:https://github.com";
            var          input       = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "gist.github.com",
            });

            var    provider  = new GitHubHostProvider(new TestCommandContext());
            string actualKey = provider.GetCredentialKey(input);

            Assert.Equal(expectedKey, actualKey);
        }
Example #12
0
        public async Task GitHubHostProvider_GenerateCredentialAsync_UnencryptedHttp_ThrowsException()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "http",
                ["host"]     = "github.com",
            });

            var context = new TestCommandContext();
            var ghApi   = Mock.Of <IGitHubRestApi>();
            var ghAuth  = Mock.Of <IGitHubAuthentication>();

            var provider = new GitHubHostProvider(context, ghApi, ghAuth);

            await Assert.ThrowsAsync <Exception>(() => provider.GenerateCredentialAsync(input));
        }
Example #13
0
        public async Task GitHubHostProvider_GenerateCredentialAsync_2FARequired_ReturnsCredential()
        {
            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "github.com",
            });

            var expectedTargetUri = new Uri("https://github.com/");
            var expectedUserName  = "******";
            var expectedPassword  = "******";
            var expectedAuthCode  = "123456";
            IEnumerable <string> expectedPatScopes = new[]
            {
                GitHubConstants.TokenScopes.Repo,
                GitHubConstants.TokenScopes.Gist
            };

            var patValue  = "PERSONAL-ACCESS-TOKEN";
            var pat       = new GitCredential(Constants.PersonalAccessTokenUserName, patValue);
            var response1 = new AuthenticationResult(GitHubAuthenticationResultType.TwoFactorApp);
            var response2 = new AuthenticationResult(GitHubAuthenticationResultType.Success, pat);

            var context = new TestCommandContext();

            var ghAuthMock = new Mock <IGitHubAuthentication>(MockBehavior.Strict);

            ghAuthMock.Setup(x => x.GetCredentialsAsync(expectedTargetUri))
            .ReturnsAsync(new GitCredential(expectedUserName, expectedPassword));
            ghAuthMock.Setup(x => x.GetAuthenticationCodeAsync(expectedTargetUri, false))
            .ReturnsAsync(expectedAuthCode);

            var ghApiMock = new Mock <IGitHubRestApi>(MockBehavior.Strict);

            ghApiMock.Setup(x => x.AcquireTokenAsync(expectedTargetUri, expectedUserName, expectedPassword, null, It.IsAny <IEnumerable <string> >()))
            .ReturnsAsync(response1);
            ghApiMock.Setup(x => x.AcquireTokenAsync(expectedTargetUri, expectedUserName, expectedPassword, expectedAuthCode, It.IsAny <IEnumerable <string> >()))
            .ReturnsAsync(response2);

            var provider = new GitHubHostProvider(context, ghApiMock.Object, ghAuthMock.Object);

            ICredential credential = await provider.GenerateCredentialAsync(input);

            Assert.NotNull(credential);
            Assert.Equal(Constants.PersonalAccessTokenUserName, credential.UserName);
            Assert.Equal(patValue, credential.Password);
        }
Example #14
0
        public void GitHubHostProvider_GetCredentialServiceUrl(string uriString, string expectedService)
        {
            Uri uri = new Uri(uriString);

            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = uri.Scheme,
                ["host"]     = uri.Host,
            });

            // Ensure nothing got lost during transformation
            Assert.Equal(uriString, input.Protocol + "://" + input.Host);

            var provider = new GitHubHostProvider(new TestCommandContext());

            Assert.Equal(expectedService, provider.GetServiceName(input));
        }
Example #15
0
        public void GitHubHostProvider_IsSupported(string uriString, bool expected)
        {
            Uri uri = new Uri(uriString);

            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = uri.Scheme,
                ["host"]     = uri.Host,
            });

            // Ensure nothing got lost during transformation
            Assert.Equal(uriString, input.Protocol + "://" + input.Host);

            var provider = new GitHubHostProvider(new TestCommandContext());

            Assert.Equal(expected, provider.IsSupported(input));
        }
Example #16
0
        async Task <ICredential> GetCredentialAsync()
        {
            if (credential != null)
            {
                return(credential);
            }

            var input = new InputArguments(new Dictionary <string, string>
            {
                ["protocol"] = "https",
                ["host"]     = "github.com",
            });

            var provider = new GitHubHostProvider(new CommandContext());

            credential = await provider.GetCredentialAsync(input);

            return(credential);
        }
Example #17
0
        public async Task GitHubHostProvider_GetSupportedAuthenticationModes(string uriString, string gitHubAuthModes, AuthenticationModes expectedModes)
        {
            var targetUri = new Uri(uriString);

            var context = new TestCommandContext {
            };

            if (gitHubAuthModes != null)
            {
                context.Environment.Variables.Add(GitHubConstants.EnvironmentVariables.AuthenticationModes, gitHubAuthModes);
            }

            var ghApiMock  = new Mock <IGitHubRestApi>(MockBehavior.Strict);
            var ghAuthMock = new Mock <IGitHubAuthentication>(MockBehavior.Strict);

            var provider = new GitHubHostProvider(context, ghApiMock.Object, ghAuthMock.Object);

            AuthenticationModes actualModes = await provider.GetSupportedAuthenticationModesAsync(targetUri);

            Assert.Equal(expectedModes, actualModes);
        }
        public async Task GitHubHostProvider_GetSupportedAuthenticationModes_NotDotCom_NewInstanceWithPassword_ReturnsBasicAndOAuth()
        {
            var targetUri = new Uri("https://ghe.io");
            var metaInfo  = new GitHubMetaInfo
            {
                InstalledVersion = "100.0",
                VerifiablePasswordAuthentication = true
            };

            var expectedModes = AuthenticationModes.Basic | AuthenticationModes.OAuth;

            var context    = new TestCommandContext();
            var ghAuthMock = new Mock <IGitHubAuthentication>(MockBehavior.Strict);

            var ghApiMock = new Mock <IGitHubRestApi>(MockBehavior.Strict);

            ghApiMock.Setup(x => x.GetMetaInfoAsync(targetUri)).ReturnsAsync(metaInfo);

            var provider = new GitHubHostProvider(context, ghApiMock.Object, ghAuthMock.Object);

            AuthenticationModes actualModes = await provider.GetSupportedAuthenticationModesAsync(targetUri);

            Assert.Equal(expectedModes, actualModes);
        }
Example #19
0
 public void GitHubHostProvider_IsGitHubDotCom(string input, bool expected)
 {
     Assert.Equal(expected, GitHubHostProvider.IsGitHubDotCom(new Uri(input)));
 }