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;
}
// we want to try authentication methods in the order in which they were
// passed in the ctor, not the order in which the SSH server returns
// the allowed authentication methods
var matchingAuthenticationMethods = authenticationState.SupportedAuthenticationMethods.Where(a => allowedAuthenticationMethods.Contains(a.Name)).ToList();
if (matchingAuthenticationMethods.Count == 0)
{
authenticationException = new SshAuthenticationException(string.Format("No suitable authentication method found to complete authentication ({0}).", string.Join(",", allowedAuthenticationMethods.ToArray())));
return false;
}
foreach (var authenticationMethod in GetOrderedAuthenticationMethods(authenticationState, matchingAuthenticationMethods))
{
if (authenticationState.FailedAuthenticationMethods.Contains(authenticationMethod))
continue;
// when the authentication method was previously executed, then skip the authentication
// method as long as there's another authentication method to try; this is done to avoid
// a stack overflow for servers that do not update the list of allowed authentication
// methods after a partial success
if (!authenticationState.ExecutedAuthenticationMethods.Contains(authenticationMethod))
{
// update state to reflect previosuly executed authentication methods
authenticationState.ExecutedAuthenticationMethods.Add(authenticationMethod);
}
var authenticationResult = authenticationMethod.Authenticate(session);
switch (authenticationResult)
{
case AuthenticationResult.PartialSuccess:
if (TryAuthenticate(session, authenticationState, authenticationMethod.AllowedAuthentications, ref authenticationException))
{
authenticationResult = AuthenticationResult.Success;
}
break;
case AuthenticationResult.Failure:
authenticationState.FailedAuthenticationMethods.Add(authenticationMethod);
authenticationException = new SshAuthenticationException(string.Format("Permission denied ({0}).", authenticationMethod.Name));
break;
case AuthenticationResult.Success:
authenticationException = null;
break;
}
if (authenticationResult == AuthenticationResult.Success)
return true;
}
return false;
}