Home Forums .NET libraries Xceed SFTP/FTP for .NET Keyboard-interactive authentication

Viewing 1 post (of 1 total)
  • Author
    Posts
  • Xceed Support
    Member
    Post count: 5658
    #21477 |

    SSHClient supports keyboard interactive
    authentication as defined by RFC 4256. Depending on the requirements of the SSH server, it can
    be used instead of password authentication.

    Keyboard interactive is a general purpose authentication method,
    suitable for interactive authentications where the
    authentication data is entered via a keyboard (or equivalent
    alphanumeric input device). The major goal of this method is to
    allow the SSH client to support a whole class of authentication
    mechanism(s) without knowing the specifics of the actual
    authentication mechanism(s).

    In practical terms, with keyboard interactive authentication, the SSH server sends
    text prompts to the client. These prompts must be given a text answer to. The client sends
    the responses back to the server. If accepted, more prompts can be sent to the client for
    response or the authentication can be declared successful or failed.

    The text prompts are arbitrary strings. There are no standard or predefined texts.
    The server decides the content of the prompts and what the required response is. As such,
    the SSHClient class cannot parse or process the prompts it receives as part of keyboard
    interactive authentication. Your application must process the prompts and supply responses
    programmatically or display the prompts to the end-user for them to type the responses.

    To authenticate with keyboard interactive, call SSHClient.Authenticate()
    with a userName and a KeyBoardInteractiveAuthenticationHandler
    delegate.

    sshClient.Authenticate( "user name", myHandler );

    The delegate Xceed.SSH.Client.KeyBoardInteractiveAuthenticationHandler is a
    callback method that will be invoked as part of keyboard interactive authentication.
    It is defined as follows

    public delegate void KeyBoardInteractiveAuthenticationHandler(
        string userName,
        string name,
        string instruction,
        string languageTag,
        KeyboardInteractiveRequest[] requests )
    • userName is the user name that was specified in the call to Authenticate().
    • name is a server-supplied string that may indicate a logical name for the series
      of requests. It can be an empty string. But it will not be null.
    • instruction is a server-supplied string that may indicate instructions on how
      to respond to the series of requests. It can be an empty string. But it will not be null.
    • languageTag is a string that specifies the language of the messages. In most cases,
      this parameter will be an empty string and the language will be english.
    • requests is an array of KeyboardInteractiveRequest objects that specify
      the information prompts and their responses. The array will not be null. Each element in the array
      represents a prompt that must be answered. The response for each element is prefilled with
      an empty string. It is possible that the array will be empty. But it will not be null.

    Xceed.SSH.Client.KeyboardInteractiveRequest is a simple class that holds the following properties:

    • Prompt is the server-supplied string that specifies what information is required.
      For example, it could be something like Password:. There are no pre-defined prompt strings.
      The server can supply any text it wants here.
    • Echo is a boolean value that specifies whether the response to the prompt should be
      echoed to the screen. In general, this value will be false when the prompt refers to sensitive
      information like passwords and true otherwise.
    • Response is the string that will contain the response to the prompt.
      Your handler will set the this property’s value.
      The string will then be sent back to the server for authentication. The response can be set to an empty string.
      If the property is set to null, an empty string will be sent back to the server.

    Each request in the requests array represents a prompt. If the prompts are presented to an end-user,
    each prompt should be displayed to the user one by one and in order. The requests array
    will typically contain one prompt but it might contain more. The KeyBoardInteractiveAuthenticationHandler
    might be called again with more prompts. There is no predefined limit on the number of prompts that
    may be asked.

    The KeyBoardInteractiveAuthenticationHandler will be invoked by the component
    on the same thread that Authenticate() was called on. Authenticate()
    will therefore block while it waits for the KeyBoardInteractiveAuthenticationHandler to return.
    The component does not impose any timeout on how long control can stay in the handler.
    However, be aware that some SSH servers enforce a limit on how long authentication
    takes. For example, the default limit on the OpenSSH server is 120 seconds.

    How to implement KeyBoardInteractiveAuthenticationHandler

    If you are certain of the contents and formatting of the prompts you will receive from
    the server, you may implement a KeyBoardInteractiveAuthenticationHandler method that
    processes and answers the prompts automatically.

    Consider this example for OpenSSH servers that use the ChallengeResponseAuthentication option:

    Example (C#)
    public static void KeyBoardInteractiveAuthenticationHandlerLinuxPAM( string userName, string name, string instruction, string languageTag, KeyboardInteractiveRequest[] requests )
    {
      // If we have a request
      if( requests.Length > 0 )
      {
        // If the first request is the string 'Password: '
        if( StringComparer.OrdinalIgnoreCase.Compare( requests[ 0 ].Prompt, "Password: " ) == 0 )
        {
          // Supply our password as the response
          requests[ 0 ].Response = "<your password>";
        }
      }
    }

    Another way to approach this authentication is to display the prompts to the console and
    accept input for the answers.

    Example (C#)
    public static void KeyBoardInteractiveAuthenticationHandlerConsole( string userName, string name, string instruction, string languageTag, KeyboardInteractiveRequest[] requests )
    {
      // If the name is non-empty
      if( !String.IsNullOrEmpty( name ) )
      {
        // Display it
        Console.WriteLine( name );
      }
    
      // If the instruction is non-empty
      if( !String.IsNullOrEmpty( instruction ) )
      {
        // Display it
        Console.WriteLine( instruction );
      }
    
      // If we have a request
      if( requests.Length > 0 )
      {
        // Go through each request in order
        foreach( KeyboardInteractiveRequest request in requests )
        {
          // Display the prompt
          Console.Write( request.Prompt );
    
          // If we can display the response as it is being typed
          if( request.Echo )
          {
            // Read the next line of text from the console
            request.Response = Console.ReadLine();
          }
          // We can't display the response
          else
          {
            StringBuilder response = new StringBuilder();
    
            // Read a key without displaying it
            ConsoleKeyInfo keyInfo = Console.ReadKey( true );
    
            // Until <Enter> is pressed
            while( keyInfo.Key != ConsoleKey.Enter )
            {
              // Add it to the response
              response.Append( keyInfo.KeyChar );
    
              // Read a key without displaying it
              keyInfo = Console.ReadKey( true );
            }
            
            // Store the response string in the request
            request.Response = response.ToString();
          }
        }
      }
    }

    Here’s an example that puts it all together, with the exceptions that
    Authenticate() can throw when called for the keyboard interactive method.

    Example (C#)
    SSHClient sshClient = new SSHClient(); sshClient.Connect( hostName, port );
    KeyBoardInteractiveAuthenticationHandler consoleHandler = new KeyBoardInteractiveAuthenticationHandler( KeyBoardInteractiveAuthenticationHandlerConsole );
    try { sshClient.Authenticate( username, consoleHandler ); } // Authentication was successful but more authentication is required by the server catch( SSHAuthenticationPartialSuccessException e ) { // The 'AuthenticationsThatCanContinue' property specifies the authentications methods that can be tried e.AuthenticationsThatCanContinue.ToString(); } // The server rejected the response(s) that were sent back. Authentication has failed catch( SSHIncorrectResponseException e ) { SSHAuthenticationFailedException authenticationFailedException = e.InnerException as SSHAuthenticationFailedException; if( authenticationFailedException != null ) { // The 'AuthenticationsThatCanContinue' property specifies the authentications methods that can be tried authenticationFailedException.AuthenticationsThatCanContinue.ToString(); } } catch( SSHUnsupportedAuthenticationMethodException e ) { // The 'AuthenticationsThatCanContinue' property specifies the authentications methods that can be tried e.AuthenticationsThatCanContinue.ToString(); } catch( SSHAuthenticationFailedException e ) { // The 'AuthenticationsThatCanContinue' property specifies the authentications methods that can be tried e.AuthenticationsThatCanContinue.ToString(); } sshClient.Disconnect();

    Applies to Xceed SFTP for .NET. Imported from legacy forums. Posted by Jb [Xceed] (had 1609 views)

Viewing 1 post (of 1 total)
  • You must be logged in to reply to this topic.