ClientAuthentication
using Renci.SshNet.Common;
using System;
using System.Collections.Generic;
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 IList<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, 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, string[] allowedAuthenticationMethods, ref SshAuthenticationException authenticationException)
{
if (allowedAuthenticationMethods.Length == 0) {
authenticationException = new SshAuthenticationException("No authentication methods defined on SSH server.");
return false;
}
List<IAuthenticationMethod> allowedAuthenticationMethodsThatAreSupported = GetAllowedAuthenticationMethodsThatAreSupported(authenticationState, allowedAuthenticationMethods);
if (allowedAuthenticationMethodsThatAreSupported.Count == 0) {
authenticationException = new SshAuthenticationException(string.Format("No suitable authentication method found to complete authentication ({0}).", string.Join(",", allowedAuthenticationMethods)));
return false;
}
foreach (IAuthenticationMethod orderedAuthenticationMethod in GetOrderedAuthenticationMethods(authenticationState, allowedAuthenticationMethodsThatAreSupported)) {
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 List<IAuthenticationMethod> GetAllowedAuthenticationMethodsThatAreSupported(AuthenticationState authenticationState, string[] allowedAuthenticationMethods)
{
List<IAuthenticationMethod> list = new List<IAuthenticationMethod>();
foreach (IAuthenticationMethod supportedAuthenticationMethod in authenticationState.SupportedAuthenticationMethods) {
string name = supportedAuthenticationMethod.Name;
for (int i = 0; i < allowedAuthenticationMethods.Length; i++) {
if (allowedAuthenticationMethods[i] == name) {
list.Add(supportedAuthenticationMethod);
break;
}
}
}
return list;
}
private static IEnumerable<IAuthenticationMethod> GetOrderedAuthenticationMethods(AuthenticationState authenticationState, List<IAuthenticationMethod> matchingAuthenticationMethods)
{
List<IAuthenticationMethod> skippedAuthenticationMethods = new List<IAuthenticationMethod>();
for (int i = 0; i < matchingAuthenticationMethods.Count; i++) {
IAuthenticationMethod authenticationMethod = matchingAuthenticationMethods[i];
if (authenticationState.ExecutedAuthenticationMethods.Contains(authenticationMethod))
skippedAuthenticationMethods.Add(authenticationMethod);
else
yield return authenticationMethod;
}
List<IAuthenticationMethod>.Enumerator enumerator = skippedAuthenticationMethods.GetEnumerator();
try {
while (enumerator.MoveNext()) {
IAuthenticationMethod current = enumerator.Current;
yield return current;
}
} finally {
((IDisposable)enumerator).Dispose();
}
enumerator = default(List<IAuthenticationMethod>.Enumerator);
}
}
}