cockpit/test/verify/check-superuser

673 lines
28 KiB
Python
Executable File

#!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/../common/pywrap", sys.argv)
# This file is part of Cockpit.
#
# Copyright (C) 2020 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
import time
from testlib import (
MachineCase,
nondestructive,
skipDistroPackage,
skipImage,
test_main,
todoPybridge,
todoPybridgeRHEL8,
wait,
)
def allow_old_cockpit_ws_messages(test):
# noisy debug message from old cockpit-ws/polkit
test.allow_journal_messages("logged in user session",
"New connection to session from.*",
"pam_unix(polkit-1:session): session opened for user root by .*uid=.*",
"admin: Executing command .*COMMAND=.*cockpit-bridge --privileged.*")
@nondestructive
@skipDistroPackage()
class TestSuperuser(MachineCase):
def testBasic(self):
b = self.browser
m = self.machine
# Log in with all defaults
self.login_and_go()
b.check_superuser_indicator("Administrative access")
b.assert_pixels("#topnav", "topnav-privileged")
# Drop privileges
b.open_superuser_dialog()
b.click(".pf-v5-c-modal-box:contains('Switch to limited access') button:contains('Limit access')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to limited access')")
b.check_superuser_indicator("Limited access")
b.assert_pixels("#topnav", "topnav-unprivileged")
# Check they are still gone after logout
b.relogin()
b.leave_page()
b.check_superuser_indicator("Limited access")
# We want to be lectured again
self.restore_file("/var/db/sudo/lectured/admin")
self.restore_file("/var/lib/sudo/lectured/admin")
m.execute("rm -rf /var/{db,lib}/sudo/lectured/admin")
# Get the privileges back, this time in the mobile layout
b.set_layout("mobile")
b.open_superuser_dialog()
if "ubuntu" not in m.image and m.image != "debian-testing":
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')",
"We trust you have received the usual lecture")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.focus(".pf-v5-c-modal-box button:contains('Cancel')")
b.assert_pixels(".pf-v5-c-modal-box:contains('Switch to administrative access')", "superuser-modal")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.check_superuser_indicator("Administrative access")
b.set_layout("desktop")
# Check we still have them after logout
b.relogin()
b.leave_page()
b.check_superuser_indicator("Administrative access")
def testNoPasswd(self):
b = self.browser
# Log in with limited access
self.login_and_go(superuser=False)
b.check_superuser_indicator("Limited access")
# Give us password-less sudo and use it
self.write_file("/etc/sudoers.d/admin", "admin ALL=(ALL) NOPASSWD:ALL")
b.become_superuser(passwordless=True)
def testTwoPasswds(self):
b = self.browser
m = self.machine
# Log in with limited access
self.login_and_go(superuser=False)
b.check_superuser_indicator("Limited access")
# Configure the sudo PAM stack to make two prompts
if "debian" in m.image or "ubuntu" in m.image:
self.write_file("/etc/pam.d/sudo", """
auth required pam_unix.so
auth required mock-pam-conv-mod.so
@include common-account
@include common-session-noninteractive
""")
else:
self.write_file("/etc/pam.d/sudo", """
auth required pam_unix.so
auth required mock-pam-conv-mod.so
account include system-auth
password include system-auth
session include system-auth
""")
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
# Let the dialog sit there for 45 seconds, to test that this doesn't trigger a D-Bus timeout.
time.sleep(45)
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "universe and everything")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "42")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.check_superuser_indicator("Administrative access")
def testWrongPasswd(self):
b = self.browser
# Log in with limited access
self.login_and_go(superuser=False)
b.check_superuser_indicator("Limited access")
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "wrong")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Sorry, try again")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "wronger")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Sorry, try again")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "wrongest")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Problem becoming administrator')", "Sudo: 3 incorrect password attempts")
b.click(".pf-v5-c-modal-box:contains('Problem becoming administrator') button:contains('Close')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Problem becoming administrator')")
b.check_superuser_indicator("Limited access")
def testNotAdmin(self):
b = self.browser
m = self.machine
# Remove special treatment of the "admin" group on Ubuntu.
# Our main test user is unfortunately called "admin" and has
# "admin" as its primary group.
#
if "ubuntu" in m.image:
self.sed_file("/^%admin/d", "/etc/sudoers")
m.execute(f"gpasswd -d admin {m.get_admin_group()}")
self.login_and_go()
b.check_superuser_indicator("Limited access")
b.open_superuser_dialog()
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Problem becoming administrator')", "Admin is not in the sudoers file.")
b.click(".pf-v5-c-modal-box:contains('Problem becoming administrator') button:contains('Close')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Problem becoming administrator')")
# no stray/hanging sudo process
wait(lambda: "sudo" not in m.execute("loginctl --lines=0 user-status admin"), tries=5)
# cancelling auth dialog stops sudo
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box", "Switch to administrative access")
b.wait_in_text(".pf-v5-c-modal-box", "Password for admin")
status = m.execute("loginctl --lines=0 user-status admin")
self.assertIn("sudo", status)
self.assertIn("cockpit-askpass", status)
b.click(".pf-v5-c-modal-box button:contains('Cancel')")
b.wait_not_present(".pf-v5-c-modal-box")
wait(lambda: "sudo" not in m.execute("loginctl --lines=0 user-status admin"), tries=5)
# logging out cleans up pending sudo auth; user should either go to "State: closing" or disappear completely
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box", "Password for admin")
self.assertIn("cockpit-askpass", m.execute("loginctl --lines=0 user-status admin"))
b.logout()
wait(lambda: "sudo" not in m.execute("loginctl --lines=0 user-status admin || true"), tries=10)
self.assertNotIn("cockpit", m.execute("loginctl --lines=0 user-status admin || true"))
def testBrokenBridgeConfig(self):
b = self.browser
m = self.machine
self.write_file("/etc/cockpit/shell.override.json", """
{
"bridges": [
{
"privileged": true,
"spawn": [
"sudo",
"-k",
"-A",
"cockpit-bridge",
"--privileged"
]
}
]
}
""")
# We don't want to be lectured in this test just to control
# the content of the dialog better.
m.execute("touch /var/{db,lib}/sudo/lectured/admin 2>/dev/null || true")
self.login_and_go(superuser=False)
b.check_superuser_indicator("Limited access")
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box:contains('Problem becoming administrator')", "Sudo: no askpass program specified, try setting SUDO_ASKPASS")
b.click(".pf-v5-c-modal-box:contains('Problem becoming administrator') button:contains('Close')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Problem becoming administrator')")
b.check_superuser_indicator("Limited access")
def testRemoveBridgeConfig(self):
m = self.machine
b = self.browser
self.login_and_go("/playground/pkgs", superuser=True)
b.leave_page()
b.check_superuser_indicator("Administrative access")
# superuser bridge is running
m.execute("pgrep -u root -a cockpit-bridge")
self.write_file("/etc/cockpit/shell.override.json", """
{
"bridges": [ ]
}
""")
b.enter_page("/playground/pkgs")
b.click("#reload")
b.leave_page()
if self.is_pybridge():
b.check_superuser_indicator("")
else:
# C bridge gets that wrong: Its .Bridges property remains at [sudo, pkexec], showing a broken indicator
b.check_superuser_indicator("Limited access")
# superuser bridge goes away
m.execute("while pgrep -u root -a cockpit-bridge; do sleep 1; done", timeout=5)
def testSingleLabelBridgeConfig(self):
b = self.browser
# When there is a single labeled privileged bridge, Cockit will start it automatically.
self.write_file("/etc/cockpit/shell.override.json", """
{
"bridges": [
{
"privileged": true,
"label": "Always fails",
"spawn": [
"/bin/bash", "-c", "echo >&2 'Hello from the bash method'; exit 1"
]
}
]
}
""")
self.login_and_go("/playground/pkgs", superuser=False)
b.leave_page()
b.check_superuser_indicator("Limited access")
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box:contains('Problem becoming administrator')", "Hello from the bash method")
b.click(".pf-v5-c-modal-box button:contains('Close')")
b.check_superuser_indicator("Limited access")
def testMultipleBridgeConfig(self):
b = self.browser
self.write_file("/etc/cockpit/shell.override.json", """
{
"bridges": [
{
"privileged": true,
"label": "Sudo",
"environ": [
"SUDO_ASKPASS=${libexecdir}/cockpit-askpass"
],
"spawn": [
"sudo",
"-k",
"-A",
"cockpit-bridge",
"--privileged"
]
},
{
"privileged": true,
"label": "Polkit",
"spawn": [
"pkexec",
"--disable-internal-agent",
"cockpit-bridge",
"--privileged"
]
}
]
}
""")
self.login_and_go("/playground/pkgs", superuser=False)
b.leave_page()
b.check_superuser_indicator("Limited access")
# Get admin rights with Polkit method
b.open_superuser_dialog()
b.set_val(".pf-v5-c-modal-box:contains('Switch to administrative access') select", "Polkit")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access') select", "Polkit")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Please authenticate")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.check_superuser_indicator("Administrative access")
# Drop them
b.open_superuser_dialog()
b.click(".pf-v5-c-modal-box:contains('Switch to limited access') button:contains('Limit access')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to limited access')")
b.check_superuser_indicator("Limited access")
# Run the regular sudo method, which should work as always
b.open_superuser_dialog()
b.set_val(".pf-v5-c-modal-box:contains('Switch to administrative access') select", "Sudo")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access') select", "Sudo")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.check_superuser_indicator("Administrative access")
def testOverview(self):
b = self.browser
self.login_and_go("/system", superuser=False)
b.wait_visible(".pf-v5-c-alert:contains('Web console is running in limited access mode.')")
b.click(".pf-v5-c-alert:contains('Web console is running in limited access mode.') button:contains('Turn on')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.wait_not_present(".pf-v5-c-alert:contains('Web console is running in limited access mode.')")
@skipDistroPackage()
class TestSuperuserOldShell(MachineCase):
provision = {
"machine1": {"address": "10.111.113.1/20", "memory_mb": 512},
"machine2": {"address": "10.111.113.2/20", "image": "centos-7", "memory_mb": 512},
}
def test(self):
b = self.browser
m = self.machine
m.start_cockpit()
# Use m1 to login into m2
b.open("/")
b.wait_visible("#login")
b.set_val("#login-user-input", "admin")
b.set_val("#login-password-input", "foobar")
b.click("#show-other-login-options")
b.wait_visible("#server-group")
b.set_val("#server-field", "10.111.113.2")
b.click('#login-button')
b.wait_in_text("#server-name", "10.111.113.2")
b.wait_visible("#hostkey-group")
b.wait_in_text("#hostkey-message-1", "You are connecting to 10.111.113.2 for the first time.")
b.click('#login-button')
b.wait_visible('#content')
# The old shell should have gotten the password from cockpit-ws and it should work
b.enter_page("/system")
b.click("#shutdown-group > button:contains('Restart')")
b.wait_popup("shutdown-dialog")
b.click("#shutdown-dialog button:contains('Restart')")
b.wait_popdown("shutdown-dialog")
@skipImage("TODO: broken on Arch Linux", "arch")
@skipDistroPackage()
class TestSuperuserOldWebserver(MachineCase):
provision = {
"machine1": {"address": "10.111.113.1/20", "image": "centos-7", "memory_mb": 512},
"machine2": {"address": "10.111.113.2/20", "memory_mb": 512},
}
@todoPybridge(reason="https://github.com/cockpit-project/cockpit/issues/18712")
def test(self):
b = self.browser
m = self.machine
allow_old_cockpit_ws_messages(self)
m.execute("firewall-cmd --add-service cockpit")
m.start_cockpit()
# Use m1 to login into m2
b.open("/")
b.wait_visible("#login")
b.set_val("#login-user-input", "admin")
b.set_val("#login-password-input", "foobar")
b.set_checked('#authorized-input', True)
b.click("#show-other-login-options")
b.wait_visible("#server-group")
b.set_val("#server-field", "10.111.113.2")
b.click('#login-button')
b.wait_in_text("#server-name", "10.111.113.2")
b.wait_visible("#conversation-group")
b.wait_in_text("#conversation-prompt", "Fingerprint")
b.wait_in_text("#conversation-message", "Do you want to proceed this time?")
b.click('#login-button')
b.wait_visible('#content')
# We should have gotten the password from the old cockpit-ws and it should work
b.check_superuser_indicator("Administrative access")
b.go("/playground/test")
b.enter_page("/playground/test")
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'result: ')
self.assertIn('result: uid=0', b.text(".super-channel span"))
def testNotAuth(self):
b = self.browser
m = self.machine
allow_old_cockpit_ws_messages(self)
m.execute("firewall-cmd --add-service cockpit")
m.start_cockpit()
# Use m1 to login into m2, but don't reuse the password
b.open("/")
b.wait_visible("#login")
b.set_val("#login-user-input", "admin")
b.set_val("#login-password-input", "foobar")
b.set_checked('#authorized-input', False)
b.click("#show-other-login-options")
b.wait_visible("#server-group")
b.set_val("#server-field", "10.111.113.2")
b.click('#login-button')
b.wait_in_text("#server-name", "10.111.113.2")
b.wait_visible("#conversation-group")
b.wait_in_text("#conversation-prompt", "Fingerprint")
b.wait_in_text("#conversation-message", "Do you want to proceed this time?")
b.click('#login-button')
b.wait_visible('#content')
# We should not have gotten the password from the old
# cockpit-ws, but we can get it back.
b.check_superuser_indicator("Limited access")
b.go("/playground/test")
b.enter_page("/playground/test")
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'access-denied')
b.switch_to_top()
b.open_superuser_dialog()
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.check_superuser_indicator("Administrative access")
b.go("/playground/test")
b.enter_page("/playground/test")
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'result: ')
self.assertIn('result: uid=0', b.text(".super-channel span"))
@skipDistroPackage()
class TestSuperuserDashboard(MachineCase):
provision = {
"machine1": {"address": "10.111.113.1/20", "memory_mb": 512},
"machine2": {"address": "10.111.113.2/20", "memory_mb": 512},
}
@todoPybridgeRHEL8()
def test(self):
b = self.browser
self.setup_provisioned_hosts()
self.login_and_go()
b.go("/@10.111.113.2")
b.wait_visible("#machine-troubleshoot")
b.click('#machine-troubleshoot')
b.wait_visible('#hosts_setup_server_dialog')
b.wait_visible('#hosts_setup_server_dialog button:contains("Add")')
b.click('#hosts_setup_server_dialog button:contains("Add")')
b.wait_in_text('#hosts_setup_server_dialog', "You are connecting to 10.111.113.2 for the first time.")
b.click('#hosts_setup_server_dialog button:contains("Accept key and connect")')
b.wait_in_text('#hosts_setup_server_dialog', "Unable to log in")
b.set_input_text("#login-custom-password", "foobar")
b.click('#hosts_setup_server_dialog button:contains("Log in")')
b.wait_not_present('#hosts_setup_server_dialog')
# There should be no superuser indicator in the Overview
b.go("/@10.111.113.2/system")
b.enter_page("/system", host="10.111.113.2")
b.wait_not_present(".ct-overview-header-actions button:contains('Administrative access')")
b.wait_not_present(".ct-overview-header-actions button:contains('Limited access')")
b.leave_page()
# The superuser indicator in the Shell should apply to machine2
b.check_superuser_indicator("Limited access")
b.become_superuser()
b.go("/@10.111.113.2/playground/test")
b.enter_page("/playground/test", host="10.111.113.2")
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'result: ')
self.assertIn('result: uid=0', b.text(".super-channel span"))
b.drop_superuser()
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'access-denied')
# back to superuser on machine2
b.become_superuser()
user = self.machines["machine2"].execute("loginctl user-status admin")
self.assertIn("cockpit-bridge --privileged", user)
# no stray askpass process
self.assertNotIn("cockpit-askpass", user)
# logging out cleans up logind sessions on both machines
b.logout()
for m in [self.machine, self.machines["machine2"]]:
m.execute('while [ "$(loginctl show-user --property=State --value admin)" = "active" ]; do sleep 1; done')
self.assertNotIn("cockpit", "loginctl user-status admin")
self.allow_hostkey_messages()
@skipDistroPackage()
class TestSuperuserOldDashboard(MachineCase):
provision = {
"machine1": {"address": "10.111.113.1/20", "image": "centos-7", "memory_mb": 512},
"machine2": {"address": "10.111.113.2/20", "memory_mb": 512},
}
@todoPybridge(reason="https://github.com/cockpit-project/cockpit/issues/18712")
def test(self):
b = self.browser
m = self.machines["machine1"]
allow_old_cockpit_ws_messages(self)
self.allow_hostkey_messages()
self.setup_provisioned_hosts()
m.execute("firewall-cmd --add-service cockpit")
m.start_cockpit()
# Log into m1 and add m2
b.open("/")
b.wait_visible("#login")
b.set_val("#login-user-input", "admin")
b.set_val("#login-password-input", "foobar")
b.set_checked('#authorized-input', True)
b.click('#login-button')
b.wait_visible('#content')
b.go("/@10.111.113.2")
b.wait_visible("#machine-troubleshoot")
b.click('#machine-troubleshoot')
b.wait_popup('troubleshoot-dialog')
b.click('#troubleshoot-dialog button:contains("Add")')
b.wait_in_text('#troubleshoot-dialog', "Fingerprint")
b.click('#troubleshoot-dialog button:contains("Connect")')
b.wait_popdown('troubleshoot-dialog')
# There should be a superuser button in the Overview of machine2
b.enter_page("/system", host="10.111.113.2")
b.click(".ct-overview-header-actions button:contains('Administrative access')")
b.click(".pf-v5-c-modal-box:contains('Switch to limited access') button:contains('Limit access')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to limited access')")
b.wait_visible(".ct-overview-header-actions button:contains('Limited access')")
b.go("/@10.111.113.2/playground/test")
b.enter_page("/playground/test", host="10.111.113.2")
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'access-denied')
b.go("/@10.111.113.2")
b.enter_page("/system", host="10.111.113.2")
b.click(".ct-overview-header-actions button:contains('Limited access')")
b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:")
b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar")
b.click(".pf-v5-c-modal-box button:contains('Authenticate')")
b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')")
b.wait_visible(".ct-overview-header-actions button:contains('Administrative access')")
b.go("/@10.111.113.2/playground/test")
b.enter_page("/playground/test", host="10.111.113.2")
b.click(".super-channel button")
b.wait_in_text(".super-channel span", 'result: ')
self.assertIn('result: uid=0', b.text(".super-channel span"))
@skipDistroPackage()
class TestSuperuserDashboardOldMachine(MachineCase):
provision = {
"machine1": {"address": "10.111.113.1/20"},
"machine2": {"address": "10.111.113.2/20", "image": "centos-7"},
}
@todoPybridge(reason="https://github.com/cockpit-project/cockpit/issues/18712")
def test(self):
b = self.browser
self.setup_provisioned_hosts()
self.login_and_go()
b.go("/@10.111.113.2")
b.wait_visible("#machine-troubleshoot")
b.click('#machine-troubleshoot')
b.wait_visible('#hosts_setup_server_dialog')
b.click('#hosts_setup_server_dialog button:contains("Add")')
b.wait_in_text('#hosts_setup_server_dialog', "You are connecting to 10.111.113.2 for the first time.")
b.click('#hosts_setup_server_dialog button:contains("Accept key and connect")')
b.wait_in_text('#hosts_setup_server_dialog', "Unable to log in")
b.set_input_text("#login-custom-password", "foobar")
b.click('#hosts_setup_server_dialog button:contains("Log in")')
b.wait_not_present('#hosts_setup_server_dialog')
# Since user and password are the same on machine2, we should
# have gotten admin rights.
b.enter_page("/system", host="10.111.113.2")
b.click("#shutdown-group > button:contains('Restart')")
b.wait_popup("shutdown-dialog")
b.click("#shutdown-dialog button:contains('Restart')")
b.wait_popdown("shutdown-dialog")
self.allow_hostkey_messages()
if __name__ == '__main__':
test_main()