From feafa2ef389524bdd403a3c4b9de7cb3e6b9e2af Mon Sep 17 00:00:00 2001 From: olegkap_cp Date: Tue, 21 Dec 2010 21:13:25 +0000 Subject: [PATCH] Add Authenticating event to allow capture of any banner text if exists that need to be presented to the user and to provide other authentication related information Refactor userauthentication proccess and add support for "keyboard-interactive" authentication method --- .../Common/AuthenticationEventArgs.cs | 32 +++++ .../Common/AuthenticationPrompt.cs | 30 ++++ .../Common/SshAuthenticationException.cs | 17 +++ .../InformationRequestMessage.cs | 24 ++-- .../InformationResponseMessage.cs | 14 +- .../RequestMessageKeyboardInteractive.cs | 34 +++++ ...stMessage.cs => RequestMessagePassword.cs} | 2 +- ...tMessage.cs => RequestMessagePublicKey.cs} | 2 +- .../Renci.SshClient/Renci.SshClient.csproj | 21 ++- .../Security/UserAuthentication.cs | 62 +++------ .../Security/UserAuthenticationHost.cs | 18 --- .../UserAuthenticationKeyboardInteractive.cs | 131 ++++++++++++++++++ .../Security/UserAuthenticationNone.cs | 10 +- .../Security/UserAuthenticationPassword.cs | 13 +- .../Security/UserAuthenticationPublicKey.cs | 16 +-- Renci.SshClient/Renci.SshClient/Session.cs | 61 +++++--- .../Renci.SshClient/SshBaseClient.cs | 12 ++ .../Renci.SshClient/UserAuthentication.cs | 20 +++ 18 files changed, 397 insertions(+), 122 deletions(-) create mode 100644 Renci.SshClient/Renci.SshClient/Common/AuthenticationEventArgs.cs create mode 100644 Renci.SshClient/Renci.SshClient/Common/AuthenticationPrompt.cs create mode 100644 Renci.SshClient/Renci.SshClient/Common/SshAuthenticationException.cs create mode 100644 Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessageKeyboardInteractive.cs rename Renci.SshClient/Renci.SshClient/Messages/Authentication/{PasswordRequestMessage.cs => RequestMessagePassword.cs} (88%) rename Renci.SshClient/Renci.SshClient/Messages/Authentication/{PublicKeyRequestMessage.cs => RequestMessagePublicKey.cs} (90%) delete mode 100644 Renci.SshClient/Renci.SshClient/Security/UserAuthenticationHost.cs create mode 100644 Renci.SshClient/Renci.SshClient/Security/UserAuthenticationKeyboardInteractive.cs create mode 100644 Renci.SshClient/Renci.SshClient/UserAuthentication.cs diff --git a/Renci.SshClient/Renci.SshClient/Common/AuthenticationEventArgs.cs b/Renci.SshClient/Renci.SshClient/Common/AuthenticationEventArgs.cs new file mode 100644 index 00000000..c3553e3b --- /dev/null +++ b/Renci.SshClient/Renci.SshClient/Common/AuthenticationEventArgs.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Renci.SshClient.Messages.Authentication; + +namespace Renci.SshClient.Common +{ + public class AuthenticationEventArgs : EventArgs + { + public string BannerMessage { get; private set; } + + public string Language { get; private set; } + + public string Instruction { get; private set; } + + public IEnumerable Prompts { get; private set; } + + public AuthenticationEventArgs(string message, string language) + { + this.BannerMessage = message; + this.Language = language; + } + + public AuthenticationEventArgs(string instruction, string language, IEnumerable prompts) + { + this.Instruction = instruction; + this.Language = language; + this.Prompts = prompts; + } + } +} diff --git a/Renci.SshClient/Renci.SshClient/Common/AuthenticationPrompt.cs b/Renci.SshClient/Renci.SshClient/Common/AuthenticationPrompt.cs new file mode 100644 index 00000000..8fc6a4ec --- /dev/null +++ b/Renci.SshClient/Renci.SshClient/Common/AuthenticationPrompt.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Renci.SshClient.Common +{ + public class AuthenticationPrompt + { + public int Id { get; private set; } + /// + /// Gets or sets a value indicating whether the user input should be echoed as characters are typed. + /// + /// + /// true if the user input should be echoed as characters are typed; otherwise, false. + /// + public bool IsEchoed { get; private set; } + + public string Request { get; private set; } + + public string Response { get; set; } + + public AuthenticationPrompt(int id, bool isEchoed, string request) + { + this.Id = id; + this.IsEchoed = isEchoed; + this.Request = request; + } + } +} diff --git a/Renci.SshClient/Renci.SshClient/Common/SshAuthenticationException.cs b/Renci.SshClient/Renci.SshClient/Common/SshAuthenticationException.cs new file mode 100644 index 00000000..bfbe27a7 --- /dev/null +++ b/Renci.SshClient/Renci.SshClient/Common/SshAuthenticationException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Renci.SshClient.Common +{ + [Serializable] + public class SshAuthenticationException : SshException + { + public SshAuthenticationException(string message) + : base(message) + { + + } + } +} diff --git a/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationRequestMessage.cs b/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationRequestMessage.cs index 6afa8a43..11dc5078 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationRequestMessage.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationRequestMessage.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Collections.Generic; +using Renci.SshClient.Common; namespace Renci.SshClient.Messages.Authentication { @@ -17,7 +18,7 @@ namespace Renci.SshClient.Messages.Authentication public string Language { get; set; } - public IEnumerable Prompts { get; set; } + public IEnumerable Prompts { get; set; } protected override void LoadData() { @@ -26,16 +27,14 @@ namespace Renci.SshClient.Messages.Authentication this.Language = this.ReadString(); var numOfPrompts = this.ReadUInt32(); - var prompts = new List(); + var prompts = new List(); for (int i = 0; i < numOfPrompts; i++) - { - prompts.Add(new PromptEcho - { - Prompt = this.ReadString(), - Echo = this.ReadBoolean(), - }); - } + { + var prompt = this.ReadString(); + var echo = this.ReadBoolean(); + prompts.Add(new AuthenticationPrompt(i, echo, prompt)); + } this.Prompts = prompts; } @@ -44,12 +43,5 @@ namespace Renci.SshClient.Messages.Authentication { throw new NotImplementedException(); } - - public class PromptEcho - { - public string Prompt { get; set; } - - public bool Echo { get; set; } - } } } diff --git a/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationResponseMessage.cs b/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationResponseMessage.cs index 17e4416a..b6fb3364 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationResponseMessage.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Authentication/InformationResponseMessage.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Renci.SshClient.Messages.Authentication { @@ -9,6 +10,13 @@ namespace Renci.SshClient.Messages.Authentication get { return MessageTypes.UserAuthenticationInformationResponse; } } + public IList Responses { get; private set; } + + public InformationResponseMessage() + { + this.Responses = new List(); + } + protected override void LoadData() { throw new NotImplementedException(); @@ -16,7 +24,11 @@ namespace Renci.SshClient.Messages.Authentication protected override void SaveData() { - throw new NotImplementedException(); + this.Write((UInt32)this.Responses.Count); + foreach (var response in this.Responses) + { + this.Write(response); + } } } } diff --git a/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessageKeyboardInteractive.cs b/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessageKeyboardInteractive.cs new file mode 100644 index 00000000..9287bdc1 --- /dev/null +++ b/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessageKeyboardInteractive.cs @@ -0,0 +1,34 @@ +using System.Text; + +namespace Renci.SshClient.Messages.Authentication +{ + internal class RequestMessageKeyboardInteractive : RequestMessage + { + public override string MethodName + { + get + { + return "keyboard-interactive"; + } + } + + public string Language { get; set; } + + public string SubMethods { get; set; } + + public RequestMessageKeyboardInteractive() + { + this.Language = string.Empty; + this.SubMethods = string.Empty; + } + + protected override void SaveData() + { + base.SaveData(); + + this.Write(this.Language); + + this.Write(this.SubMethods, Encoding.UTF8); + } + } +} diff --git a/Renci.SshClient/Renci.SshClient/Messages/Authentication/PasswordRequestMessage.cs b/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessagePassword.cs similarity index 88% rename from Renci.SshClient/Renci.SshClient/Messages/Authentication/PasswordRequestMessage.cs rename to Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessagePassword.cs index 52b9d1a3..2d5280a2 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Authentication/PasswordRequestMessage.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessagePassword.cs @@ -2,7 +2,7 @@ namespace Renci.SshClient.Messages.Authentication { - internal class PasswordRequestMessage : RequestMessage + internal class RequestMessagePassword : RequestMessage { public override string MethodName { diff --git a/Renci.SshClient/Renci.SshClient/Messages/Authentication/PublicKeyRequestMessage.cs b/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessagePublicKey.cs similarity index 90% rename from Renci.SshClient/Renci.SshClient/Messages/Authentication/PublicKeyRequestMessage.cs rename to Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessagePublicKey.cs index e6d97174..7a862751 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Authentication/PublicKeyRequestMessage.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Authentication/RequestMessagePublicKey.cs @@ -2,7 +2,7 @@ namespace Renci.SshClient.Messages.Authentication { - internal class PublicKeyRequestMessage : RequestMessage + internal class RequestMessagePublicKey : RequestMessage { public override string MethodName { diff --git a/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj b/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj index 115da283..d30bb143 100644 --- a/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj +++ b/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj @@ -60,13 +60,17 @@ + + + + @@ -99,6 +103,15 @@ + + Code + + + Code + + + Code + @@ -187,10 +200,7 @@ - - - @@ -246,9 +256,9 @@ - + - + Code @@ -259,6 +269,7 @@ +