Skip to content

Fail with a friendlier error message when response has not been set #1245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}\"");
}
}
}
}
}