Skip to content

Commit

Permalink
Improve tests for partial success limit.
Browse files Browse the repository at this point in the history
  • Loading branch information
drieseng committed Oct 5, 2017
1 parent 14b654d commit c2e1de5
Show file tree
Hide file tree
Showing 12 changed files with 609 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;

namespace Renci.SshNet.Tests.Classes
{
/// <summary>
/// * ConnectionInfo provides the following authentication methods (in order):
/// o publickey
/// o password
/// * Partial success limit is 2
///
/// none
/// (1=FAIL)
/// |
/// +------------------------+------------------------+
/// | | |
/// password ◄--\ publickey keyboard-interactive
/// (7=SKIP) | (2=PS)
/// | |
/// | password
/// | (3=PS)
/// | |
/// | password
/// | (4=PS)
/// | |
/// | publickey
/// | (5=PS)
/// | |
/// \---- publickey
/// (6=SKIP)
/// </summary>
[TestClass]
public class ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit : ClientAuthenticationTestBase
{
private int _partialSuccessLimit;
private ClientAuthentication _clientAuthentication;
private SshAuthenticationException _actualException;

protected override void SetupData()
{
_partialSuccessLimit = 2;
}

protected override void SetupMocks()
{
var seq = new MockSequence();

SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_FAILURE"));
SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS"));
SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_BANNER"));

ConnectionInfoMock.InSequence(seq).Setup(p => p.CreateNoneAuthenticationMethod())
.Returns(NoneAuthenticationMethodMock.Object);

/* 1 */

NoneAuthenticationMethodMock.InSequence(seq).Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.Failure);
ConnectionInfoMock.InSequence(seq)
.Setup(p => p.AuthenticationMethods)
.Returns(new List<IAuthenticationMethod>
{
PublicKeyAuthenticationMethodMock.Object,
PasswordAuthenticationMethodMock.Object
});
NoneAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"password", "publickey", "keyboard-interactive"});

/* Enumerate supported authentication methods */

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");

/* 2 */

PublicKeyAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.PartialSuccess);
PublicKeyAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"password"});

/* Enumerate supported authentication methods */

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");

/* 3 */

PasswordAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.PartialSuccess);
PasswordAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"password"});

/* Enumerate supported authentication methods */

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");

/* 4 */

PasswordAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.PartialSuccess);
PasswordAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"publickey"});

/* Enumerate supported authentication methods */

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");

/* 5 */

PublicKeyAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.PartialSuccess);
PublicKeyAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"publickey"});

/* Enumerate supported authentication methods */

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");

/* 6: Record partial success limit reached exception, and skip password authentication method */

PublicKeyAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Name)
.Returns("publickey-partial1");

/* 7: Record partial success limit reached exception, and skip password authentication method */

PasswordAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Name)
.Returns("password-partial1");

SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE"));
SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS"));
SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER"));
}

protected override void Arrange()
{
base.Arrange();

_clientAuthentication = new ClientAuthentication(_partialSuccessLimit);
}

protected override void Act()
{
try
{
_clientAuthentication.Authenticate(ConnectionInfoMock.Object, SessionMock.Object);
Assert.Fail();
}
catch (SshAuthenticationException ex)
{
_actualException = ex;
}
}

[TestMethod]
public void AuthenticateOnPasswordAuthenticationMethodShouldHaveBeenInvokedTwice()
{
PasswordAuthenticationMethodMock.Verify(p => p.Authenticate(SessionMock.Object), Times.Exactly(2));
}

[TestMethod]
public void AuthenticateOnPublicKeyAuthenticationMethodShouldHaveBeenInvokedTwice()
{
PublicKeyAuthenticationMethodMock.Verify(p => p.Authenticate(SessionMock.Object), Times.Exactly(2));
}

[TestMethod]
public void AuthenticateShouldThrowSshAuthenticationException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("Reached authentication attempt limit for method (password-partial1).", _actualException.Message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ protected override void SetupMocks()
ConnectionInfoMock.InSequence(seq).Setup(p => p.CreateNoneAuthenticationMethod())
.Returns(NoneAuthenticationMethodMock.Object);

NoneAuthenticationMethodMock.InSequence(seq).Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.Failure);
NoneAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.Failure);
ConnectionInfoMock.InSequence(seq).Setup(p => p.AuthenticationMethods)
.Returns(new List<IAuthenticationMethod>
{
PublicKeyAuthenticationMethodMock.Object
});
.Returns(new List<IAuthenticationMethod>
{
PublicKeyAuthenticationMethodMock.Object
});
NoneAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] { "password" });
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"password"});

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@

namespace Renci.SshNet.Tests.Classes
{
/// <summary>
/// * ConnectionInfo provides the following authentication methods (in order):
/// o password
/// o publickey
/// o keyboard-interactive
/// * Partial success limit is 1
/// * Scenario:
/// none
/// (1=FAIL)
/// |
/// +------------------------------+
/// | |
/// publickey password
/// (2=PARTIAL)
/// *----------------------*
/// | |
/// keyboard-interactive publickey
/// (3=SUCCESS)
/// </summary>
[TestClass]
public class ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess : ClientAuthenticationTestBase
{
Expand All @@ -26,6 +45,8 @@ protected override void SetupMocks()
ConnectionInfoMock.InSequence(seq).Setup(p => p.CreateNoneAuthenticationMethod())
.Returns(NoneAuthenticationMethodMock.Object);

/* 1 */

NoneAuthenticationMethodMock.InSequence(seq).Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.Failure);
ConnectionInfoMock.InSequence(seq).Setup(p => p.AuthenticationMethods)
Expand All @@ -35,20 +56,34 @@ protected override void SetupMocks()
PublicKeyAuthenticationMethodMock.Object,
KeyboardInteractiveAuthenticationMethodMock.Object,
});
NoneAuthenticationMethodMock.InSequence(seq).Setup(p => p.AllowedAuthentications).Returns(new[] { "publickey", "password" });
NoneAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.AllowedAuthentications)
.Returns(new[] {"publickey", "password"});

/* Enumerate supported authentication methods */

PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");
PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive");

/* 2 */

PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.PartialSuccess);
PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.AllowedAuthentications)
.Returns(new[] { "keyboard-interactive", "publickey" });
.Returns(new[] {"keyboard-interactive", "publickey"});

/* Enumerate supported authentication methods */

PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password");
PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey");
KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive");

PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Authenticate(SessionMock.Object)).Returns(AuthenticationResult.Success);
/* 3 */

PublicKeyAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Authenticate(SessionMock.Object))
.Returns(AuthenticationResult.Success);

SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE"));
SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ namespace Renci.SshNet.Tests.Classes
/// o publickey
/// o keyboard-interactive
/// * Partial success limit is 2
///
/// * Scenario:
/// none
/// (1=FAIL)
/// |
/// +-------------------+
/// | |
/// publickey keyboard-interactive
/// (2=PS) ^ (6=FAIL)
/// | |
/// password |
/// (3=PS) |
/// | |
/// password |
/// (4=PS) |
/// | |
/// password |
/// (5=SKIP) |
/// +------------+
/// +------------------------+
/// | |
/// publickey keyboard-interactive
/// (2=PS) ^ (6=FAIL)
/// | |
/// password |
/// (3=PS) |
/// | |
/// password |
/// (4=PS) |
/// | |
/// password |
/// (5=SKIP) |
/// +---------------+
/// </summary>
[TestClass]
public class ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch : ClientAuthenticationTestBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ protected override void SetupMocks()

PasswordAuthenticationMethodMock.InSequence(seq)
.Setup(p => p.Name)
.Returns("password-partial1");
.Returns("password-partial2");

/* 8 */

Expand Down
Loading

0 comments on commit c2e1de5

Please sign in to comment.