# < Summary

Information

Class: | Renci.SshNet.ClientAuthentication
Assembly: | Renci.SshNet
File(s): | \home\appveyor\projects\ssh-net\src\Renci.SshNet\ClientAuthentication.cs

Line coverage
97%

Covered lines: | 135
Uncovered lines: | 4
Coverable lines: | 139
Total lines: | 319
Line coverage: | 97.1%

Branch coverage
97%

Covered branches: | 43
Total branches: | 44
Branch coverage: | 97.7%

Method coverage

Feature is only available for sponsors

Upgrade to PRO version

# Metrics

Method | Branch coverage | Cyclomatic complexity | Line coverage
--- | --- | --- | ---
.ctor(...) | 100% | 2 | 100%
get_PartialSuccessLimit() | 100% | 1 | 100%
Authenticate(...) | 100% | 8 | 100%
TryAuthenticate(...) | 93.75% | 16 | 90.9%
.ctor(...) | 100% | 1 | 100%
RecordFailure(...) | 100% | 1 | 100%
RecordPartialSuccess(...) | 100% | 2 | 100%
GetPartialSuccessCount(...) | 100% | 2 | 100%
GetSupportedAuthenticationMethods(...) | 100% | 6 | 100%
GetActiveAuthenticationMethods() | 100% | 8 | 100%

# File(s)

## \home\appveyor\projects\ssh-net\src\Renci.SshNet\ClientAuthentication.cs

| # | Line |  | Line coverage
--- | --- | --- | --- | ---
|  | `1` |  | `using System;`
|  | `2` |  | `using System.Collections.Generic;`
|  | `3` |  | `using System.Globalization;`
|  | `4` |  | ``
|  | `5` |  | `using Renci.SshNet.Common;`
|  | `6` |  | ``
|  | `7` |  | `namespace Renci.SshNet`
|  | `8` |  | `{`
|  | `9` |  | `/// <summary>`
|  | `10` |  | `/// Represents a mechanism to authenticate a given client.`
|  | `11` |  | `/// </summary>`
|  | `12` |  | `internal sealed class ClientAuthentication : IClientAuthentication`
|  | `13` |  | `{`
|  | `14` |  | `private readonly int _partialSuccessLimit;`
|  | `15` |  | ``
|  | `16` |  | `/// <summary>`
|  | `17` |  | `/// Initializes a new instance of the <see cref="ClientAuthentication"/> class.`
|  | `18` |  | `/// </summary>`
|  | `19` |  | `/// <param name="partialSuccessLimit">The number of times an authentication attempt with any given <see cref="IA`
|  | `20` |  | `/// <exception cref="ArgumentOutOfRangeException"><paramref name="partialSuccessLimit"/> is less than one.</exce`
| 1534 | `21` |  | `public ClientAuthentication(int partialSuccessLimit)`
| 1534 | `22` |  | `{`
| 1534 | `23` |  | `if (partialSuccessLimit < 1)`
| 6 | `24` |  | `{`
| 6 | `25` |  | `throw new ArgumentOutOfRangeException(nameof(partialSuccessLimit), "Cannot be less than one.");`
|  | `26` |  | `}`
|  | `27` |  | ``
| 1528 | `28` |  | `_partialSuccessLimit = partialSuccessLimit;`
| 1528 | `29` |  | `}`
|  | `30` |  | ``
|  | `31` |  | `/// <summary>`
|  | `32` |  | `/// Gets the number of times an authentication attempt with any given <see cref="IAuthenticationMethod"/> can`
|  | `33` |  | `/// result in <see cref="AuthenticationResult.PartialSuccess"/> before it is disregarded.`
|  | `34` |  | `/// </summary>`
|  | `35` |  | `/// <value>`
|  | `36` |  | `/// The number of times an authentication attempt with any given <see cref="IAuthenticationMethod"/> can result`
|  | `37` |  | `/// in <see cref="AuthenticationResult.PartialSuccess"/> before it is disregarded.`
|  | `38` |  | `/// </value>`
|  | `39` |  | `internal int PartialSuccessLimit`
|  | `40` |  | `{`
| 27 | `41` |  | `get { return _partialSuccessLimit; }`
|  | `42` |  | `}`
|  | `43` |  | ``
|  | `44` |  | `/// <summary>`
|  | `45` |  | `/// Attempts to perform authentication for a given <see cref="ISession"/> using the`
|  | `46` |  | `/// <see cref="IConnectionInfoInternal.AuthenticationMethods"/> of the specified`
|  | `47` |  | `/// <see cref="IConnectionInfoInternal"/>.`
|  | `48` |  | `/// </summary>`
|  | `49` |  | `/// <param name="connectionInfo">A <see cref="IConnectionInfoInternal"/> to use for authenticating.</param>`
|  | `50` |  | `/// <param name="session">The <see cref="ISession"/> for which to perform authentication.</param>`
|  | `51` |  | `/// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> or <paramref name="session"/> is <`
|  | `52` |  | `/// <exception cref="SshAuthenticationException">Failed to authenticate the client.</exception>`
|  | `53` |  | `public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session)`
| 1504 | `54` |  | `{`
| 1504 | `55` |  | `if (connectionInfo is null)`
| 3 | `56` |  | `{`
| 3 | `57` |  | `throw new ArgumentNullException(nameof(connectionInfo));`
|  | `58` |  | `}`
|  | `59` |  | ``
| 1501 | `60` |  | `if (session is null)`
| 3 | `61` |  | `{`
| 3 | `62` |  | `throw new ArgumentNullException(nameof(session));`
|  | `63` |  | `}`
|  | `64` |  | ``
| 1498 | `65` |  | `session.RegisterMessage("SSH_MSG_USERAUTH_FAILURE");`
| 1498 | `66` |  | `session.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS");`
| 1498 | `67` |  | `session.RegisterMessage("SSH_MSG_USERAUTH_BANNER");`
| 1498 | `68` |  | `session.UserAuthenticationBannerReceived += connectionInfo.UserAuthenticationBannerReceived;`
|  | `69` |  | ``
|  | `70` |  | `try`
| 1498 | `71` |  | `{`
|  | `72` |  | `// the exception to report an authentication failure with`
| 1498 | `73` |  | `SshAuthenticationException authenticationException = null;`
|  | `74` |  | ``
|  | `75` |  | `// try to authenticate against none`
| 1498 | `76` |  | `var noneAuthenticationMethod = connectionInfo.CreateNoneAuthenticationMethod();`
|  | `77` |  | ``
| 1498 | `78` |  | `var authenticated = noneAuthenticationMethod.Authenticate(session);`
| 1497 | `79` |  | `if (authenticated != AuthenticationResult.Success)`
| 1497 | `80` |  | `{`
| 1497 | `81` |  | `if (!TryAuthenticate(session, new AuthenticationState(connectionInfo.AuthenticationMethods), noneAut`
| 168 | `82` |  | `{`
| 168 | `83` |  | `throw authenticationException;`
|  | `84` |  | `}`
| 1329 | `85` |  | `}`
| 1329 | `86` |  | `}`
|  | `87` |  | `finally`
| 1498 | `88` |  | `{`
| 1498 | `89` |  | `session.UserAuthenticationBannerReceived -= connectionInfo.UserAuthenticationBannerReceived;`
| 1498 | `90` |  | `session.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE");`
| 1498 | `91` |  | `session.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS");`
| 1498 | `92` |  | `session.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER");`
| 1498 | `93` |  | `}`
| 1329 | `94` |  | `}`
|  | `95` |  | ``
|  | `96` |  | `private bool TryAuthenticate(ISession session,`
|  | `97` |  | `AuthenticationState authenticationState,`
|  | `98` |  | `string[] allowedAuthenticationMethods,`
|  | `99` |  | `ref SshAuthenticationException authenticationException)`
| 2139 | `100` |  | `{`
| 2139 | `101` |  | `if (allowedAuthenticationMethods.Length == 0)`
| 0 | `102` |  | `{`
| 0 | `103` |  | `authenticationException = new SshAuthenticationException("No authentication methods defined on SSH serve`
| 0 | `104` |  | `return false;`
|  | `105` |  | `}`
|  | `106` |  | ``
|  | `107` |  | `// we want to try authentication methods in the order in which they were`
|  | `108` |  | `// passed in the ctor, not the order in which the SSH server returns`
|  | `109` |  | `// the allowed authentication methods`
| 2139 | `110` |  | `var matchingAuthenticationMethods = authenticationState.GetSupportedAuthenticationMethods(allowedAuthenticat`
| 2139 | `111` |  | `if (matchingAuthenticationMethods.Count == 0)`
| 21 | `112` |  | `{`
| 21 | `113` |  | `authenticationException = new SshAuthenticationException(string.Format(CultureInfo.InvariantCulture,`
| 21 | `114` |  | `"No suitable authentication metho`
| 21 | `115` |  | `#if NET || NETSTANDARD2_1_OR_GREATER`
| 21 | `116` |  | `string.Join(',', allowedAuthentic`
| 21 | `117` |  | `#else`
| 21 | `118` |  | `string.Join(",", allowedAuthentic`
| 21 | `119` |  | `#endif // NET || NETSTANDARD2_1_OR_GREATER`
| 21 | `120` |  | `;`
| 21 | `121` |  | `return false;`
|  | `122` |  | `}`
|  | `123` |  | ``
| 9568 | `124` |  | `foreach (var authenticationMethod in authenticationState.GetActiveAuthenticationMethods(matchingAuthenticati`
| 2354 | `125` |  | `{`
|  | `126` |  | `// guard against a stack overlow for servers that do not update the list of allowed authentication`
|  | `127` |  | `// methods after a partial success`
| 2354 | `128` |  | `if (authenticationState.GetPartialSuccessCount(authenticationMethod) >= _partialSuccessLimit)`
| 202 | `129` |  | `{`
|  | `130` |  | `/* TODO Get list of all authentication methods that have reached the partial success limit? */`
|  | `131` |  | ``
| 202 | `132` |  | `authenticationException = new SshAuthenticationException(string.Format("Reached authentication attem`
| 202 | `133` |  | `authenticationMethod.Name));`
| 202 | `134` |  | `continue;`
|  | `135` |  | `}`
|  | `136` |  | ``
| 2152 | `137` |  | `var authenticationResult = authenticationMethod.Authenticate(session);`
| 2152 | `138` |  | `switch (authenticationResult)`
|  | `139` |  | `{`
|  | `140` |  | `case AuthenticationResult.PartialSuccess:`
| 642 | `141` |  | `authenticationState.RecordPartialSuccess(authenticationMethod);`
| 642 | `142` |  | `if (TryAuthenticate(session, authenticationState, authenticationMethod.AllowedAuthentications, r`
| 165 | `143` |  | `{`
| 165 | `144` |  | `authenticationResult = AuthenticationResult.Success;`
| 165 | `145` |  | `}`
|  | `146` |  | ``
| 642 | `147` |  | `break;`
|  | `148` |  | `case AuthenticationResult.Failure:`
| 181 | `149` |  | `authenticationState.RecordFailure(authenticationMethod);`
| 181 | `150` |  | `authenticationException = new SshAuthenticationException(string.Format("Permission denied ({0}).`
| 181 | `151` |  | `break;`
|  | `152` |  | `case AuthenticationResult.Success:`
| 1329 | `153` |  | `authenticationException = null;`
| 1329 | `154` |  | `break;`
|  | `155` |  | `default:`
| 0 | `156` |  | `break;`
|  | `157` |  | `}`
|  | `158` |  | ``
| 2152 | `159` |  | `if (authenticationResult == AuthenticationResult.Success)`
| 1494 | `160` |  | `{`
| 1494 | `161` |  | `return true;`
|  | `162` |  | `}`
| 658 | `163` |  | `}`
|  | `164` |  | ``
| 624 | `165` |  | `return false;`
| 2139 | `166` |  | `}`
|  | `167` |  | ``
|  | `168` |  | `private sealed class AuthenticationState`
|  | `169` |  | `{`
|  | `170` |  | `private readonly IList<IAuthenticationMethod> _supportedAuthenticationMethods;`
|  | `171` |  | ``
|  | `172` |  | `/// <summary>`
|  | `173` |  | `/// Records if a given <see cref="IAuthenticationMethod"/> has been tried, and how many times this resulted`
|  | `174` |  | `/// in <see cref="AuthenticationResult.PartialSuccess"/>.`
|  | `175` |  | `/// </summary>`
|  | `176` |  | `/// <remarks>`
|  | `177` |  | `/// When there's no entry for a given <see cref="IAuthenticationMethod"/>, then it was never tried.`
|  | `178` |  | `/// </remarks>`
|  | `179` |  | `private readonly Dictionary<IAuthenticationMethod, int> _authenticationMethodPartialSuccessRegister;`
|  | `180` |  | ``
|  | `181` |  | `/// <summary>`
|  | `182` |  | `/// Holds the list of authentications methods that failed.`
|  | `183` |  | `/// </summary>`
|  | `184` |  | `private readonly List<IAuthenticationMethod> _failedAuthenticationMethods;`
|  | `185` |  | ``
| 1497 | `186` |  | `public AuthenticationState(IList<IAuthenticationMethod> supportedAuthenticationMethods)`
| 1497 | `187` |  | `{`
| 1497 | `188` |  | `_supportedAuthenticationMethods = supportedAuthenticationMethods;`
| 1497 | `189` |  | `_failedAuthenticationMethods = new List<IAuthenticationMethod>();`
| 1497 | `190` |  | `_authenticationMethodPartialSuccessRegister = new Dictionary<IAuthenticationMethod, int>();`
| 1497 | `191` |  | `}`
|  | `192` |  | ``
|  | `193` |  | `/// <summary>`
|  | `194` |  | `/// Records a <see cref="AuthenticationResult.Failure"/> authentication attempt for the specified`
|  | `195` |  | `/// <see cref="IAuthenticationMethod"/> .`
|  | `196` |  | `/// </summary>`
|  | `197` |  | `/// <param name="authenticationMethod">An <see cref="IAuthenticationMethod"/> for which to record the result`
|  | `198` |  | `public void RecordFailure(IAuthenticationMethod authenticationMethod)`
| 181 | `199` |  | `{`
| 181 | `200` |  | `_failedAuthenticationMethods.Add(authenticationMethod);`
| 181 | `201` |  | `}`
|  | `202` |  | ``
|  | `203` |  | `/// <summary>`
|  | `204` |  | `/// Records a <see cref="AuthenticationResult.PartialSuccess"/> authentication attempt for the specified`
|  | `205` |  | `/// <see cref="IAuthenticationMethod"/> .`
|  | `206` |  | `/// </summary>`
|  | `207` |  | `/// <param name="authenticationMethod">An <see cref="IAuthenticationMethod"/> for which to record the result`
|  | `208` |  | `public void RecordPartialSuccess(IAuthenticationMethod authenticationMethod)`
| 642 | `209` |  | `{`
| 642 | `210` |  | `if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var partialSuccess`
| 223 | `211` |  | `{`
| 223 | `212` |  | `_authenticationMethodPartialSuccessRegister[authenticationMethod] = partialSuccessCount + 1;`
| 223 | `213` |  | `}`
|  | `214` |  | `else`
| 419 | `215` |  | `{`
| 419 | `216` |  | `_authenticationMethodPartialSuccessRegister.Add(authenticationMethod, 1);`
| 419 | `217` |  | `}`
| 642 | `218` |  | `}`
|  | `219` |  | ``
|  | `220` |  | `/// <summary>`
|  | `221` |  | `/// Returns the number of times an authentication attempt with the specified <see cref="IAuthenticationMetho`
|  | `222` |  | `/// has resulted in <see cref="AuthenticationResult.PartialSuccess"/>.`
|  | `223` |  | `/// </summary>`
|  | `224` |  | `/// <param name="authenticationMethod">An <see cref="IAuthenticationMethod"/>.</param>`
|  | `225` |  | `/// <returns>`
|  | `226` |  | `/// The number of times an authentication attempt with the specified <see cref="IAuthenticationMethod"/>`
|  | `227` |  | `/// has resulted in <see cref="AuthenticationResult.PartialSuccess"/>.`
|  | `228` |  | `/// </returns>`
|  | `229` |  | `public int GetPartialSuccessCount(IAuthenticationMethod authenticationMethod)`
| 2354 | `230` |  | `{`
| 2354 | `231` |  | `if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var partialSuccess`
| 516 | `232` |  | `{`
| 516 | `233` |  | `return partialSuccessCount;`
|  | `234` |  | `}`
|  | `235` |  | ``
| 1838 | `236` |  | `return 0;`
| 2354 | `237` |  | `}`
|  | `238` |  | ``
|  | `239` |  | `/// <summary>`
|  | `240` |  | `/// Returns a list of supported authentication methods that match one of the specified allowed authenticatio`
|  | `241` |  | `/// methods.`
|  | `242` |  | `/// </summary>`
|  | `243` |  | `/// <param name="allowedAuthenticationMethods">A list of allowed authentication methods.</param>`
|  | `244` |  | `/// <returns>`
|  | `245` |  | `/// A list of supported authentication methods that match one of the specified allowed authentication method`
|  | `246` |  | `/// </returns>`
|  | `247` |  | `/// <remarks>`
|  | `248` |  | `/// The authentication methods are returned in the order in which they were specified in the list that was`
|  | `249` |  | `/// used to initialize the current <see cref="AuthenticationState"/> instance.`
|  | `250` |  | `/// </remarks>`
|  | `251` |  | `public List<IAuthenticationMethod> GetSupportedAuthenticationMethods(string[] allowedAuthenticationMethods)`
| 2139 | `252` |  | `{`
| 2139 | `253` |  | `var result = new List<IAuthenticationMethod>();`
|  | `254` |  | ``
| 13761 | `255` |  | `foreach (var supportedAuthenticationMethod in _supportedAuthenticationMethods)`
| 3672 | `256` |  | `{`
| 3672 | `257` |  | `var nameOfSupportedAuthenticationMethod = supportedAuthenticationMethod.Name;`
|  | `258` |  | ``
| 12028 | `259` |  | `for (var i = 0; i < allowedAuthenticationMethods.Length; i++)`
| 4808 | `260` |  | `{`
| 4808 | `261` |  | `if (allowedAuthenticationMethods[i] == nameOfSupportedAuthenticationMethod)`
| 2466 | `262` |  | `{`
| 2466 | `263` |  | `result.Add(supportedAuthenticationMethod);`
| 2466 | `264` |  | `break;`
|  | `265` |  | `}`
| 2342 | `266` |  | `}`
| 3672 | `267` |  | `}`
|  | `268` |  | ``
| 2139 | `269` |  | `return result;`
| 2139 | `270` |  | `}`
|  | `271` |  | ``
|  | `272` |  | `/// <summary>`
|  | `273` |  | `/// Returns the authentication methods from the specified list that have not yet failed.`
|  | `274` |  | `/// </summary>`
|  | `275` |  | `/// <param name="matchingAuthenticationMethods">A list of authentication methods.</param>`
|  | `276` |  | `/// <returns>`
|  | `277` |  | `/// The authentication methods from <paramref name="matchingAuthenticationMethods"/> that have not yet faile`
|  | `278` |  | `/// </returns>`
|  | `279` |  | `/// <remarks>`
|  | `280` |  | `/// <para>`
|  | `281` |  | `/// This method first returns the authentication methods that have not yet been executed, and only then`
|  | `282` |  | `/// returns those for which an authentication attempt resulted in a <see cref="AuthenticationResult.PartialS`
|  | `283` |  | `/// </para>`
|  | `284` |  | `/// <para>`
|  | `285` |  | `/// Any <see cref="IAuthenticationMethod"/> that has failed is skipped.`
|  | `286` |  | `/// </para>`
|  | `287` |  | `/// </remarks>`
|  | `288` |  | `public IEnumerable<IAuthenticationMethod> GetActiveAuthenticationMethods(List<IAuthenticationMethod> matchin`
| 2118 | `289` |  | `{`
| 2118 | `290` |  | `var skippedAuthenticationMethods = new List<IAuthenticationMethod>();`
|  | `291` |  | ``
| 6242 | `292` |  | `for (var i = 0; i < matchingAuthenticationMethods.Count; i++)`
| 2409 | `293` |  | `{`
| 2409 | `294` |  | `var authenticationMethod = matchingAuthenticationMethods[i];`
|  | `295` |  | ``
|  | `296` |  | `// skip authentication methods that have already failed`
| 2409 | `297` |  | `if (_failedAuthenticationMethods.Contains(authenticationMethod))`
| 1 | `298` |  | `{`
| 1 | `299` |  | `continue;`
|  | `300` |  | `}`
|  | `301` |  | ``
|  | `302` |  | `// delay use of authentication methods that had a PartialSuccess result`
| 2408 | `303` |  | `if (_authenticationMethodPartialSuccessRegister.ContainsKey(authenticationMethod))`
| 570 | `304` |  | `{`
| 570 | `305` |  | `skippedAuthenticationMethods.Add(authenticationMethod);`
| 570 | `306` |  | `continue;`
|  | `307` |  | `}`
|  | `308` |  | ``
| 1838 | `309` |  | `yield return authenticationMethod;`
| 432 | `310` |  | `}`
|  | `311` |  | ``
| 3080 | `312` |  | `foreach (var authenticationMethod in skippedAuthenticationMethods)`
| 516 | `313` |  | `{`
| 516 | `314` |  | `yield return authenticationMethod;`
| 428 | `315` |  | `}`
| 624 | `316` |  | `}`
|  | `317` |  | `}`
|  | `318` |  | `}`
|  | `319` |  | `}`

# Methods/Properties

.ctor(System.Int32)
get_PartialSuccessLimit()
Authenticate(Renci.SshNet.IConnectionInfoInternal,Renci.SshNet.ISession)
TryAuthenticate(Renci.SshNet.ISession,Renci.SshNet.ClientAuthentication/AuthenticationState,System.String[],Renci.SshNet.Common.SshAuthenticationException&)
.ctor(System.Collections.Generic.IList`1<Renci.SshNet.IAuthenticationMethod>)
RecordFailure(Renci.SshNet.IAuthenticationMethod)
RecordPartialSuccess(Renci.SshNet.IAuthenticationMethod)
GetPartialSuccessCount(Renci.SshNet.IAuthenticationMethod)
GetSupportedAuthenticationMethods(System.String[])
GetActiveAuthenticationMethods()