ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System.Collections.Generic;
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;
  3. using Moq;
  4. using Renci.SshNet.Common;
  5. namespace Renci.SshNet.Tests.Classes
  6. {
  7. /// <summary>
  8. /// * ConnectionInfo provides the following authentication methods (in order):
  9. /// o password
  10. /// o publickey
  11. /// o keyboard-interactive
  12. /// * Partial success limit is 2
  13. /// * Scenario:
  14. /// none
  15. /// (1=FAIL)
  16. /// |
  17. /// +------------------------+
  18. /// | |
  19. /// publickey keyboard-interactive
  20. /// (2=PS) ^ (6=FAIL)
  21. /// | |
  22. /// password |
  23. /// (3=PS) |
  24. /// | |
  25. /// password |
  26. /// (4=PS) |
  27. /// | |
  28. /// password |
  29. /// (5=SKIP) |
  30. /// +---------------+
  31. /// </summary>
  32. [TestClass]
  33. public class ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch : ClientAuthenticationTestBase
  34. {
  35. private int _partialSuccessLimit;
  36. private ClientAuthentication _clientAuthentication;
  37. private SshAuthenticationException _actualException;
  38. protected override void SetupData()
  39. {
  40. _partialSuccessLimit = 2;
  41. }
  42. protected override void SetupMocks()
  43. {
  44. var seq = new MockSequence();
  45. SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_FAILURE"));
  46. SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS"));
  47. SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_BANNER"));
  48. ConnectionInfoMock.InSequence(seq).Setup(p => p.CreateNoneAuthenticationMethod())
  49. .Returns(NoneAuthenticationMethodMock.Object);
  50. /* 1 */
  51. NoneAuthenticationMethodMock.InSequence(seq).Setup(p => p.Authenticate(SessionMock.Object))
  52. .Returns(AuthenticationResult.Failure);
  53. ConnectionInfoMock.InSequence(seq)
  54. .Setup(p => p.AuthenticationMethods)
  55. .Returns(new List<IAuthenticationMethod>
  56. {
  57. PasswordAuthenticationMethodMock.Object,
  58. PublicKeyAuthenticationMethodMock.Object,
  59. KeyboardInteractiveAuthenticationMethodMock.Object,
  60. });
  61. NoneAuthenticationMethodMock.InSequence(seq)
  62. .Setup(p => p.AllowedAuthentications)
  63. .Returns(new[] { "publickey", "keyboard-interactive" });
  64. /* Enumerate supported authentication methods */
  65. PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");
  66. PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
  67. KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive");
  68. /* 2 */
  69. PublicKeyAuthenticationMethodMock.InSequence(seq)
  70. .Setup(p => p.Authenticate(SessionMock.Object))
  71. .Returns(AuthenticationResult.PartialSuccess);
  72. PublicKeyAuthenticationMethodMock.InSequence(seq)
  73. .Setup(p => p.AllowedAuthentications)
  74. .Returns(new[] { "password" });
  75. /* Enumerate supported authentication methods */
  76. PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");
  77. PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
  78. KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive");
  79. /* 3 */
  80. PasswordAuthenticationMethodMock.InSequence(seq)
  81. .Setup(p => p.Authenticate(SessionMock.Object))
  82. .Returns(AuthenticationResult.PartialSuccess);
  83. PasswordAuthenticationMethodMock.InSequence(seq)
  84. .Setup(p => p.AllowedAuthentications)
  85. .Returns(new[] { "password" });
  86. /* Enumerate supported authentication methods */
  87. PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");
  88. PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
  89. KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive");
  90. /* 4 */
  91. PasswordAuthenticationMethodMock.InSequence(seq)
  92. .Setup(p => p.Authenticate(SessionMock.Object))
  93. .Returns(AuthenticationResult.PartialSuccess);
  94. PasswordAuthenticationMethodMock.InSequence(seq)
  95. .Setup(p => p.AllowedAuthentications)
  96. .Returns(new[] { "password" });
  97. /* Enumerate supported authentication methods */
  98. PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");
  99. PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
  100. KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive");
  101. /* 5: Record partial success limit reached exception, and skip password authentication method */
  102. PasswordAuthenticationMethodMock.InSequence(seq)
  103. .Setup(p => p.Name)
  104. .Returns("password-partial");
  105. /* 6 */
  106. KeyboardInteractiveAuthenticationMethodMock.InSequence(seq)
  107. .Setup(p => p.Authenticate(SessionMock.Object))
  108. .Returns(AuthenticationResult.Failure);
  109. KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive-failure");
  110. SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE"));
  111. SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS"));
  112. SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER"));
  113. }
  114. protected override void Arrange()
  115. {
  116. base.Arrange();
  117. _clientAuthentication = new ClientAuthentication(_partialSuccessLimit);
  118. }
  119. protected override void Act()
  120. {
  121. try
  122. {
  123. _clientAuthentication.Authenticate(ConnectionInfoMock.Object, SessionMock.Object);
  124. Assert.Fail();
  125. }
  126. catch (SshAuthenticationException ex)
  127. {
  128. _actualException = ex;
  129. }
  130. }
  131. [TestMethod]
  132. public void AuthenticateOnKeyboardInteractiveAuthenticationMethodShouldHaveBeenInvokedOnce()
  133. {
  134. KeyboardInteractiveAuthenticationMethodMock.Verify(p => p.Authenticate(SessionMock.Object), Times.Once);
  135. }
  136. [TestMethod]
  137. public void AuthenticateShouldThrowSshAuthenticationException()
  138. {
  139. Assert.IsNotNull(_actualException);
  140. Assert.IsNull(_actualException.InnerException);
  141. Assert.AreEqual("Permission denied (keyboard-interactive-failure).", _actualException.Message);
  142. }
  143. }
  144. }