Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shell: Remove the "half-off" mode of the host switcher #20825

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,21 @@ fi

AM_CONDITIONAL([ENABLE_DOC], [test "$enable_doc" = "yes"])

# Default for AllowMultiHost

AC_MSG_CHECKING([for AllowMultiHost default])
AC_ARG_ENABLE(multihost,
AS_HELP_STRING([--disable-multihost],
[Set AllowMultiHost to false by default]),
[], [enable_multihost=yes])
AC_MSG_RESULT($enable_multihost)
if test "$enable_multihost" != "no"; then
multihost_def=1
else
multihost_def=0
fi
AC_DEFINE_UNQUOTED(ALLOW_MULTIHOST_DEFAULT, [$multihost_def], [default for AllowMultiHost configuration setting])

# cockpit-client
AC_MSG_CHECKING([whether to install cockpit-client])
AC_ARG_ENABLE([cockpit-client],
Expand Down
18 changes: 18 additions & 0 deletions doc/man/cockpit.conf.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ ForwardedForHeader = X-Forwarded-For
<emphasis>Connect to</emphasis> option to specify the host to log into.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>AllowMultiHost</option></term>
<listitem>
<para>
When set to <literal>true</literal>, cockpit will allow
users to connect to multiple hosts in one session. The
default is OS specific.
</para>
<para>
Connecting to multiple hosts in one session might be
problematic since the browser will load JavaScript code
from these hosts and execute it all without isolation from
each other. This gives one host full access to all other
hosts in that session, exposing every host to bugs and
malice served from any other host.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>MaxStartups</option></term>
<listitem><para>Same as the <command>sshd</command> configuration option by the same name.
Expand Down
22 changes: 1 addition & 21 deletions pkg/shell/hosts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ import {
CaretDownIcon,
CaretUpIcon,
EditIcon,
ExclamationCircleIcon,
ExternalLinkAltIcon,
MinusIcon,
} from '@patternfly/react-icons';
import { Label } from "@patternfly/react-core/dist/esm/components/Label";
import { PageSidebar } from "@patternfly/react-core/dist/esm/components/Page";
import { Popover } from "@patternfly/react-core/dist/esm/components/Popover";
import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip";

import 'polyfills';
Expand Down Expand Up @@ -197,22 +193,7 @@ export class CockpitHosts extends React.Component {
const label = this.props.machine.label || "";
const user = this.props.machine.user || this.state.current_user;

let add_host_action;

if (this.props.enable_add_host) {
add_host_action = <Button variant="secondary" onClick={this.onAddNewHost}>{_("Add new host")}</Button>;
} else {
const footer = <a href="https://cockpit-project.org/blog/cockpit-322.html" target="_blank" rel="noreferrer">
<ExternalLinkAltIcon /> {_("Read more...")}
</a>;
add_host_action = (
<Popover id="disabled-add-host-help"
headerContent={_("Host switching is not supported")}
bodyContent={_("Connecting to remote hosts inside of a web console session is deprecated and will be removed in the future. You can still connect to your existing hosts for now.")}
footerContent={footer}>
<Label className="deprecated-add-host" color="blue" icon={<ExclamationCircleIcon />}>{_("Deprecated")}</Label>
</Popover>);
}
const add_host_action = <Button variant="secondary" onClick={this.onAddNewHost}>{_("Add new host")}</Button>;

return (
<>
Expand Down Expand Up @@ -285,5 +266,4 @@ CockpitHosts.propTypes = {
selector: PropTypes.string.isRequired,
hostAddr: PropTypes.func.isRequired,
jump: PropTypes.func.isRequired,
enable_add_host: PropTypes.bool.isRequired,
};
25 changes: 12 additions & 13 deletions pkg/shell/indexes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import { CockpitHosts, CockpitCurrentHost } from "./hosts.jsx";
import { codes, HostModal } from "./hosts_dialog.jsx";
import { EarlyFailure, EarlyFailureReady } from './failures.jsx';
import { WithDialogs } from "dialogs.jsx";
import { read_os_release } from "os-release";
import { get_manifest_config_matchlist } from "utils";

import * as base_index from "./base_index";

Expand Down Expand Up @@ -103,15 +101,9 @@ function MachinesIndex(index_options, machines, loader) {

/* Host switcher enabled? */
let host_switcher_enabled = false;
read_os_release().then(os_release => {
const enabled = os_release && get_manifest_config_matchlist(
"shell", "host_switcher", false,
[os_release.PLATFORM_ID, os_release.VERSION_CODENAME]);
if (enabled) {
host_switcher_enabled = true;
update_machines();
}
});
const meta_multihost = document.head.querySelector("meta[name='allow-multihost']");
if (meta_multihost instanceof HTMLMetaElement && meta_multihost.content == "yes")
host_switcher_enabled = true;

/* Navigation */
let ready = false;
Expand Down Expand Up @@ -187,6 +179,14 @@ function MachinesIndex(index_options, machines, loader) {

if (!state)
state = index.retrieve_state();

// Force a redirect to localhost when the host switcher is
// disabled. That way, people won't accidentally connect to
// remote machines via URL bookmarks or similar that point to
// them.
if (!host_switcher_enabled)
state.host = "localhost";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test.


let machine = machines.lookup(state.host);

/* No such machine */
Expand Down Expand Up @@ -389,15 +389,14 @@ function MachinesIndex(index_options, machines, loader) {
machine = machines.lookup(state.host);

// deprecation transition period: show existing remote hosts, but disable adding new ones
if (host_switcher_enabled || machines.list.length > 1) {
if (host_switcher_enabled) {
hosts_sel_root.render(
React.createElement(CockpitHosts, {
machine: machine || {},
machines,
selector: "nav-hosts",
hostAddr: index.href,
jump: index.jump,
enable_add_host: host_switcher_enabled,
}));
} else {
hosts_sel_root.render(React.createElement(CockpitCurrentHost, { machine: machine || {} }));
Expand Down
8 changes: 8 additions & 0 deletions src/ws/cockpitchannelresponse.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "cockpitchannelresponse.h"

#include "common/cockpitchannel.h"
#include "common/cockpitconf.h"
#include "common/cockpitflow.h"
#include "common/cockpitwebinject.h"
#include "common/cockpitwebserver.h"
Expand Down Expand Up @@ -103,6 +104,13 @@ cockpit_channel_inject_perform (CockpitChannelInject *inject,
prefixed_application = g_strdup_printf ("/%s", cockpit_creds_get_application (creds));
}

{
const gboolean allow_multihost = cockpit_conf_bool ("WebService", "AllowMultiHost",
ALLOW_MULTIHOST_DEFAULT);
g_string_append_printf (str, "\n <meta name=\"allow-multihost\" content=\"%s\">",
allow_multihost ? "yes" : "no");
}

if (inject->base_path)
{
const gchar *checksum = cockpit_web_service_get_checksum (inject->service, inject->host);
Expand Down
3 changes: 3 additions & 0 deletions src/ws/cockpithandlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ add_page_to_environment (JsonObject *object,
{
static gint page_login_to = -1;
gboolean require_host = FALSE;
gboolean allow_multihost;
JsonObject *page;
const gchar *value;

Expand All @@ -268,9 +269,11 @@ add_page_to_environment (JsonObject *object,
}

require_host = is_cockpit_client || cockpit_conf_bool ("WebService", "RequireHost", FALSE);
allow_multihost = cockpit_conf_bool ("WebService", "AllowMultiHost", ALLOW_MULTIHOST_DEFAULT);

json_object_set_boolean_member (page, "connect", page_login_to);
json_object_set_boolean_member (page, "require_host", require_host);
json_object_set_boolean_member (page, "allow_multihost", allow_multihost);
json_object_set_object_member (object, "page", page);
}

Expand Down
9 changes: 7 additions & 2 deletions test/common/testlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1623,8 +1623,8 @@ def setUp(self, restrict: bool = True) -> None:
self.sshd_socket = 'sshd.socket'
self.restart_sshd = f'systemctl try-restart {self.sshd_service}'

# only enabled by default on released OSes; see pkg/shell/manifest.json
self.multihost_enabled = image.startswith(("rhel-9", "centos-9")) or image in ["ubuntu-2204", "ubuntu-stable", "debian-stable", "fedora-39", "fedora-40", "fedora-coreos"]
# enabled by default except on RHEL 10 and friends.
self.multihost_enabled = image not in ["rhel-10", "centos-10"]

def nonDestructiveSetup(self) -> None:
"""generic setUp/tearDown for @nondestructive tests"""
Expand Down Expand Up @@ -1776,6 +1776,11 @@ def tearDown(self) -> None:

shutil.rmtree(self.tmpdir, ignore_errors=True)

def enable_multihost(self, machine: testvm.Machine) -> None:
if not self.multihost_enabled:
machine.write("/etc/cockpit/shell.override.json",
'{ "config": { "host_switcher": true } }')

def login_and_go(
self,
path: str | None = None,
Expand Down
21 changes: 0 additions & 21 deletions test/verify/check-shell-host-switching
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,6 @@ class TestHostSwitching(testlib.MachineCase, HostSwitcherHelpers):
self.allow_restart_journal_messages()
self.allow_hostkey_messages()

def enable_multihost(self, machine):
if not self.multihost_enabled:
machine.write("/etc/cockpit/shell.override.json",
'{ "config": { "host_switcher": true } }')

def testBasic(self):
b = self.browser
m1 = self.machines["machine1"]
Expand All @@ -139,22 +134,6 @@ class TestHostSwitching(testlib.MachineCase, HostSwitcherHelpers):
b.assert_pixels("#hosts-sel", "no-switching", skip_layouts=["mobile"])
b.logout()

# transition period: Existing remote hosts are still shown
m1.write("/etc/cockpit/machines.d/99-webui.json",
'{"srv": { "address": "my.srv", "visible": true }}')
b.login_and_go(superuser=False)
b.click("#hosts-sel button")
self.wait_host_addresses(b, ["localhost", "my.srv"])
b.wait_in_text(".deprecated-add-host", "Deprecated")
b.assert_pixels(".nav-hosts-actions", "deprecated", skip_layouts=["mobile"])
# clicking on it shows popover with help
b.click(".deprecated-add-host")
b.wait_text("#popover-disabled-add-host-help-header", "Host switching is not supported")
b.click(".pf-v5-c-popover__close button")
b.wait_not_present("#popover-disabled-add-host-help-header")
b.logout()
m1.execute("rm /etc/cockpit/machines.d/99-webui.json")

# enable host switcher for this test
self.enable_multihost(m1)
b.login_and_go(superuser=False)
Expand Down
2 changes: 2 additions & 0 deletions test/verify/check-shell-multi-machine
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class TestMultiMachineAdd(testlib.MachineCase):
# and failing to load sofware updates breaks pixel tests in release builds
self.setup_provisioned_hosts(disable_preload=True)
self.setup_ssh_auth()
self.enable_multihost(self.machine)

def testBasic(self):
b = self.browser
Expand Down Expand Up @@ -250,6 +251,7 @@ class TestMultiMachine(testlib.MachineCase):
self.allow_journal_messages("sudo: unable to resolve host machine1: .*")

self.setup_provisioned_hosts(disable_preload=True)
self.enable_multihost(self.machine)

def checkDirectLogin(self, root='/', known_host=False):
b = self.browser
Expand Down
1 change: 1 addition & 0 deletions test/verify/check-shell-multi-os
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class TestRHEL8(testlib.MachineCase):

stock_m = self.machines['stock']
stock_m.execute("hostnamectl set-hostname stock")
self.enable_multihost(dev_m)

# Wait for connectivity between the two
stock_m.execute("ping -q -w5 -c5 10.111.113.1")
Expand Down
1 change: 1 addition & 0 deletions test/verify/check-superuser
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ class TestSuperuserDashboard(testlib.MachineCase):
def test(self):
b = self.browser
self.setup_provisioned_hosts()
self.enable_multihost(self.machine)

self.login_and_go()
b.go("/@10.111.113.2")
Expand Down
2 changes: 2 additions & 0 deletions test/verify/check-system-realms
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ class TestRealms(testlib.MachineCase):
self.op_admin_password = "#realms-op-admin-password"
self.domain_sel = "#system_information_domain_button"
self.machine.execute("hostnamectl set-hostname x0.cockpit.lan")
self.enable_multihost(self.machine)

# realmd times out on inactivity, which occasionally races with the proxy
self.allow_journal_messages("couldn't get all properties of org.freedesktop.realmd.Service.*org.freedesktop.DBus.Error.NoReply: Remote peer disconnected")
Expand Down Expand Up @@ -989,6 +990,7 @@ class TestKerberos(testlib.MachineCase):
def setUp(self):
super().setUp()
maybe_setup_fake_chrony(self.machine)
self.enable_multihost(self.machine)

def configure_kerberos(self, keytab):
self.machines["services"].execute("/root/run-freeipa")
Expand Down
2 changes: 2 additions & 0 deletions test/verify/check-system-shutdown-restart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class TestShutdownRestart(testlib.MachineCase):
m2 = self.machines['machine2']
b2 = self.new_browser(m2)

self.enable_multihost(m2)

m.start_cockpit()

self.login_and_go("/system")
Expand Down
8 changes: 8 additions & 0 deletions tools/cockpit.spec
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ ExcludeArch: %{ix86}
%endif
%endif

%define enable_multihost 1
%if 0%{?rhel} >= 10
%define enable_multihost 0
%endif

# Ship custom SELinux policy
%define selinuxtype targeted
%define selinux_configure_arg --enable-selinux-policy=%{selinuxtype}
Expand Down Expand Up @@ -165,6 +170,9 @@ BuildRequires: python3-tox-current-env
%if %{build_pcp} == 0
--disable-pcp \
%endif
%if %{enable_multihost} == 0
--disable-multihost \
%endif

%make_build

Expand Down