def test_send_cmd_unix_endings(unicode_chr): """Ensure the correct line ending is used when unix is specified.""" runner = Bladerunner({ "unix_line_endings": True, "windows_line_endings": False, "second_password": "******", }) server = Mock() # server.expect returns an integer of the prompt matched in its list # we want to return N+1 to simulate matching a passwd prompt server.expect = Mock(return_value=(len(runner.options["shell_prompts"]) + len(runner.options["extra_prompts"]) + 1)) with patch.object(base, "format_output") as p_format_out: runner._send_cmd("fake", server) p_format_out.assert_called_once_with(server.before, "fake", runner.options) server.send.assert_called_once_with("fake{0}".format(unicode_chr(0x000A))) # the second password should be send with sendline server.sendline.assert_called_once_with("hunter55") assert server.expect.call_count == 2
def test_send_cmd_unix_endings(unicode_chr): """Ensure the correct line ending is used when unix is specified.""" runner = Bladerunner({ "unix_line_endings": True, "windows_line_endings": False, "second_password": "******", }) server = Mock() # server.expect returns an integer of the prompt matched in its list # we want to return N+1 to simulate matching a passwd prompt server.expect = Mock(return_value=( len(runner.options["shell_prompts"]) + len(runner.options["extra_prompts"]) + 1 )) with patch.object(base, "format_output") as p_format_out: runner._send_cmd("fake", server) p_format_out.assert_called_once_with(server.before, "fake", runner.options) server.send.assert_called_once_with("fake{0}".format(unicode_chr(0x000A))) # the second password should be send with sendline server.sendline.assert_called_once_with("hunter55") assert server.expect.call_count == 2
def test_login_send_password(): """Ensure then calls when logging in properly with a passwd prompt.""" runner = Bladerunner() sshc = Mock() sshc.expect = Mock(return_value=22) assert runner.login(sshc, "mock word", 1) == (sshc, 1) sshc.sendline.assert_called_once_with("mock word")
def test_login_new_host(): """The first passwd prompt is a match for a new ssh key identity.""" runner = Bladerunner() sshc = Mock() sshc.expect = Mock(side_effect=iter([2, 22])) # passwd, then shell assert runner.login(sshc, "fake", 0) == (sshc, 1) assert sshc.sendline.mock_calls == [call("yes"), call("fake")]
def test_login_new_host_failures(pexpect_exceptions): """Catch the pexpect EOF and TIMEOUT exceptions after accepting the key.""" runner = Bladerunner() sshc = Mock() sshc.expect = Mock(side_effect=pexpect_exceptions("fake exception")) with patch.object(runner, "send_interrupt") as p_interrupt: assert runner.login(sshc, "hunter12", 0) == (None, -1) sshc.sendline.assert_called_once_with("yes") p_interrupt.assert_called_once_with(sshc)
def test_login_passwd_fail(): """Ensure the calls when receiving another passwd prompt after sending.""" runner = Bladerunner() sshc = Mock() sshc.expect = Mock(return_value=1) with patch.object(runner, "send_interrupt") as p_interrupt: assert runner.login(sshc, "fakepasswd", 1) == (sshc, -5) sshc.sendline.assert_called_once_with("fakepasswd") p_interrupt.assert_called_once_with(sshc)
def side_effect(*args, **kwargs): m = Mock() def expect(patterns, timeout): return responder(m, side_effect.responses, patterns, timeout) m.expect = expect # TODO: implements a exact match m.expect_exact = expect return m
def test_fallback_prompt_guess(pexpect_exceptions): """If a TIMEOUT or EOF error is raised, call _try_for_unmatched_prompt.""" server = Mock() server.expect = Mock(side_effect=pexpect_exceptions("mock exception")) runner = Bladerunner({ "username": "******", "password": "******", }) with patch.object(runner, "_try_for_unmatched_prompt") as p_try_for: runner._send_cmd("not real", server) p_try_for.assert_called_once_with(server, server.before, "not real")
def test_send_cmd_no_preference(): """Ensure we call to pexpect's sendline which uses os.linesep.""" runner = Bladerunner() server = Mock() server.expect = Mock(return_value=1) with patch.object(base, "format_output") as p_format_out: runner._send_cmd("mock", server) p_format_out.assert_called_once_with(server.before, "mock", runner.options) server.sendline.assert_called_once_with("mock") assert server.expect.call_count == 1
def test_close_keep_open(pexpect_exceptions): """Ensure we can close a connection inside another, for jumpboxes.""" runner = Bladerunner() sshc = Mock() # exceptions are ignored here, we hope we're back on the jumpbox sshc.expect = Mock(side_effect=pexpect_exceptions("mock exception")) runner.close(sshc, False) sshc.sendline.assert_called_once_with("exit") sshc.expect.assert_called_once_with( runner.options["shell_prompts"] + runner.options["extra_prompts"], runner.options["cmd_timeout"], )
def test_push_expect_forward(pexpect_exceptions): """Verify the calls made to push the pexpect connection object forward.""" runr = Bladerunner() sshc = Mock() # any EOF or TIMEOUT exceptions are ignored sshc.expect = Mock(side_effect=pexpect_exceptions("faked exception")) runr._push_expect_forward(sshc) assert sshc.expect.mock_calls == [ call(runr.options["shell_prompts"] + runr.options["extra_prompts"], 2), call(runr.options["shell_prompts"] + runr.options["extra_prompts"], 2), ]
def test_send_interrupt(unicode_chr, pexpect_exceptions): """Ensure Bladerunner sends ^c to the sshc when jumpboxing.""" runner = Bladerunner() sshc = Mock() # any EOF or TIMEOUT exceptions are ignored sshc.expect = Mock(side_effect=pexpect_exceptions("faked exception")) with patch.object(runner, "_push_expect_forward") as p_push: runner.send_interrupt(sshc) sshc.sendline.assert_called_once_with(unicode_chr(0x003)) sshc.expect.assert_called_once_with( runner.options["shell_prompts"] + runner.options["extra_prompts"], 3) p_push.assert_called_once_with(sshc)
def test_connect_new_exceptions(pexpect_exceptions): """If TIMEOUT or EOF exceptions are raised, connect returns (None, -7).""" runner = Bladerunner({"debug": 2, "jump_host": "nowhere"}) sshr = Mock() sshr.expect = Mock(side_effect=pexpect_exceptions("faked")) sshr.isalive = Mock(return_value=False) with patch.object(base, "can_resolve", return_value=True): with patch.object(base.pexpect, "spawn", return_value=sshr) as p_spawn: res = runner.connect("nowhere", "noone", "hunter29", 99) p_spawn.assert_called_once_with("ssh -p 99 -t -vv noone@nowhere", timeout=20) # default timeout assert res == (None, -7)
def test_login_fail_guess(pexpect_exceptions): """When sending a password fails try to guess the shell prompt.""" runner = Bladerunner() sshc = Mock() sshc.expect = Mock(side_effect=pexpect_exceptions("fake explosion")) with patch.object(runner, "_try_for_unmatched_prompt") as p_try_for: runner.login(sshc, "passwerd", 1) sshc.sendline.assert_called_once_with("passwerd") p_try_for.assert_called_once_with( sshc, sshc.before, "login", _from_login=True, )
def test_connect_exception_guess(pexpect_exceptions): """If the pexpect object is alive on connect timeout, guess the prompt.""" runner = Bladerunner({"timeout": "fake"}) sshr = Mock() sshr.expect = Mock(side_effect=pexpect_exceptions("not real")) sshr.before = Mock(return_value="what") sshr.isalive = Mock(return_value=True) with patch.object(base, "can_resolve", return_value=True): with patch.object(base.pexpect, "spawn", return_value=sshr) as p_spawn: with patch.object(runner, "_try_for_unmatched_prompt") as p_guess: res = runner.connect("fence", "tim", "hunter1", 4) p_spawn.assert_called_once_with("ssh -p 4 -t tim@fence", timeout="fake") p_guess.assert_called_once_with(sshr, sshr.before, "ssh -p 4 -t tim@fence", _from_login=True)
def test_try_for_unmatched_fails(): """Bladerunner "hits enter" up to 3 times to try to guess the prompt.""" runner = Bladerunner() server = Mock() server.expect = Mock(side_effect=pexpect.TIMEOUT("fake")) server.before = bytes_or_string("mock output") with patch.object(runner, "send_interrupt") as p_interrupt: ret = runner._try_for_unmatched_prompt( server, bytes_or_string("out"), "fake", ) assert ret == -1 assert "out" in runner.options["shell_prompts"] p_interrupt.assert_called_once_with(server)
def test_try_unmatched_fails_from_login(): """When trying to guess on login, return None, -6 on error.""" runner = Bladerunner() server = Mock() server.expect = Mock(side_effect=pexpect.TIMEOUT("fake")) server.before = bytes_or_string("mock output") with patch.object(runner, "send_interrupt") as p_interrupt: ret = runner._try_for_unmatched_prompt( server, bytes_or_string("out"), "fake", True, ) assert ret == (None, -6) assert "out" in runner.options["shell_prompts"] p_interrupt.assert_called_once_with(server)
def test_connect_exception_guess(pexpect_exceptions): """If the pexpect object is alive on connect timeout, guess the prompt.""" runner = Bladerunner({"timeout": "fake"}) sshr = Mock() sshr.expect = Mock(side_effect=pexpect_exceptions("not real")) sshr.before = Mock(return_value="what") sshr.isalive = Mock(return_value=True) with patch.object(base, "can_resolve", return_value=True): with patch.object(base.pexpect, "spawn", return_value=sshr) as p_spawn: with patch.object(runner, "_try_for_unmatched_prompt") as p_guess: runner.connect("fence", "tim", "hunter1", 4) p_spawn.assert_called_once_with("ssh -p 4 -t tim@fence", timeout="fake") p_guess.assert_called_once_with(sshr, sshr.before, "ssh -p 4 -t tim@fence", _from_login=True)
def test_send_cmd_winderps_endings(unicode_chr): """Ensure the wrong line endings are used when winderps is required.""" runner = Bladerunner({ "unix_line_endings": False, "windows_line_endings": True, }) server = Mock() server.expect = Mock(return_value=1) with patch.object(base, "format_output") as p_format_out: runner._send_cmd("fake", server) p_format_out.assert_called_once_with(server.before, "fake", runner.options) server.send.assert_called_once_with("fake{0}{1}".format( unicode_chr(0x000D), unicode_chr(0x000A), )) assert server.expect.call_count == 1
def test_send_cmd_winderps_endings(unicode_chr): """Ensure the wrong line endings are used when winderps is required.""" runner = Bladerunner({ "unix_line_endings": False, "windows_line_endings": True, }) server = Mock() server.expect = Mock(return_value=1) with patch.object(base, "format_output") as p_format_out: runner._send_cmd("faked", server) p_format_out.assert_called_once_with(server.before, "faked", runner.options) server.send.assert_called_once_with("faked{0}{1}".format( unicode_chr(0x000D), unicode_chr(0x000A), )) assert server.expect.call_count == 1
def test_connect_new_connection(): """Ensure Bladerunner creates the initial pexpect object correctly.""" runner = Bladerunner({"debug": 2, "jump_host": "nowhere", "timeout": 14}) sshr = Mock() sshr.expect = Mock(return_value="faked") with patch.object(base, "can_resolve", return_value=True): with patch.object(base.pexpect, "spawn", return_value=sshr) as p_spawn: with patch.object(runner, "_multipass") as p_multipass: runner.connect("nowhere", "bobby", "hunter44", 15) p_spawn.assert_called_once_with("ssh -p 15 -t -vv bobby@nowhere", timeout=14) p_multipass.assert_called_once_with(sshr, "hunter44", "faked") sshr.expect.assert_called_once_with( runner.options["passwd_prompts"] + runner.options["shell_prompts"] + runner.options["extra_prompts"], runner.options["timeout"], ) assert runner.sshc == sshr # could be used as a jumpbox in future connects assert sshr.logfile_read == FakeStdOut # debug is set, logging to stdout
def test_send_cmd_no_line_endings(): """If are False, pexpect's sendline should be called (which uses os).""" runner = Bladerunner() # we need to update after init as init will fallback to os preferred runner.options.update({ "unix_line_endings": False, "windows_line_endings": False, }) server = Mock() server.expect = Mock(return_value=1) with patch.object(base, "format_output") as p_format_out: runner._send_cmd("fake_cmd", server) p_format_out.assert_called_once_with( server.before, "fake_cmd", runner.options, ) server.sendline.assert_called_once_with("fake_cmd") assert server.expect.call_count == 1