ClientAuthentication
using Renci.SshNet.Common;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Renci.SshNet
{
internal class ClientAuthentication : IClientAuthentication
{
private class AuthenticationState
{
private readonly IList<IAuthenticationMethod> _supportedAuthenticationMethods;
public IList<IAuthenticationMethod> ExecutedAuthenticationMethods { get; set; }
public IList<IAuthenticationMethod> FailedAuthenticationMethods { get; set; }
public IEnumerable<IAuthenticationMethod> SupportedAuthenticationMethods => _supportedAuthenticationMethods;
public AuthenticationState(IList<IAuthenticationMethod> supportedAuthenticationMethods)
{
_supportedAuthenticationMethods = supportedAuthenticationMethods;
ExecutedAuthenticationMethods = new List<IAuthenticationMethod>();
FailedAuthenticationMethods = new List<IAuthenticationMethod>();
}
}
public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session)
{
if (connectionInfo == null)
throw new ArgumentNullException("connectionInfo");
if (session == null)
throw new ArgumentNullException("session");
session.RegisterMessage("SSH_MSG_USERAUTH_FAILURE");
session.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS");
session.RegisterMessage("SSH_MSG_USERAUTH_BANNER");
session.UserAuthenticationBannerReceived += connectionInfo.UserAuthenticationBannerReceived;
try {
SshAuthenticationException authenticationException = null;
IAuthenticationMethod authenticationMethod = connectionInfo.CreateNoneAuthenticationMethod();
if (authenticationMethod.Authenticate(session) != 0 && !TryAuthenticate(session, new AuthenticationState(connectionInfo.AuthenticationMethods), authenticationMethod.AllowedAuthentications.ToList(), ref authenticationException))
throw authenticationException;
} finally {
session.UserAuthenticationBannerReceived -= connectionInfo.UserAuthenticationBannerReceived;
session.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE");
session.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS");
session.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER");
}
}
private static bool TryAuthenticate(ISession session, AuthenticationState authenticationState, ICollection<string> allowedAuthenticationMethods, ref SshAuthenticationException authenticationException)
{
if (allowedAuthenticationMethods.Count == 0) {
authenticationException = new SshAuthenticationException("No authentication methods defined on SSH server.");
return false;
}
List<IAuthenticationMethod> list = (from a in authenticationState.SupportedAuthenticationMethods
where allowedAuthenticationMethods.Contains(a.Name)
select a).ToList();
if (list.Count == 0) {
authenticationException = new SshAuthenticationException(string.Format("No suitable authentication method found to complete authentication ({0}).", string.Join(",", allowedAuthenticationMethods.ToArray())));
return false;
}
foreach (IAuthenticationMethod orderedAuthenticationMethod in GetOrderedAuthenticationMethods(authenticationState, list)) {
if (!authenticationState.FailedAuthenticationMethods.Contains(orderedAuthenticationMethod)) {
if (!authenticationState.ExecutedAuthenticationMethods.Contains(orderedAuthenticationMethod))
authenticationState.ExecutedAuthenticationMethods.Add(orderedAuthenticationMethod);
AuthenticationResult authenticationResult = orderedAuthenticationMethod.Authenticate(session);
switch (authenticationResult) {
case AuthenticationResult.PartialSuccess:
if (TryAuthenticate(session, authenticationState, orderedAuthenticationMethod.AllowedAuthentications, ref authenticationException))
authenticationResult = AuthenticationResult.Success;
break;
case AuthenticationResult.Failure:
authenticationState.FailedAuthenticationMethods.Add(orderedAuthenticationMethod);
authenticationException = new SshAuthenticationException($"""{orderedAuthenticationMethod.Name}""");
break;
case AuthenticationResult.Success:
authenticationException = null;
break;
}
if (authenticationResult == AuthenticationResult.Success)
return true;
}
}
return false;
}
private static IEnumerable<IAuthenticationMethod> GetOrderedAuthenticationMethods(AuthenticationState authenticationState, IEnumerable<IAuthenticationMethod> matchingAuthenticationMethods)
{
List<IAuthenticationMethod> skippedAuthenticationMethods = new List<IAuthenticationMethod>();
foreach (IAuthenticationMethod matchingAuthenticationMethod in matchingAuthenticationMethods) {
if (authenticationState.ExecutedAuthenticationMethods.Contains(matchingAuthenticationMethod))
skippedAuthenticationMethods.Add(matchingAuthenticationMethod);
else
yield return matchingAuthenticationMethod;
}
List<IAuthenticationMethod>.Enumerator enumerator2 = skippedAuthenticationMethods.GetEnumerator();
try {
while (enumerator2.MoveNext()) {
IAuthenticationMethod current2 = enumerator2.Current;
yield return current2;
}
} finally {
((IDisposable)enumerator2).Dispose();
}
enumerator2 = default(List<IAuthenticationMethod>.Enumerator);
}
}
}