< Summary

Information
Class: Renci.SshNet.PrivateKeyAuthenticationMethod
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\PrivateKeyAuthenticationMethod.cs
Line coverage
87%
Covered lines: 118
Uncovered lines: 17
Coverable lines: 135
Total lines: 261
Line coverage: 87.4%
Branch coverage
80%
Covered branches: 16
Total branches: 20
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%2100%
get_Name()100%1100%
get_KeyFiles()100%1100%
Authenticate(...)100%10100%
Session_UserAuthenticationSuccessReceived(...)100%1100%
Session_UserAuthenticationFailureReceived(...)100%2100%
Session_UserAuthenticationPublicKeyReceived(...)100%1100%
Dispose()100%10%
Dispose(...)33.33%626.66%
Finalize()100%1100%
get_BufferCapacity()100%1100%
.ctor(...)100%1100%
LoadData()100%10%
SaveData()100%1100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Collections.ObjectModel;
 4using System.Linq;
 5using System.Threading;
 6
 7using Renci.SshNet.Common;
 8using Renci.SshNet.Messages;
 9using Renci.SshNet.Messages.Authentication;
 10
 11namespace Renci.SshNet
 12{
 13    /// <summary>
 14    /// Provides functionality to perform private key authentication.
 15    /// </summary>
 16    public class PrivateKeyAuthenticationMethod : AuthenticationMethod, IDisposable
 17    {
 41918        private AuthenticationResult _authenticationResult = AuthenticationResult.Failure;
 41919        private EventWaitHandle _authenticationCompleted = new ManualResetEvent(initialState: false);
 20#pragma warning disable S1450 // Private fields only used as local variables in methods should become local variables
 21        private bool _isSignatureRequired;
 22#pragma warning restore S1450 // Private fields only used as local variables in methods should become local variables
 23        private bool _isDisposed;
 24
 25        /// <summary>
 26        /// Gets the name of the authentication method.
 27        /// </summary>
 28        public override string Name
 29        {
 207630            get { return "publickey"; }
 31        }
 32
 33        /// <summary>
 34        /// Gets the key files used for authentication.
 35        /// </summary>
 111636        public ICollection<IPrivateKeySource> KeyFiles { get; private set; }
 37
 38        /// <summary>
 39        /// Initializes a new instance of the <see cref="PrivateKeyAuthenticationMethod"/> class.
 40        /// </summary>
 41        /// <param name="username">The username.</param>
 42        /// <param name="keyFiles">The key files.</param>
 43        /// <exception cref="ArgumentException"><paramref name="username"/> is whitespace or <see langword="null"/>.</ex
 44        public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles)
 41945            : base(username)
 41346        {
 41347            if (keyFiles is null)
 348            {
 349                throw new ArgumentNullException(nameof(keyFiles));
 50            }
 51
 41052            KeyFiles = new Collection<IPrivateKeySource>(keyFiles);
 41053        }
 54
 55        /// <summary>
 56        /// Authenticates the specified session.
 57        /// </summary>
 58        /// <param name="session">The session to authenticate.</param>
 59        /// <returns>
 60        /// Result of authentication  process.
 61        /// </returns>
 62        public override AuthenticationResult Authenticate(Session session)
 68263        {
 68264            session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived;
 68265            session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived;
 68266            session.UserAuthenticationPublicKeyReceived += Session_UserAuthenticationPublicKeyReceived;
 67
 68268            session.RegisterMessage("SSH_MSG_USERAUTH_PK_OK");
 69
 136570            var hostAlgorithms = KeyFiles.SelectMany(x => x.HostKeyAlgorithms).ToList();
 71
 72            try
 68273            {
 274474                foreach (var hostAlgorithm in hostAlgorithms)
 68975                {
 68976                    _ = _authenticationCompleted.Reset();
 68977                    _isSignatureRequired = false;
 78
 68979                    var message = new RequestMessagePublicKey(ServiceName.Connection,
 68980                                                              Username,
 68981                                                              hostAlgorithm.Name,
 68982                                                              hostAlgorithm.Data);
 83
 68984                    if (hostAlgorithms.Count == 1)
 585                    {
 86                        // If only one key file provided then send signature for very first request
 587                        var signatureData = new SignatureData(message, session.SessionId).GetBytes();
 88
 589                        message.Signature = hostAlgorithm.Sign(signatureData);
 590                    }
 91
 92                    // Send public key authentication request
 68993                    session.SendMessage(message);
 94
 68995                    session.WaitOnHandle(_authenticationCompleted);
 96
 68997                    if (_isSignatureRequired)
 67598                    {
 67599                        _ = _authenticationCompleted.Reset();
 100
 675101                        var signatureMessage = new RequestMessagePublicKey(ServiceName.Connection,
 675102                                                                           Username,
 675103                                                                           hostAlgorithm.Name,
 675104                                                                           hostAlgorithm.Data);
 105
 675106                        var signatureData = new SignatureData(message, session.SessionId).GetBytes();
 107
 675108                        signatureMessage.Signature = hostAlgorithm.Sign(signatureData);
 109
 110                        // Send public key authentication request with signature
 675111                        session.SendMessage(signatureMessage);
 675112                    }
 113
 689114                    session.WaitOnHandle(_authenticationCompleted);
 115
 689116                    if (_authenticationResult is AuthenticationResult.Success or AuthenticationResult.PartialSuccess)
 680117                    {
 680118                        break;
 119                    }
 9120                }
 121
 682122                return _authenticationResult;
 123            }
 124            finally
 682125            {
 682126                session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
 682127                session.UserAuthenticationFailureReceived -= Session_UserAuthenticationFailureReceived;
 682128                session.UserAuthenticationPublicKeyReceived -= Session_UserAuthenticationPublicKeyReceived;
 682129                session.UnRegisterMessage("SSH_MSG_USERAUTH_PK_OK");
 682130            }
 682131        }
 132
 133        private void Session_UserAuthenticationSuccessReceived(object sender, MessageEventArgs<SuccessMessage> e)
 678134        {
 678135            _authenticationResult = AuthenticationResult.Success;
 136
 678137            _ = _authenticationCompleted.Set();
 678138        }
 139
 140        private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs<FailureMessage> e)
 11141        {
 11142            if (e.Message.PartialSuccess)
 2143            {
 2144                _authenticationResult = AuthenticationResult.PartialSuccess;
 2145            }
 146            else
 9147            {
 9148                _authenticationResult = AuthenticationResult.Failure;
 9149            }
 150
 151            // Copy allowed authentication methods
 11152            AllowedAuthentications = e.Message.AllowedAuthentications;
 153
 11154            _ = _authenticationCompleted.Set();
 11155        }
 156
 157        private void Session_UserAuthenticationPublicKeyReceived(object sender, MessageEventArgs<PublicKeyMessage> e)
 675158        {
 675159            _isSignatureRequired = true;
 675160            _ = _authenticationCompleted.Set();
 675161        }
 162
 163        /// <summary>
 164        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 165        /// </summary>
 166        public void Dispose()
 0167        {
 0168            Dispose(disposing: true);
 0169            GC.SuppressFinalize(this);
 0170        }
 171
 172        /// <summary>
 173        /// Releases unmanaged and - optionally - managed resources.
 174        /// </summary>
 175        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langwor
 176        protected virtual void Dispose(bool disposing)
 419177        {
 419178            if (_isDisposed)
 0179            {
 0180                return;
 181            }
 182
 419183            if (disposing)
 0184            {
 0185                var authenticationCompleted = _authenticationCompleted;
 0186                if (authenticationCompleted != null)
 0187                {
 0188                    _authenticationCompleted = null;
 0189                    authenticationCompleted.Dispose();
 0190                }
 191
 0192                _isDisposed = true;
 0193            }
 419194        }
 195
 196        /// <summary>
 197        /// Finalizes an instance of the <see cref="PrivateKeyAuthenticationMethod"/> class.
 198        /// </summary>
 199        ~PrivateKeyAuthenticationMethod()
 838200        {
 419201            Dispose(disposing: false);
 838202        }
 203
 204        private sealed class SignatureData : SshData
 205        {
 206            private readonly RequestMessagePublicKey _message;
 207
 208            private readonly byte[] _sessionId;
 209            private readonly byte[] _serviceName;
 210            private readonly byte[] _authenticationMethod;
 211
 212            protected override int BufferCapacity
 213            {
 214                get
 680215                {
 680216                    var capacity = base.BufferCapacity;
 680217                    capacity += 4; // SessionId length
 680218                    capacity += _sessionId.Length; // SessionId
 680219                    capacity += 1; // Authentication Message Code
 680220                    capacity += 4; // UserName length
 680221                    capacity += _message.Username.Length; // UserName
 680222                    capacity += 4; // ServiceName length
 680223                    capacity += _serviceName.Length; // ServiceName
 680224                    capacity += 4; // AuthenticationMethod length
 680225                    capacity += _authenticationMethod.Length; // AuthenticationMethod
 680226                    capacity += 1; // TRUE
 680227                    capacity += 4; // PublicKeyAlgorithmName length
 680228                    capacity += _message.PublicKeyAlgorithmName.Length; // PublicKeyAlgorithmName
 680229                    capacity += 4; // PublicKeyData length
 680230                    capacity += _message.PublicKeyData.Length; // PublicKeyData
 680231                    return capacity;
 680232                }
 233            }
 234
 680235            public SignatureData(RequestMessagePublicKey message, byte[] sessionId)
 680236            {
 680237                _message = message;
 680238                _sessionId = sessionId;
 680239                _serviceName = ServiceName.Connection.ToArray();
 680240                _authenticationMethod = Ascii.GetBytes("publickey");
 680241            }
 242
 243            protected override void LoadData()
 0244            {
 0245                throw new NotImplementedException();
 246            }
 247
 248            protected override void SaveData()
 680249            {
 680250                WriteBinaryString(_sessionId);
 680251                Write((byte) RequestMessage.AuthenticationMessageCode);
 680252                WriteBinaryString(_message.Username);
 680253                WriteBinaryString(_serviceName);
 680254                WriteBinaryString(_authenticationMethod);
 680255                Write((byte)1); // TRUE
 680256                WriteBinaryString(_message.PublicKeyAlgorithmName);
 680257                WriteBinaryString(_message.PublicKeyData);
 680258            }
 259        }
 260    }
 261}