#!/usr/bin/python # -*- coding: utf-8 -*- # This file is part of Cockpit. # # Copyright (C) 2016 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 . import parent from testlib import * FIX_AUDITD = """ set -e mkdir -p /var/log/audit touch /var/log/audit.log restorecon -r /var/log/audit systemctl start auditd """ SELINUX_ALERT_SCRIPT = """ set -e mkdir -p ~/selinux_temp cd ~/selinux_temp cp /bin/ls ls chcon -t httpd_exec_t ls # this won't work, but it generates an error runcon -u system_u -r system_r -t httpd_t -- ./ls /home/* || true """ SELINUX_FIXABLE_ALERT_SCRIPT = """ set -e mkdir -p ~/.ssh ssh-keygen -t rsa -f ~/.ssh/test-avc-rsa -N "" mv -f ~/.ssh/authorized_keys ~/.ssh/authorized_keys.test-avc cat .ssh/test-avc-rsa.pub >> ~/.ssh/authorized_keys chcon -t tmp_t ~/.ssh/authorized_keys ssh -o StrictHostKeyChecking=no -o 'BatchMode=yes' -i ~/.ssh/test-avc-rsa localhost || true mv -f ~/.ssh/authorized_keys.test-avc ~/.ssh/authorized_keys """ @skipImage("DBus API of setroubleshoot too old", "centos-7") class TestSelinux(MachineCase): @skipImage("No setroubleshoot", "continuous-atomic", "debian-stable", "debian-testing", "fedora-atomic", "rhel-atomic", "ubuntu-1604", "ubuntu-stable") def testTroubleshootAlerts(self): b = self.browser self.login_and_go("/selinux/setroubleshoot") # at the beginning, there should be no entries b.wait_in_text("body", "No SELinux alerts.") # fix audit events first self.machine.execute(script=FIX_AUDITD) ######################################################### # trigger an alert self.machine.execute(script=SELINUX_ALERT_SCRIPT) row_selector = "tbody:contains('ls from read access on the directory')" # wait for the alert to appear b.wait_present(row_selector) # expand it to see details toggle_selector = row_selector + " .listing-ct-toggle" b.wait_present(toggle_selector) b.click(toggle_selector) # this should have two alerts, but there seems to be a known issue that some messages are delayed # b.wait_in_text(row_selector, "2 occurrences") panel_selector = row_selector + " tr.listing-ct-panel" # a solution is present b.wait_present(panel_selector) b.wait_in_text(panel_selector, "You must tell SELinux about this by enabling the 'httpd_read_user_content' boolean.") # ... but we can't apply it automatically # there are several solutions this can match against - that's ok, we want at least one to have this message b.wait_in_text(panel_selector, "Unable to apply this solution automatically") # collapse again b.click(toggle_selector) # wait until it is collapsed b.wait_not_in_text(row_selector, "You must tell SELinux about this by enabling the 'httpd_read_user_content' boolean.") # now expand again so we can dismiss the alert b.click(toggle_selector) b.wait_present(row_selector + " button.pficon-delete") # HACK: we need updated test images for delete to work # dismiss the alert #b.click(row_selector + " button.pficon-delete") #b.wait_not_present(row_selector) #b.wait_in_text("body", "No SELinux alerts.") ######################################################### # trigger a fixable alert self.machine.execute(script=SELINUX_FIXABLE_ALERT_SCRIPT) row_selector = "tbody:contains('sshd from open access on the file')" # wait for the alert to appear b.wait_present(row_selector) # expand it to see details toggle_selector = row_selector + " .listing-ct-toggle" b.wait_present(toggle_selector) b.click(toggle_selector) panel_selector = row_selector + " tr.listing-ct-panel" # a solution is present b.wait_present(panel_selector) b.wait_in_text(panel_selector, "you can run restorecon") # and it can be applied btn_sel = "div.list-group-item:contains('you can run restorecon') button" b.click(btn_sel) # HACK there's a known issue where setroubleshoot is unable to run the fix # the fix should be applied b.wait_in_text(row_selector, "Solution applied successfully:") # b.wait_in_text(row_selector, "Successfully ran /sbin/restorecon") # HACK: we need updated test images for delete to work # dismiss the alert #b.click(row_selector + " button.pficon-delete") #b.wait_not_present(row_selector) #b.wait_in_text("body", "No SELinux alerts.") @skipImage("No cockpit-selinux", "debian-stable", "debian-testing", "continuous-atomic", "fedora-atomic", "ubuntu-1604", "ubuntu-stable") def testEnforcingToggle(self): b = self.browser m = self.machine # HACK: http://bugzilla.redhat.com/show_bug.cgi?id=1346364 # This issue happens when selinux item is in kickstart # as happens in our virt-builder and virt-install usage m.execute("chmod ugo+r /etc/selinux/config") self.login_and_go("/selinux/setroubleshoot") ######################################################### # wait for the page to be present b.wait_in_text("body", "SELinux Policy") # SELinux should be enabled and enforcing at the beginning on_off_selector_active = "div.btn-onoff-ct label.active" b.wait_in_text(on_off_selector_active, "On") m.execute("getenforce | grep -q 'Enforcing'") # now set to permissive using the ui button b.click("div.btn-onoff-ct label.active span") b.wait_in_text(on_off_selector_active, "Off") m.execute("getenforce | grep -q 'Permissive'") # when in permissive mode, expect a warning b.wait_in_text("div.selinux-policy-ct", "Setting deviates") # switch back using cli, ui should react m.execute("setenforce 1") b.wait_in_text(on_off_selector_active, "On") # warning should disappear b.wait_not_in_text("div.selinux-policy-ct", "Setting deviates") # Switch to another page b.switch_to_top() b.go("/system") b.enter_page("/system") # Now on another page change the status m.execute("setenforce 0") # Switch back into the page and we get the updated status b.switch_to_top() b.go("/selinux/setroubleshoot") b.enter_page("/selinux/setroubleshoot") b.wait_in_text(on_off_selector_active, "Off") b.wait_in_text("div.selinux-policy-ct", "Setting deviates") if __name__ == '__main__': test_main()