ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs 8.6 KB

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