phpseclib - Can I connect using username, key and password (not a key passphrase)

旧时模样 提交于 2019-11-27 15:24:30
neubert

phpseclib supports multi factor authentication. Here's an example of how to do it:

<?php
include('Net/SSH2.php');
include('Crypt/RSA.php')

$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents('/path/to/key.pem'));

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'pass1', $rsa)) {
    exit('Login failed');
}
// this does the same thing as the above
//if (!$ssh->login($username, 'pass1') && !$ssh->login('username', $rsa)) {
//    exit('Login failed');
//}

echo $ssh->exec('pwd');
echo $ssh->exec('ls -la');
?>

Something to keep in mind, however: a lot of people confuse password protected private keys as being multi factor (password and public key) when in fact it is not. At least not in-so-far as SSH is concerned.

user2048615

Disclaimer by @MartinPrikryl: This solution is obsolete, now that phpseclib supports multi-factor authentication natively - See also the answer by @BoukeVersteegh and @neubert.


I ran across the same problem for one of my projects using phpseclib. I tried several of the suggestions to no avail, and finally did some research into the library code myself. I ended up modifying it, though not alot.

In the SSH2.php private method '_privatekey_login' (called from the login method when there is a key), there is code at the end of the method to handle authentication failure.

extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
   case NET_SSH2_MSG_USERAUTH_FAILURE:
      // either the login is bad or the server employs multi-factor authentication
      return false;
   case NET_SSH2_MSG_USERAUTH_SUCCESS:
      $this->bitmap |= NET_SSH2_MASK_LOGIN;
      return true;
}

After putting in some logs, I found that the response I was getting back from the server was indeed "password,keyboard-interactive".

I modified all of the login methods (both in the SFTP AND SSH2 classes) to take a second password, passing it all the way to the '_privatekey_login' method. I then changed the above section to the following:

extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
   case NET_SSH2_MSG_USERAUTH_FAILURE:
      // Possible multi-factor authentication.
      if ($password && $this->_keyboard_interactive_login($username, $password)) {
         $this->bitmap |= NET_SSH2_MASK_LOGIN;
         return true;
      }
      // the login is bad.
      return false;
   case NET_SSH2_MSG_USERAUTH_SUCCESS:
      $this->bitmap |= NET_SSH2_MASK_LOGIN;
      return true;
}

I copied the keyboard interactive call from another portion of the code, so some of that might not be completely necessary. While it might not apply to all servers, it worked beautifully in my case.

Short simple answer: first login with user+key, then login with user+pass.

$host = 'ftp.example.com';
$username = 'username';
$password = 'secret';
$key = new RSA();
$key->load(file_get_contents('~/.ssh/private_key.pem'));

$sftp = new SFTP($host);

if ($sftp->login($username, $key) || $sftp->login($username, $secret)) {
    // success
} else {
    // failed
}

Yes, this was mentioned already, but long notes made it obscure and look complicated.

I decided to delete my other answer because it turns out I was wrong; you can do multi-factored logins with SSH, just not in a standard way. None of these authentication methods are native or built-in to openssh and therefore there is no standard way to go about it. Most use Google Authenticator to provide a one-time password, but there are differences. According to what this site recommends, it looks like it is done by invoking a command AFTER the user has been authenticated by the SSH server. Looking at the phpseclib source code in Net/SSH2.php in the login() method it has the following code:

case NET_SSH2_MSG_USERAUTH_FAILURE:
    // can we use keyboard-interactive authentication?  if not then either the login is bad or the server employees
    // multi-factor authentication
    [...]
    return false;

Even the phpseclib devs realized that multi-factor authentication is possible, but due to lack of standards, they didn't bother coding it. Googling your error code

authenticated with partial success

shows that this is how the server you are trying to connect to is set up. If you would like to code multi-factor authentication specific to your server's set-up, I don't see why it's not possible. This is the file that you would need to edit in order to do it.

You can use the SSH2 bindings in PECL. It supports all of the authentication mechanisms you mentioned and works quite well.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!