1
0
mirror of https://github.com/danog/phpseclib.git synced 2024-12-12 09:09:39 +01:00
phpseclib/tests/Functional/Net/SSH2Test.php

546 lines
15 KiB
PHP
Raw Normal View History

<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace phpseclib3\Tests\Functional\Net;
use phpseclib3\Net\SSH2;
use phpseclib3\Tests\PhpseclibFunctionalTestCase;
2014-12-10 02:31:41 +01:00
class SSH2Test extends PhpseclibFunctionalTestCase
{
/**
* @return SSH2
*/
public function getSSH2()
{
return new SSH2($this->getEnv('SSH_HOSTNAME'), 22);
}
/**
* @return SSH2
*/
public function getSSH2Login()
{
$ssh = $this->getSSH2();
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertTrue(
$ssh->login($username, $password),
'SSH2 login using password failed.'
);
return $ssh;
}
public function testConstructor()
{
$ssh = $this->getSSH2();
2020-12-13 02:34:38 +01:00
$this->assertIsObject(
2017-12-07 21:08:19 +01:00
$ssh,
'Could not construct NET_SSH2 object.'
);
return $ssh;
}
/**
2015-03-29 18:07:17 +02:00
* @depends testConstructor
* @group github408
* @group github412
*/
2022-04-20 03:09:36 +02:00
public function testPreLogin(SSH2 $ssh)
2014-07-20 22:58:24 +02:00
{
$this->assertFalse(
$ssh->isConnected(),
'Failed asserting that SSH2 is not connected after construction.'
);
$this->assertFalse(
$ssh->isAuthenticated(),
'Failed asserting that SSH2 is not authenticated after construction.'
);
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that SSH2 does not have open shell after construction.'
);
$this->assertEquals(
0,
$ssh->getInteractiveChannelId(),
'Failed asserting that channel identifier 0 is returned.'
);
2014-07-20 22:58:24 +02:00
$this->assertNotEmpty(
$ssh->getServerPublicHostKey(),
'Failed asserting that a non-empty public host key was fetched.'
);
$this->assertTrue(
$ssh->isConnected(),
'Failed asserting that SSH2 is connected after public key fetch.'
);
$this->assertNotEmpty(
$ssh->getServerIdentification(),
'Failed asserting that the server identifier was set after connect.'
);
return $ssh;
}
/**
2015-03-29 18:07:17 +02:00
* @depends testPreLogin
*/
2022-04-20 03:09:36 +02:00
public function testBadPassword(SSH2 $ssh)
{
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertFalse(
$ssh->login($username, 'zzz' . $password),
'SSH2 login using password succeeded.'
);
$this->assertTrue(
$ssh->isConnected(),
'Failed asserting that SSH2 is connected after bad login attempt.'
);
$this->assertFalse(
$ssh->isAuthenticated(),
'Failed asserting that SSH2 is not authenticated after bad login attempt.'
);
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that SSH2 does not have open shell after bad login attempt.'
);
return $ssh;
}
/**
* @depends testBadPassword
*/
2022-04-20 03:09:36 +02:00
public function testPasswordLogin(SSH2 $ssh)
{
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertTrue(
$ssh->login($username, $password),
'SSH2 login using password failed.'
);
2014-03-06 11:35:54 +01:00
$this->assertTrue(
$ssh->isAuthenticated(),
'Failed asserting that SSH2 is authenticated after good login attempt.'
);
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that SSH2 does not have open shell after good login attempt.'
);
2014-03-06 11:35:54 +01:00
return $ssh;
}
/**
2015-03-29 18:07:17 +02:00
* @depends testPasswordLogin
* @group github280
2023-02-06 00:33:16 +01:00
* @requires PHPUnit < 10
2015-03-29 18:07:17 +02:00
*/
2022-04-20 03:09:36 +02:00
public function testExecWithMethodCallback(SSH2 $ssh)
2014-03-06 11:35:54 +01:00
{
2017-12-14 07:31:32 +01:00
$callbackObject = $this->getMockBuilder('stdClass')
2022-01-30 16:34:42 +01:00
->setMethods(['callbackMethod'])
2017-12-14 07:31:32 +01:00
->getMock();
2014-03-06 11:35:54 +01:00
$callbackObject
->expects($this->atLeastOnce())
->method('callbackMethod')
->will($this->returnValue(true));
2017-11-27 09:30:14 +01:00
$ssh->exec('pwd', [$callbackObject, 'callbackMethod']);
2017-05-28 15:58:00 +02:00
$this->assertFalse(
$ssh->isPTYOpen(),
'Failed asserting that SSH2 does not have open exec channel after exec.'
);
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that SSH2 does not have open shell channel after exec.'
);
$this->assertEquals(
0,
$ssh->getInteractiveChannelId(),
'Failed asserting that channel identifier 0 is returned after exec.'
);
2017-05-28 15:58:00 +02:00
return $ssh;
}
public function testGetServerPublicHostKey()
{
$ssh = $this->getSSH2();
$this->assertIsString($ssh->getServerPublicHostKey());
}
public function testOpenSocketConnect()
{
$fsock = fsockopen($this->getEnv('SSH_HOSTNAME'), 22);
$ssh = new SSH2($fsock);
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertTrue(
$ssh->login($username, $password),
'SSH2 login using an open socket failed.'
);
}
2017-05-28 15:58:00 +02:00
/**
* @depends testExecWithMethodCallback
* @group github1009
*/
2022-04-20 03:09:36 +02:00
public function testDisablePTY(SSH2 $ssh)
2017-05-28 15:58:00 +02:00
{
$ssh->enablePTY();
$this->assertTrue(
$ssh->isPTYEnabled(),
'Failed asserting that pty was enabled.'
);
$this->assertFalse(
$ssh->isPTYOpen(),
'Failed asserting that pty was not open after enable.'
);
$this->assertEquals(
0,
$ssh->getInteractiveChannelId(),
'Failed asserting that 0 channel identifier is returned prior to opening.'
);
2017-05-28 15:58:00 +02:00
$ssh->exec('ls -latr');
$this->assertTrue(
$ssh->isPTYOpen(),
'Failed asserting that pty was open.'
);
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that shell was not open after pty exec.'
);
$this->assertEquals(
SSH2::CHANNEL_EXEC,
$ssh->getInteractiveChannelId(),
'Failed asserting that exec channel identifier is returned after exec.'
);
2017-05-28 15:58:00 +02:00
$ssh->disablePTY();
$this->assertFalse(
$ssh->isPTYEnabled(),
'Failed asserting that pty was disabled.'
);
$this->assertFalse(
$ssh->isPTYOpen(),
'Failed asserting that pty was not open after disable.'
);
$this->assertEquals(
SSH2::CHANNEL_EXEC,
$ssh->getInteractiveChannelId(),
'Failed asserting that exec channel identifier is returned after pty exec close.'
);
2017-05-28 15:58:00 +02:00
$ssh->exec('pwd');
2017-09-06 07:27:07 +02:00
$this->assertFalse(
$ssh->isPTYOpen(),
'Failed asserting that pty was not open after exec.'
);
2017-09-06 07:27:07 +02:00
return $ssh;
}
/**
* @depends testDisablePTY
* @group github1167
*/
2022-04-20 03:09:36 +02:00
public function testChannelDataAfterOpen(SSH2 $ssh)
2017-09-06 07:27:07 +02:00
{
// Ubuntu's OpenSSH from 5.8 to 6.9 didn't work with multiple channels. see
// https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/1334916 for more info.
// https://lists.ubuntu.com/archives/oneiric-changes/2011-July/005772.html discusses
// when consolekit was incorporated.
// https://marc.info/?l=openssh-unix-dev&m=163409903417589&w=2 discusses some of the
// issues with how Ubuntu incorporated consolekit
2022-03-09 01:59:30 +01:00
$pattern = '#^SSH-2\.0-OpenSSH_([\d.]+)[^ ]* Ubuntu-.*$#';
$match = preg_match($pattern, $ssh->getServerIdentification(), $matches);
$match = $match && version_compare('5.8', $matches[1], '<=');
$match = $match && version_compare('6.9', $matches[1], '>=');
if ($match) {
self::markTestSkipped('Ubuntu\'s OpenSSH >= 5.8 <= 6.9 didn\'t work well with multiple channels');
}
2017-09-06 07:27:07 +02:00
$ssh->write("ping 127.0.0.1\n");
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after shell read/write.'
);
$this->assertFalse(
$ssh->isPTYOpen(),
'Failed asserting that pty was not open after shell read/write.'
);
$this->assertEquals(
SSH2::CHANNEL_SHELL,
$ssh->getInteractiveChannelId(),
'Failed asserting that shell channel identifier is returned after shell read/write.'
);
2017-09-06 07:27:07 +02:00
$ssh->enablePTY();
$this->assertTrue(
$ssh->exec('bash'),
'Failed asserting exec command succeeded.'
);
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after pty exec.'
);
$this->assertTrue(
$ssh->isPTYOpen(),
'Failed asserting that pty was not open after exec.'
);
$this->assertEquals(
SSH2::CHANNEL_EXEC,
$ssh->getInteractiveChannelId(),
'Failed asserting that exec channel identifier is returned after pty exec.'
);
2017-09-06 07:27:07 +02:00
$ssh->write("ls -latr\n");
$ssh->setTimeout(1);
2022-03-09 01:59:30 +01:00
$this->assertIsString($ssh->read());
$this->assertTrue(
$ssh->isTimeout(),
'Failed asserting that pty exec read timed out'
);
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 shell remains open across pty exec read/write.'
);
$this->assertTrue(
$ssh->isPTYOpen(),
'Failed asserting that pty was open after read timeout.'
);
}
public function testOpenShell()
{
$ssh = $this->getSSH2Login();
$this->assertTrue(
$ssh->openShell(),
'SSH2 shell initialization failed.'
);
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after init.'
);
$this->assertNotFalse(
$ssh->read(),
'Failed asserting that read succeeds.'
);
$ssh->write('hello');
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after read/write.'
);
$this->assertEquals(
SSH2::CHANNEL_SHELL,
$ssh->getInteractiveChannelId(),
'Failed asserting that shell channel identifier is returned after read/write.'
);
return $ssh;
}
/**
* @depends testOpenShell
*/
public function testResetOpenShell(SSH2 $ssh)
{
$ssh->reset();
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after reset.'
);
$this->assertEquals(
SSH2::CHANNEL_SHELL,
$ssh->getInteractiveChannelId(),
'Failed asserting that shell channel identifier is returned after reset.'
);
}
public function testMultipleExecPty()
{
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
$ssh = $this->getSSH2Login();
$ssh->enablePTY();
$ssh->exec('bash');
$ssh->exec('bash');
}
public function testMultipleInteractiveChannels()
{
$ssh = $this->getSSH2Login();
$this->assertTrue(
$ssh->openShell(),
'SSH2 shell initialization failed.'
);
$this->assertEquals(
SSH2::CHANNEL_SHELL,
$ssh->getInteractiveChannelId(),
'Failed asserting that shell channel identifier is returned after open shell.'
);
$ssh->setTimeout(1);
$this->assertIsString(
$ssh->read(),
'Failed asserting that read succeeds after shell init'
);
$directory = $ssh->exec('pwd');
$this->assertFalse(
$ssh->isTimeout(),
'failed'
);
$this->assertIsString(
$directory,
'Failed asserting that exec succeeds after shell read/write'
);
$ssh->write("pwd\n");
$this->assertStringContainsString(
trim($directory),
$ssh->read(),
'Failed asserting that current directory can be read from shell after exec'
);
$ssh->enablePTY();
$this->assertTrue(
$ssh->exec('bash'),
'Failed asserting that pty exec succeeds'
);
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after pty exec.'
);
$this->assertEquals(
SSH2::CHANNEL_EXEC,
$ssh->getInteractiveChannelId(),
'Failed asserting that exec channel identifier is returned after pty exec.'
);
$ssh->write("pwd\n", SSH2::CHANNEL_SHELL);
$this->assertStringContainsString(
trim($directory),
$ssh->read('', SSH2::READ_SIMPLE, SSH2::CHANNEL_SHELL),
'Failed asserting that current directory can be read from shell after pty exec'
);
$this->assertTrue(
$ssh->isPTYOpen(),
'Failed asserting that SSH2 has open pty exec after shell read/write.'
);
$ssh->write("pwd\n", SSH2::CHANNEL_EXEC);
$this->assertIsString(
$ssh->read('', SSH2::READ_SIMPLE, SSH2::CHANNEL_EXEC),
'Failed asserting that pty exec read succeeds'
);
$ssh->reset(SSH2::CHANNEL_EXEC);
$this->assertFalse(
$ssh->isPTYOpen(),
'Failed asserting that SSH2 has closed pty exec after reset.'
);
$ssh->disablePTY();
$this->assertTrue(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has open shell after pty exec.'
);
$ssh->write("pwd\n", SSH2::CHANNEL_SHELL);
$this->assertStringContainsString(
trim($directory),
$ssh->read('', SSH2::READ_SIMPLE, SSH2::CHANNEL_SHELL),
'Failed asserting that current directory can be read from shell after pty exec'
);
$ssh->reset(SSH2::CHANNEL_SHELL);
$this->assertFalse(
$ssh->isShellOpen(),
'Failed asserting that SSH2 has closed shell after reset.'
);
$this->assertEquals(
SSH2::CHANNEL_EXEC,
$ssh->getInteractiveChannelId(),
'Failed asserting that exec channel identifier is maintained as last opened channel.'
);
2017-05-28 15:58:00 +02:00
}
}