Skip to content

Commit

Permalink
Fail with a friendlier error message when response has not been set (#…
Browse files Browse the repository at this point in the history
…1245)

Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
  • Loading branch information
Rob-Hague and WojciechNagorski authored Dec 2, 2023
1 parent 4c7bd35 commit a027c76
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class AuthenticationPromptEventArgs : AuthenticationEventArgs
/// <param name="instruction">The instruction.</param>
/// <param name="language">The language.</param>
/// <param name="prompts">The information request prompts.</param>
public AuthenticationPromptEventArgs(string username, string instruction, string language, IEnumerable<AuthenticationPrompt> prompts)
public AuthenticationPromptEventArgs(string username, string instruction, string language, IReadOnlyList<AuthenticationPrompt> prompts)
: base(username)
{
Instruction = instruction;
Expand All @@ -35,6 +35,6 @@ public AuthenticationPromptEventArgs(string username, string instruction, string
/// <summary>
/// Gets server information request prompts.
/// </summary>
public IEnumerable<AuthenticationPrompt> Prompts { get; }
public IReadOnlyList<AuthenticationPrompt> Prompts { get; }
}
}
14 changes: 12 additions & 2 deletions src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,19 @@ private void Session_UserAuthenticationInformationRequestReceived(object sender,

var informationResponse = new InformationResponseMessage();

foreach (var response in from r in eventArgs.Prompts orderby r.Id ascending select r.Response)
foreach (var prompt in eventArgs.Prompts.OrderBy(r => r.Id))
{
informationResponse.Responses.Add(response);
if (prompt.Response is null)
{
throw new SshAuthenticationException(
$"{nameof(AuthenticationPrompt)}.{nameof(prompt.Response)} is null for " +
$"prompt \"{prompt.Request}\". You can set this by subscribing to " +
$"{nameof(KeyboardInteractiveAuthenticationMethod)}.{nameof(AuthenticationPrompt)} " +
$"and inspecting the {nameof(AuthenticationPromptEventArgs.Prompts)} property " +
$"of the event args.");
}

informationResponse.Responses.Add(prompt.Response);
}

// Send information response message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal sealed class InformationRequestMessage : Message
/// <summary>
/// Gets information request prompts.
/// </summary>
public IEnumerable<AuthenticationPrompt> Prompts { get; private set; }
public IReadOnlyList<AuthenticationPrompt> Prompts { get; private set; }

/// <summary>
/// Called when type specific data need to be loaded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationM
return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, new PrivateKeyFile(memoryStream));
}

public PasswordAuthenticationMethod CreateRegulatUserPasswordAuthenticationMethod()
public PasswordAuthenticationMethod CreateRegularUserPasswordAuthenticationMethod()
{
return new PasswordAuthenticationMethod(Users.Regular.UserName, Users.Regular.Password);
}
Expand Down
46 changes: 38 additions & 8 deletions test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public void Multifactor_Password_ExceedsPartialSuccessLimit()
.Update()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod());
var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());
using (var client = new SftpClient(connectionInfo))
{
try
Expand All @@ -187,7 +187,7 @@ public void Multifactor_Password_MatchPartialSuccessLimit()
.Update()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod());
var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
Expand All @@ -205,7 +205,7 @@ public void Multifactor_Password_Or_PublicKeyAndKeyboardInteractive()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod(),
_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod());
_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
Expand Down Expand Up @@ -243,7 +243,7 @@ public void Multifactor_PasswordAndPublicKey_Or_PasswordAndPassword()
.Update()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(),
var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(),
_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey());
using (var client = new SftpClient(connectionInfo))
{
Expand Down Expand Up @@ -275,14 +275,14 @@ public void Multifactor_PasswordAndPassword_Or_PublicKey()
.Update()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(),
var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(),
_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey());
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
}

connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod());
connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
Expand All @@ -297,13 +297,13 @@ public void Multifactor_Password_Or_Password()
.Update()
.Restart();

var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod());
var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod());
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
}

connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(),
connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(),
_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey());
using (var client = new SftpClient(connectionInfo))
{
Expand Down Expand Up @@ -423,5 +423,35 @@ public void KeyboardInteractiveConnectionInfo()
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}\"");
}
}
}
}
}

0 comments on commit a027c76

Please sign in to comment.