diff --git a/Renci.SshClient/Renci.SshClient/KeyFile.cs b/Renci.SshClient/Renci.SshClient/KeyFile.cs
index 39b6f401..f1049764 100644
--- a/Renci.SshClient/Renci.SshClient/KeyFile.cs
+++ b/Renci.SshClient/Renci.SshClient/KeyFile.cs
@@ -131,7 +131,7 @@ namespace Renci.SshClient
throw new NotSupportedException(string.Format("Key '{0}' is not supported.", keyName));
}
- this._key.Load(System.Convert.FromBase64String(data.ToString()), passPhrase.GetSshBytes());
+ this._key.Load(System.Convert.FromBase64String(data.ToString()), passPhrase);
}
public void Open(string fileName)
diff --git a/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj b/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj
index 780b505e..ffc5b634 100644
--- a/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj
+++ b/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj
@@ -121,10 +121,11 @@
-
-
-
-
+
+
+
+
+
@@ -189,9 +190,6 @@
-
-
-
@@ -201,6 +199,7 @@
+
diff --git a/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKey.cs b/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKey.cs
index db2fdb67..12f930a5 100644
--- a/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKey.cs
+++ b/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKey.cs
@@ -10,7 +10,7 @@ namespace Renci.SshClient.Security
this.Load(data, null);
}
- public abstract void Load(IEnumerable data, IEnumerable passPhrase);
+ public abstract void Load(IEnumerable data, string passPhrase);
public abstract CryptoPublicKey GetPublicKey();
diff --git a/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyDss.cs b/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyDss.cs
index 45535191..03f3c577 100644
--- a/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyDss.cs
+++ b/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyDss.cs
@@ -19,7 +19,7 @@ namespace Renci.SshClient.Security
get { return "ssh-dss"; }
}
- public override void Load(IEnumerable data, IEnumerable passPhrase)
+ public override void Load(IEnumerable data, string passPhrase)
{
if (passPhrase != null)
{
@@ -68,7 +68,7 @@ namespace Renci.SshClient.Security
public override CryptoPublicKey GetPublicKey()
{
- return new CryptoPublicKeyDss();
+ return new CryptoPublicKeyDss(this._p, this._q, this._g, this._x);
}
public override IEnumerable GetSignature(IEnumerable key)
@@ -90,7 +90,7 @@ namespace Renci.SshClient.Security
var DSA = new System.Security.Cryptography.DSACryptoServiceProvider();
DSA.ImportParameters(DSAKeyInfo);
- var DSAFormatter = new RSAPKCS1SignatureFormatter(DSA);
+ var DSAFormatter = new DSASignatureFormatter(DSA);
DSAFormatter.SetHashAlgorithm("SHA1");
var signature = DSAFormatter.CreateSignature(sha1);
diff --git a/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyRsa.cs b/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyRsa.cs
index 89beb8be..3f3a566c 100644
--- a/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyRsa.cs
+++ b/Renci.SshClient/Renci.SshClient/Security/CryptoPrivateKeyRsa.cs
@@ -22,7 +22,7 @@ namespace Renci.SshClient.Security
get { return "ssh-rsa"; }
}
- public override void Load(IEnumerable data, IEnumerable passPhrase)
+ public override void Load(IEnumerable data, string passPhrase)
{
if (passPhrase != null)
{
@@ -92,14 +92,14 @@ namespace Renci.SshClient.Security
{
RSAParameters RSAKeyInfo = new RSAParameters();
- RSAKeyInfo.Exponent = _exponent.TrimLeadinZero().ToArray();
- RSAKeyInfo.D = _dValue.TrimLeadinZero().ToArray();
- RSAKeyInfo.Modulus = _modulus.TrimLeadinZero().ToArray();
- RSAKeyInfo.P = _pValue.TrimLeadinZero().ToArray();
- RSAKeyInfo.Q = _qValue.TrimLeadinZero().ToArray();
- RSAKeyInfo.DP = _dpValue.TrimLeadinZero().ToArray();
- RSAKeyInfo.DQ = _dqValue.TrimLeadinZero().ToArray();
- RSAKeyInfo.InverseQ = _inverseQ.TrimLeadinZero().ToArray();
+ RSAKeyInfo.Exponent = this._exponent.TrimLeadinZero().ToArray();
+ RSAKeyInfo.D = this._dValue.TrimLeadinZero().ToArray();
+ RSAKeyInfo.Modulus = this._modulus.TrimLeadinZero().ToArray();
+ RSAKeyInfo.P = this._pValue.TrimLeadinZero().ToArray();
+ RSAKeyInfo.Q = this._qValue.TrimLeadinZero().ToArray();
+ RSAKeyInfo.DP = this._dpValue.TrimLeadinZero().ToArray();
+ RSAKeyInfo.DQ = this._dqValue.TrimLeadinZero().ToArray();
+ RSAKeyInfo.InverseQ = this._inverseQ.TrimLeadinZero().ToArray();
cs.Write(data, 0, data.Length);
diff --git a/Renci.SshClient/Renci.SshClient/Security/CryptoPublicKeyDss.cs b/Renci.SshClient/Renci.SshClient/Security/CryptoPublicKeyDss.cs
index 2d0edca3..925318a2 100644
--- a/Renci.SshClient/Renci.SshClient/Security/CryptoPublicKeyDss.cs
+++ b/Renci.SshClient/Renci.SshClient/Security/CryptoPublicKeyDss.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
+using Renci.SshClient.Common;
namespace Renci.SshClient.Security
{
@@ -111,7 +112,38 @@ namespace Renci.SshClient.Security
public override IEnumerable GetBytes()
{
- throw new NotImplementedException();
+ return new DsaPublicKeyData
+ {
+ P = this._p,
+ Q = this._q,
+ G = this._g,
+ Public = this._x,
+ }.GetBytes();
}
+
+ private class DsaPublicKeyData : SshData
+ {
+ public IEnumerable P { get; set; }
+
+ public IEnumerable Q { get; set; }
+
+ public IEnumerable G { get; set; }
+
+ public IEnumerable Public { get; set; }
+
+ protected override void LoadData()
+ {
+ }
+
+ protected override void SaveData()
+ {
+ this.Write("ssh-dss");
+ this.Write(this.P.GetSshString());
+ this.Write(this.Q.GetSshString());
+ this.Write(this.G.GetSshString());
+ this.Write(this.Public.GetSshString());
+ }
+ }
+
}
}
diff --git a/Renci.SshClient/Renci.SshClient/Security/UserAuthentication.cs b/Renci.SshClient/Renci.SshClient/Security/UserAuthentication.cs
new file mode 100644
index 00000000..5e758326
--- /dev/null
+++ b/Renci.SshClient/Renci.SshClient/Security/UserAuthentication.cs
@@ -0,0 +1,65 @@
+using Renci.SshClient.Messages;
+using Renci.SshClient.Messages.Authentication;
+
+namespace Renci.SshClient.Security
+{
+ internal abstract class UserAuthentication
+ {
+ public abstract string Name { get; }
+
+ public bool IsAuthenticated { get; private set; }
+
+ public string ErrorMessage { get; private set; }
+
+ protected Session Session { get; private set; }
+
+ public UserAuthentication(Session session)
+ {
+ this.Session = session;
+ }
+
+ ///
+ /// Executes this instance.
+ ///
+ /// true if method was execute; otherwise false.
+ public bool Execute()
+ {
+ Message.RegisterMessageType(MessageTypes.UserAuthenticationFailure);
+ Message.RegisterMessageType(MessageTypes.UserAuthenticationSuccess);
+ Message.RegisterMessageType(MessageTypes.UserAuthenticationBanner);
+
+ this.Session.MessageReceived += Session_MessageReceived;
+
+ var result = this.Run();
+
+ this.Session.MessageReceived -= Session_MessageReceived;
+
+ Message.UnRegisterMessageType(MessageTypes.UserAuthenticationFailure);
+ Message.UnRegisterMessageType(MessageTypes.UserAuthenticationSuccess);
+ Message.UnRegisterMessageType(MessageTypes.UserAuthenticationBanner);
+
+ return result;
+ }
+
+ protected abstract bool Run();
+
+ protected abstract void HandleMessage(T message) where T : Message;
+
+ protected virtual void HandleMessage(SuccessMessage message)
+ {
+ this.IsAuthenticated = true;
+ }
+
+ protected virtual void HandleMessage(FailureMessage message)
+ {
+ this.ErrorMessage = message.Message;
+ this.IsAuthenticated = false;
+ }
+
+ private void Session_MessageReceived(object sender, Common.MessageReceivedEventArgs e)
+ {
+ dynamic message = e.Message;
+ this.HandleMessage(message);
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationHost.cs b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationHost.cs
similarity index 62%
rename from Renci.SshClient/Renci.SshClient/Services/UserAuthenticationHost.cs
rename to Renci.SshClient/Renci.SshClient/Security/UserAuthenticationHost.cs
index 44e1bb29..30f4cbb5 100644
--- a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationHost.cs
+++ b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationHost.cs
@@ -1,4 +1,4 @@
-namespace Renci.SshClient.Services
+namespace Renci.SshClient.Security
{
internal class UserAuthenticationHost : UserAuthentication
{
@@ -15,7 +15,12 @@
}
- public override bool Start()
+ protected override bool Run()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ protected override void HandleMessage(T message)
{
throw new System.NotImplementedException();
}
diff --git a/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationNone.cs b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationNone.cs
new file mode 100644
index 00000000..c2e64e6e
--- /dev/null
+++ b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationNone.cs
@@ -0,0 +1,51 @@
+using System.Threading;
+using Renci.SshClient.Messages;
+using Renci.SshClient.Messages.Authentication;
+
+namespace Renci.SshClient.Security
+{
+ internal class UserAuthenticationNone : UserAuthentication
+ {
+ private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false);
+
+ public override string Name
+ {
+ get { return "none"; }
+ }
+
+ public UserAuthenticationNone(Session session)
+ : base(session)
+ {
+
+ }
+
+ protected override bool Run()
+ {
+ this.Session.SendMessage(new RequestMessage
+ {
+ ServiceName = ServiceNames.Connection,
+ Username = this.Session.ConnectionInfo.Username,
+ });
+
+ this.Session.WaitHandle(this._authenticationCompleted);
+
+ return true;
+ }
+
+ protected override void HandleMessage(T message)
+ {
+ }
+
+ protected override void HandleMessage(SuccessMessage message)
+ {
+ base.HandleMessage(message);
+ this._authenticationCompleted.Set();
+ }
+
+ protected override void HandleMessage(FailureMessage message)
+ {
+ base.HandleMessage(message);
+ this._authenticationCompleted.Set();
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationPassword.cs b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationPassword.cs
new file mode 100644
index 00000000..5c7b8a18
--- /dev/null
+++ b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationPassword.cs
@@ -0,0 +1,62 @@
+using System.Threading;
+using Renci.SshClient.Messages;
+using Renci.SshClient.Messages.Authentication;
+
+namespace Renci.SshClient.Security
+{
+ internal class UserAuthenticationPassword : UserAuthentication
+ {
+ private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false);
+
+ public override string Name
+ {
+ get
+ {
+ return "password";
+ }
+ }
+
+ public UserAuthenticationPassword(Session session)
+ : base(session)
+ {
+
+ }
+
+ protected override bool Run()
+ {
+ // TODO: Handle all user authentication messages
+ //Message.RegisterMessageType(MessageTypes.UserAuthenticationPasswordChangeRequired);
+
+ if (string.IsNullOrEmpty(this.Session.ConnectionInfo.Password))
+ return false;
+
+ this.Session.SendMessage(new PasswordRequestMessage
+ {
+ ServiceName = ServiceNames.Connection,
+ Username = this.Session.ConnectionInfo.Username,
+ Password = this.Session.ConnectionInfo.Password,
+ });
+
+ this.Session.WaitHandle(this._authenticationCompleted);
+
+ return true;
+ }
+
+ protected override void HandleMessage(T message)
+ {
+ // TODO: Handle password specific messages
+ }
+
+ protected override void HandleMessage(SuccessMessage message)
+ {
+ base.HandleMessage(message);
+ this._authenticationCompleted.Set();
+ }
+
+ protected override void HandleMessage(FailureMessage message)
+ {
+ base.HandleMessage(message);
+ this._authenticationCompleted.Set();
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationPublicKey.cs b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationPublicKey.cs
new file mode 100644
index 00000000..19db474a
--- /dev/null
+++ b/Renci.SshClient/Renci.SshClient/Security/UserAuthenticationPublicKey.cs
@@ -0,0 +1,109 @@
+using System.Threading;
+using Renci.SshClient.Common;
+using Renci.SshClient.Messages;
+using Renci.SshClient.Messages.Authentication;
+
+namespace Renci.SshClient.Security
+{
+ internal class UserAuthenticationPublicKey : UserAuthentication
+ {
+ private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false);
+
+ public override string Name
+ {
+ get
+ {
+ return "publickey";
+ }
+ }
+
+ public UserAuthenticationPublicKey(Session session)
+ : base(session)
+ {
+
+ }
+
+ protected override bool Run()
+ {
+ if (this.Session.ConnectionInfo.KeyFile == null)
+ return false;
+
+ Message.RegisterMessageType(MessageTypes.UserAuthenticationInformationRequest);
+
+
+ // TODO: Complete full public key implemention which includes other messages
+ var message = new PublicKeyRequestMessage
+ {
+ ServiceName = ServiceNames.Connection,
+ Username = this.Session.ConnectionInfo.Username,
+ PublicKeyAlgorithmName = this.Session.ConnectionInfo.KeyFile.AlgorithmName,
+ PublicKeyData = this.Session.ConnectionInfo.KeyFile.PublicKey,
+ Signature = new byte[] { },
+ //Signature = this.Session.ConnectionInfo.KeyFile.GetSignature(this.Session.SessionId),
+ };
+
+ var signatureData = new SignatureData(message, this.Session.SessionId.GetSshString()).GetBytes();
+
+ var signature = this.Session.ConnectionInfo.KeyFile.GetSignature(signatureData);
+
+ message.Signature = signature;
+
+ this.Session.SendMessage(message);
+
+ this.Session.WaitHandle(this._authenticationCompleted);
+
+ Message.UnRegisterMessageType(MessageTypes.UserAuthenticationInformationRequest);
+
+
+ return true;
+ }
+
+ protected override void HandleMessage(T message)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ protected override void HandleMessage(SuccessMessage message)
+ {
+ base.HandleMessage(message);
+ this._authenticationCompleted.Set();
+ }
+
+ protected override void HandleMessage(FailureMessage message)
+ {
+ base.HandleMessage(message);
+ this._authenticationCompleted.Set();
+ }
+
+ private class SignatureData : SshData
+ {
+
+ private PublicKeyRequestMessage _message;
+
+ private string _sessionId;
+
+ public SignatureData(PublicKeyRequestMessage message, string sessionId)
+ {
+ this._message = message;
+ this._sessionId = sessionId;
+ }
+
+ protected override void LoadData()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ protected override void SaveData()
+ {
+ this.Write(this._sessionId);
+ this.Write((byte)this._message.MessageType);
+ this.Write(this._message.Username);
+ this.Write("ssh-connection");
+ this.Write("publickey");
+ this.Write((byte)1);
+ this.Write(this._message.PublicKeyAlgorithmName);
+ this.Write(this._message.PublicKeyData.GetSshString());
+ }
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshClient/Services/ConnectionService.cs b/Renci.SshClient/Renci.SshClient/Services/ConnectionService.cs
deleted file mode 100644
index 8719d78e..00000000
--- a/Renci.SshClient/Renci.SshClient/Services/ConnectionService.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using Renci.SshClient.Messages;
-
-namespace Renci.SshClient.Services
-{
- internal class ConnectionService : Service
- {
- public override ServiceNames ServiceName
- {
- get { throw new NotImplementedException(); }
- }
-
- public ConnectionService(Session session)
- : base(session)
- {
-
- }
- }
-}
diff --git a/Renci.SshClient/Renci.SshClient/Services/Service.cs b/Renci.SshClient/Renci.SshClient/Services/Service.cs
deleted file mode 100644
index 23ebe0fb..00000000
--- a/Renci.SshClient/Renci.SshClient/Services/Service.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Renci.SshClient.Messages;
-
-namespace Renci.SshClient.Services
-{
- internal abstract class Service
- {
- public abstract ServiceNames ServiceName { get; }
-
- protected Session Session { get; private set; }
-
- public Service(Session session)
- {
- this.Session = session;
- }
-
- protected void SendMessage(Message message)
- {
- this.Session.SendMessage(message);
- }
-
- }
-}
diff --git a/Renci.SshClient/Renci.SshClient/Services/UserAuthentication.cs b/Renci.SshClient/Renci.SshClient/Services/UserAuthentication.cs
deleted file mode 100644
index ba2e2907..00000000
--- a/Renci.SshClient/Renci.SshClient/Services/UserAuthentication.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Renci.SshClient.Messages;
-
-namespace Renci.SshClient.Services
-{
- internal abstract class UserAuthentication
- {
- public abstract string Name { get; }
-
- protected Session Session { get; private set; }
-
- public UserAuthentication(Session session)
- {
- this.Session = session;
- }
-
- public abstract bool Start();
-
- protected void SendMessage(Message message)
- {
- this.Session.SendMessage(message);
- }
-
- }
-}
diff --git a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationPassword.cs b/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationPassword.cs
deleted file mode 100644
index 546806fb..00000000
--- a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationPassword.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Renci.SshClient.Messages;
-using Renci.SshClient.Messages.Authentication;
-
-namespace Renci.SshClient.Services
-{
- internal class UserAuthenticationPassword : UserAuthentication
- {
- public override string Name
- {
- get
- {
- return "password";
- }
- }
-
- public UserAuthenticationPassword(Session session)
- : base(session)
- {
-
- }
-
- public override bool Start()
- {
- // TODO: Handle all user authentication messages
- //Message.RegisterMessageType(MessageTypes.UserAuthenticationPasswordChangeRequired);
-
- if (!string.IsNullOrEmpty(this.Session.ConnectionInfo.Password))
- {
- this.SendMessage(new PasswordRequestMessage
- {
- ServiceName = ServiceNames.Connection,
- Username = this.Session.ConnectionInfo.Username,
- Password = this.Session.ConnectionInfo.Password,
- });
- return true;
- }
- return false;
- }
- }
-}
diff --git a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationPublicKey.cs b/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationPublicKey.cs
deleted file mode 100644
index c68aef7a..00000000
--- a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationPublicKey.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Renci.SshClient.Messages;
-using Renci.SshClient.Messages.Authentication;
-
-namespace Renci.SshClient.Services
-{
- internal class UserAuthenticationPublicKey : UserAuthentication
- {
- public override string Name
- {
- get
- {
- return "publickey";
- }
- }
-
- public UserAuthenticationPublicKey(Session session)
- : base(session)
- {
-
- }
-
-
- public override bool Start()
- {
- if (this.Session.ConnectionInfo.KeyFile != null)
- {
- // TODO: Complete full public key implemention which includes other messages
- this.SendMessage(new PublicKeyRequestMessage
- {
- ServiceName = ServiceNames.Connection,
- Username = this.Session.ConnectionInfo.Username,
- PublicKeyAlgorithmName = this.Session.ConnectionInfo.KeyFile.AlgorithmName,
- PublicKeyData = this.Session.ConnectionInfo.KeyFile.PublicKey,
- Signature = this.Session.ConnectionInfo.KeyFile.GetSignature(this.Session.SessionId),
- });
- return true;
- }
- return false;
- }
- }
-}
diff --git a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationService.cs b/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationService.cs
deleted file mode 100644
index bc903553..00000000
--- a/Renci.SshClient/Renci.SshClient/Services/UserAuthenticationService.cs
+++ /dev/null
@@ -1,155 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using Renci.SshClient.Common;
-using Renci.SshClient.Messages;
-using Renci.SshClient.Messages.Authentication;
-using Renci.SshClient.Messages.Transport;
-using Renci.SshClient.Security;
-
-namespace Renci.SshClient.Services
-{
- internal class UserAuthenticationService : Service
- {
- private IList _executedMethods = new List();
-
- private EventWaitHandle _serviceAccepted = new AutoResetEvent(false);
-
- private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false);
-
- public override ServiceNames ServiceName
- {
- get { return ServiceNames.UserAuthentication; }
- }
-
- public EventWaitHandle AuthenticationCompletedHandle { get; private set; }
-
- public string ErrorMessage { get; private set; }
-
- public bool IsAuthenticated { get; private set; }
-
- public UserAuthenticationService(Session session)
- : base(session)
- {
- this.AuthenticationCompletedHandle = new AutoResetEvent(false);
- }
-
- public void AuthenticateUser()
- {
- // Register Authentication response messages
- Message.RegisterMessageType(MessageTypes.UserAuthenticationFailure);
- Message.RegisterMessageType(MessageTypes.UserAuthenticationSuccess);
- Message.RegisterMessageType(MessageTypes.UserAuthenticationBanner);
-
- // Attach event handlers to handle messages
- this.Session.MessageReceived += SessionInfo_MessageReceived;
-
- // Request user authorization service
- this.SendMessage(new ServiceRequestMessage
- {
- ServiceName = ServiceNames.UserAuthentication,
- });
-
- // Wait for service to be accepted
- this.Session.WaitHandle(this._serviceAccepted);
-
- // Start by quering supported authentication methods
- this.SendMessage(new RequestMessage
- {
- Username = this.Session.ConnectionInfo.Username,
- ServiceName = ServiceNames.Connection,
- });
-
- // Wait for authentication to be completed
- this.Session.WaitHandle(this._authenticationCompleted);
-
- this.Session.MessageReceived -= SessionInfo_MessageReceived;
-
- Message.UnRegisterMessageType(MessageTypes.UserAuthenticationFailure);
- Message.UnRegisterMessageType(MessageTypes.UserAuthenticationSuccess);
- Message.UnRegisterMessageType(MessageTypes.UserAuthenticationBanner);
- }
-
- private void SessionInfo_MessageReceived(object sender, MessageReceivedEventArgs e)
- {
- this.HandleMessage((dynamic)e.Message);
- }
-
- private void HandleMessage(T message)
- {
- // Ignore messages that cannot be handled by this module
- }
-
- private void HandleMessage(ServiceAcceptMessage message)
- {
- if (message.ServiceName == ServiceNames.UserAuthentication)
- {
- this._serviceAccepted.Set();
- }
- }
-
- private void HandleMessage(SuccessMessage message)
- {
- this.AuthenticationSucceded();
- }
-
- private void HandleMessage(FailureMessage message)
- {
- if (message.PartialSuccess)
- {
- this.AuthenticationFailed(message.Message);
- return;
- }
-
- // Get method that was not executed yet
- var methodsToTry = message.AllowedAuthentications.Except(this._executedMethods);
-
- if (methodsToTry.Count() == 0)
- {
- this.AuthenticationFailed(string.Format("User '{0}' cannot be authorized.", this.Session.ConnectionInfo.Username));
- return;
- }
-
- // Execute authentication method
- foreach (var methodName in methodsToTry)
- {
- UserAuthentication userAuthentication = null;
-
- if (methodName == "publickey")
- {
- userAuthentication = new UserAuthenticationPublicKey(this.Session);
- }
- else if (methodName == "password")
- {
- userAuthentication = new UserAuthenticationPassword(this.Session);
- }
- this._executedMethods.Add(methodName);
- if (userAuthentication != null)
- {
- if (userAuthentication.Start())
- break;
- }
- }
- }
-
- private void HandleMessage(BannerMessage message)
- {
- }
-
- private void AuthenticationFailed(string message)
- {
- this.IsAuthenticated = false;
- this.ErrorMessage = message;
- this._authenticationCompleted.Set();
- }
-
- private void AuthenticationSucceded()
- {
- this.IsAuthenticated = true;
- this._authenticationCompleted.Set();
- }
-
-
-
- }
-}
diff --git a/Renci.SshClient/Renci.SshClient/Session.cs b/Renci.SshClient/Renci.SshClient/Session.cs
index 7873dbe1..c6304982 100644
--- a/Renci.SshClient/Renci.SshClient/Session.cs
+++ b/Renci.SshClient/Renci.SshClient/Session.cs
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
+using System.Security.Authentication;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
@@ -14,7 +15,6 @@ using Renci.SshClient.Messages;
using Renci.SshClient.Messages.Connection;
using Renci.SshClient.Messages.Transport;
using Renci.SshClient.Security;
-using Renci.SshClient.Services;
namespace Renci.SshClient
{
@@ -59,19 +59,19 @@ namespace Renci.SshClient
private Socket _socket;
- private int _waitTimeout = 5 * 1000; // Set default receive timeout to 5 seconds
-
private KeyExchange _keyExhcange;
private BackgroundWorker _messageListener;
private EventWaitHandle _keyExhangedFinishedWaitHandle = new AutoResetEvent(false);
- private IDictionary _services = new Dictionary();
+ private EventWaitHandle _serviceAccepted = new AutoResetEvent(false);
+
+ private EventWaitHandle _exceptionWaitHandle = new AutoResetEvent(false);
private IDictionary _openChannels = new Dictionary();
- private EventWaitHandle _exceptionWaitHandle = new AutoResetEvent(false);
+ private IDictionary _executedAuthenticationMethods = new Dictionary();
///
/// Exception that need to be thrown by waiting thread
@@ -83,6 +83,11 @@ namespace Renci.SshClient
///
private bool _isDisconnectByClient;
+ ///
+ /// Specifies weither connection is authenticated
+ ///
+ private bool _isAuthenticated;
+
public event EventHandler MessageReceived;
protected HMAC ServerMac { get; private set; }
@@ -195,13 +200,38 @@ namespace Renci.SshClient
return;
}
- var authenticationService = new UserAuthenticationService(this);
-
- authenticationService.AuthenticateUser();
-
- if (!authenticationService.IsAuthenticated)
+ // Request user authorization service
+ this.SendMessage(new ServiceRequestMessage
{
- throw new InvalidOperationException(string.Format("User cannot be authenticated. Reason: {0}.", authenticationService.ErrorMessage));
+ ServiceName = ServiceNames.UserAuthentication,
+ });
+
+ // Wait for service to be accepted
+ this.WaitHandle(this._serviceAccepted);
+
+ // This implemention will ignore supported by server methods and will try to authenticated user using method supported by the client.
+ string errorMessage = null; // Hold last authentication error if any
+ foreach (var methodName in Settings.SupportedAuthenticationMethods.Keys)
+ {
+ var userAuthentication = Settings.SupportedAuthenticationMethods[methodName](this);
+
+ if (userAuthentication.Execute())
+ {
+ if (userAuthentication.IsAuthenticated)
+ {
+ this._isAuthenticated = true;
+ break;
+ }
+ else
+ {
+ errorMessage = userAuthentication.ErrorMessage;
+ }
+ }
+ }
+
+ if (!this._isAuthenticated)
+ {
+ throw new AuthenticationException(errorMessage ?? "User cannot be authenticated.");
}
}
@@ -277,6 +307,7 @@ namespace Renci.SshClient
protected virtual void HandleMessage(ServiceAcceptMessage message)
{
+ this._serviceAccepted.Set();
}
protected virtual void HandleMessage(ServiceRequestMessage message)
diff --git a/Renci.SshClient/Renci.SshClient/Settings.cs b/Renci.SshClient/Renci.SshClient/Settings.cs
index 5cd5b6cd..a873cc3c 100644
--- a/Renci.SshClient/Renci.SshClient/Settings.cs
+++ b/Renci.SshClient/Renci.SshClient/Settings.cs
@@ -16,6 +16,8 @@ namespace Renci.SshClient
public static IDictionary> HostKeyAlgorithms { get; private set; }
+ public static IDictionary> SupportedAuthenticationMethods { get; private set; }
+
static Settings()
{
Settings.KeyExchangeAlgorithms = new Dictionary>()
@@ -43,6 +45,13 @@ namespace Renci.SshClient
{"ssh-rsa", () => { return new CryptoPublicKeyRsa();}},
{"ssh-dsa", () => { return new CryptoPublicKeyDss();}}, // TODO: Need to be tested
};
+
+ Settings.SupportedAuthenticationMethods = new Dictionary>()
+ {
+ {"none", (session)=> {return new UserAuthenticationNone(session);}},
+ {"publickey", (session)=> {return new UserAuthenticationPublicKey(session);}},
+ {"password", (session)=> {return new UserAuthenticationPassword(session);}},
+ };
}
}
}