| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 | using Renci.SshNet.Common;using Renci.SshNet.IntegrationTests.Common;namespace Renci.SshNet.IntegrationTests{    [TestClass]    public class AuthenticationTests : IntegrationTestBase    {        private AuthenticationMethodFactory _authenticationMethodFactory;        private IConnectionInfoFactory _connectionInfoFactory;        private IConnectionInfoFactory _adminConnectionInfoFactory;        private RemoteSshdConfig _remoteSshdConfig;        [TestInitialize]        public void SetUp()        {            _authenticationMethodFactory = new AuthenticationMethodFactory();            _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort, _authenticationMethodFactory);            _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort);            _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig();        }        [TestCleanup]        public void TearDown()        {            _remoteSshdConfig?.Reset();            using (var client = new SshClient(_adminConnectionInfoFactory.Create()))            {                client.Connect();                // Reset the password back to the "regular" password.                using (var cmd = client.RunCommand($"echo \"{Users.Regular.Password}\n{Users.Regular.Password}\" | sudo passwd " + Users.Regular.UserName))                {                    Assert.AreEqual(0, cmd.ExitStatus, cmd.Error);                }                // Remove password expiration                using (var cmd = client.RunCommand($"sudo chage --expiredate -1 " + Users.Regular.UserName))                {                    Assert.AreEqual(0, cmd.ExitStatus, cmd.Error);                }            }        }        [TestMethod]        public void Multifactor_PublicKey()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        [TestCategory("Authentication")]        public void Multifactor_PublicKey_Connect_Then_Reconnect()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();                client.Disconnect();                client.Connect();                client.Disconnect();            }        }        [TestMethod]        public void Multifactor_PublicKeyWithPassPhrase()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyWithPassPhraseAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_PublicKey_MultiplePrivateKey()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserMultiplePrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_PublicKey_MultipleAuthenticationMethod()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod(),                                                               _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_KeyboardInteractiveAndPublicKey()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive,publickey")                             .WithChallengeResponseAuthentication(true)                             .WithKeyboardInteractiveAuthentication(true)                             .WithUsePAM(true)                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethodWithBadPassword(),                                                               _authenticationMethodFactory.CreateRegularUserKeyboardInteractiveAuthenticationMethod(),                                                               _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_Password_ExceedsPartialSuccessLimit()        {            // configure server to require more successfull authentications from a given method than our partial            // success limit (5) allows            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,password,password,password,password,password")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                try                {                    client.Connect();                    Assert.Fail();                }                catch (SshAuthenticationException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("Reached authentication attempt limit for method (password).", ex.Message);                }            }        }        [TestMethod]        public void Multifactor_Password_MatchPartialSuccessLimit()        {            // configure server to require a number of successfull authentications from a given method that exactly            // matches our partial success limit (5)            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,password,password,password,password")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_Password_Or_PublicKeyAndKeyboardInteractive()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password publickey,keyboard-interactive")                             .WithChallengeResponseAuthentication(true)                             .WithKeyboardInteractiveAuthentication(true)                             .WithUsePAM(true)                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod(),                                                               _authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_Password_Or_PublicKeyAndPassword_BadPassword()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password publickey,password")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethodWithBadPassword(),                                                               _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                try                {                    client.Connect();                    Assert.Fail();                }                catch (SshAuthenticationException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("Permission denied (password).", ex.Message);                }            }        }        [TestMethod]        public void Multifactor_PasswordAndPublicKey_Or_PasswordAndPassword()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,publickey password,password")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(),                                                               _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }            connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethodWithBadPassword(),                                                               _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                try                {                    client.Connect();                    Assert.Fail();                }                catch (SshAuthenticationException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("Permission denied (password).", ex.Message);                }            }        }        [TestMethod]        public void Multifactor_PasswordAndPassword_Or_PublicKey()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,password publickey")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(),                                                               _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }            connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void Multifactor_Password_Or_Password()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password password")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }            connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(),                                                           _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey());            using (var client = new SftpClient(connectionInfo))            {                client.Connect();            }        }        [TestMethod]        public void KeyboardInteractive_PasswordExpired()        {            var temporaryPassword = new Random().Next().ToString();            using (var client = new SshClient(_adminConnectionInfoFactory.Create()))            {                client.Connect();                // Temporarity modify password so that when we expire this password, we change reset the password back to                // the "regular" password.                using (var cmd = client.RunCommand($"echo \"{temporaryPassword}\n{temporaryPassword}\" | sudo passwd " + Users.Regular.UserName))                {                    Assert.AreEqual(0, cmd.ExitStatus, cmd.Error);                }                // Force the password to expire immediately                using (var cmd = client.RunCommand($"sudo chage -d 0 " + Users.Regular.UserName))                {                    Assert.AreEqual(0, cmd.ExitStatus, cmd.Error);                }            }            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive")                             .WithChallengeResponseAuthentication(true)                             .WithKeyboardInteractiveAuthentication(true)                             .WithUsePAM(true)                             .Update()                             .Restart();            var keyboardInteractive = new KeyboardInteractiveAuthenticationMethod(Users.Regular.UserName);            int authenticationPromptCount = 0;            keyboardInteractive.AuthenticationPrompt += (sender, args) =>            {                Console.WriteLine(args.Instruction);                foreach (var authenticationPrompt in args.Prompts)                {                    Console.WriteLine(authenticationPrompt.Request);                    switch (authenticationPromptCount)                    {                        case 0:                            // Regular password prompt                            authenticationPrompt.Response = temporaryPassword;                            break;                        case 1:                            // Password expired, provide current password                            authenticationPrompt.Response = temporaryPassword;                            break;                        case 2:                            // Password expired, provide new password                            authenticationPrompt.Response = Users.Regular.Password;                            break;                        case 3:                            // Password expired, retype new password                            authenticationPrompt.Response = Users.Regular.Password;                            break;                    }                    authenticationPromptCount++;                }            };            var connectionInfo = _connectionInfoFactory.Create(keyboardInteractive);            using (var client = new SftpClient(connectionInfo))            {                client.Connect();                Assert.AreEqual(4, authenticationPromptCount);            }        }        [TestMethod]        public void KeyboardInteractiveConnectionInfo()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive")                             .WithChallengeResponseAuthentication(true)                             .WithKeyboardInteractiveAuthentication(true)                             .WithUsePAM(true)                             .Update()                             .Restart();            var host = SshServerHostName;            var port = SshServerPort;            var username = User.UserName;            var password = User.Password;            #region Example KeyboardInteractiveConnectionInfo AuthenticationPrompt            var connectionInfo = new KeyboardInteractiveConnectionInfo(host, port, username);            connectionInfo.AuthenticationPrompt += delegate (object sender, AuthenticationPromptEventArgs e)                                                       {                                                           Console.WriteLine(e.Instruction);                                                           foreach (var prompt in e.Prompts)                                                           {                                                               Console.WriteLine(prompt.Request);                                                               prompt.Response = password;                                                           }                                                       };            using (var client = new SftpClient(connectionInfo))            {                client.Connect();                //  Do something here                client.Disconnect();            }            #endregion            Assert.AreEqual(connectionInfo.Host, SshServerHostName);            Assert.AreEqual(connectionInfo.Username, User.UserName);        }        [TestMethod]        public void KeyboardInteractive_NoResponseSet_ThrowsSshAuthenticationException()        {            // ...instead of a cryptic ArgumentNullException            // https://github.com/sshnet/SSH.NET/issues/382            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive")                             .WithChallengeResponseAuthentication(true)                             .WithKeyboardInteractiveAuthentication(true)                             .WithUsePAM(true)                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(new KeyboardInteractiveAuthenticationMethod(Users.Regular.UserName));            using (var client = new SftpClient(connectionInfo))            {                try                {                    client.Connect();                    Assert.Fail();                }                catch (SshAuthenticationException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.IsTrue(ex.Message.StartsWith("AuthenticationPrompt.Response is null for prompt \"Password: \""), $"Message was \"{ex.Message}\"");                }            }        }    }}
 |