On 08/30/2013 03:28 PM, Petr Viktorin wrote: > On 08/28/2013 03:04 PM, Ana Krivokapic wrote: >> Hello, >> >> This patch adds integration tests for the forced client re-enrollment >> feature, according to the test plan at: >> http://www.freeipa.org/page/V3/Forced_client_re-enrollment#Test_Plan >> >> >> https://fedorahosted.org/freeipa/ticket/3832 > > Thank you! The tests are good. As expected I have some nitpicks below. > > > I recommend putting the test case names from the wiki in the method > docstrings. > > [...] >> + def restore_client(self): >> + client = self.clients[0] > > I'll ask you to allow SSH here, because the controller can theoretically also > act as one of the test hosts: > > iptables -A INPUT -p tcp --dport 22 -j ACCEPT > >> + client.run_command([ >> + 'iptables', >> + '-A', 'INPUT', >> + '-j', 'REJECT', >> + '-p', 'all', >> + '--source', self.master.ip >> + ]) >> + self.uninstall_client() >> + client.run_command(['iptables', '-F']) > > [...] >> + def backup_keytab(self): >> + self.clients[0].get_file(CLIENT_KEYTAB, TEMP_KEYTAB) >> + self.master.put_file(TEMP_KEYTAB, BACKUP_KEYTAB) > > Please use get_file_contents & put_file_contents. There might be more tests > running on the controller machine, we don't want to use a shared file. > For BACKUP_KEYTAB and EMPTY_KEYTAB please use a file inside > master.config.test_dir; we don't want to leave files on the testing machines. > The test_dir gets cleaned up. >
Thanks for the review! All issues are fixed in the updated patch. -- Regards, Ana Krivokapic Associate Software Engineer FreeIPA team Red Hat Inc.
From 3afc75d270e6e899acf98b20a1f65f48811ca8fa Mon Sep 17 00:00:00 2001 From: Ana Krivokapic <akriv...@redhat.com> Date: Wed, 28 Aug 2013 14:58:44 +0200 Subject: [PATCH] Add integration tests for forced client re-enrollment Add integration tests for the forced client re-enrollment feature: http://www.freeipa.org/page/V3/Forced_client_re-enrollment#Test_Plan https://fedorahosted.org/freeipa/ticket/3832 --- .../test_forced_client_reenrollment.py | 278 +++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 ipatests/test_integration/test_forced_client_reenrollment.py diff --git a/ipatests/test_integration/test_forced_client_reenrollment.py b/ipatests/test_integration/test_forced_client_reenrollment.py new file mode 100644 index 0000000000000000000000000000000000000000..4ba4cda1d4fe509110fffa91e1c13d78b457f64d --- /dev/null +++ b/ipatests/test_integration/test_forced_client_reenrollment.py @@ -0,0 +1,278 @@ +# Authors: +# Ana Krivokapic <akriv...@redhat.com> +# +# Copyright (C) 2013 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import subprocess + +from ipatests.test_integration.base import IntegrationTest +from ipatests.test_integration import tasks + +CLIENT_KEYTAB = '/etc/krb5.keytab' + + +class TestForcedClientReenrollment(IntegrationTest): + """ + Forced client re-enrollment + http://www.freeipa.org/page/V3/Forced_client_re-enrollment#Test_Plan + """ + num_replicas = 1 + num_clients = 1 + + @classmethod + def install(cls): + super(TestForcedClientReenrollment, cls).install() + tasks.install_master(cls.master) + tasks.install_replica(cls.master, cls.replicas[0], setup_ca=False) + cls.BACKUP_KEYTAB = os.path.join( + cls.master.config.test_dir, + 'krb5.keytab' + ) + + def setUp(self): + tasks.prepare_host(self.clients[0]) + tasks.install_client(self.master, self.clients[0]) + + def tearDown(self): + tasks.uninstall_client(self.clients[0]) + self.delete_client_host_entry() + + def test_reenroll_with_force_join(self): + """ + Client re-enrollment using admin credentials (--force-join) + """ + sshfp_record_pre = self.get_sshfp_record() + self.restore_client() + self.check_client_host_entry() + self.reenroll_client(force_join=True) + sshfp_record_post = self.get_sshfp_record() + assert sshfp_record_pre == sshfp_record_post + + def test_reenroll_with_keytab(self): + """ + Client re-enrollment using keytab + """ + self.backup_keytab() + sshfp_record_pre = self.get_sshfp_record() + self.restore_client() + self.check_client_host_entry() + self.restore_keytab() + self.reenroll_client(keytab=self.BACKUP_KEYTAB) + sshfp_record_post = self.get_sshfp_record() + assert sshfp_record_pre == sshfp_record_post + + def test_reenroll_with_both_force_join_and_keytab(self): + """ + Client re-enrollment using both --force-join and --keytab options + """ + self.backup_keytab() + sshfp_record_pre = self.get_sshfp_record() + self.restore_client() + self.check_client_host_entry() + self.restore_keytab() + self.reenroll_client(force_join=True, keytab=self.BACKUP_KEYTAB) + sshfp_record_post = self.get_sshfp_record() + assert sshfp_record_pre == sshfp_record_post + + def test_reenroll_to_replica(self): + """ + Client re-enrollment using keytab, to a replica + """ + self.backup_keytab() + sshfp_record_pre = self.get_sshfp_record() + self.restore_client() + self.check_client_host_entry() + self.restore_keytab() + self.reenroll_client(keytab=self.BACKUP_KEYTAB, to_replica=True) + sshfp_record_post = self.get_sshfp_record() + assert sshfp_record_pre == sshfp_record_post + + def test_try_to_reenroll_with_disabled_host(self): + """ + Client re-enrollment using keytab, with disabled host + """ + self.backup_keytab() + self.disable_client_host_entry() + self.restore_client() + self.check_client_host_entry(enabled=False) + self.restore_keytab() + self.reenroll_client(keytab=self.BACKUP_KEYTAB, expect_fail=True) + + def test_try_to_reenroll_with_uninstalled_host(self): + """ + Client re-enrollment using keytab, with uninstalled host + """ + self.backup_keytab() + self.uninstall_client() + self.restore_client() + self.check_client_host_entry(enabled=False) + self.restore_keytab() + self.reenroll_client(keytab=self.BACKUP_KEYTAB, expect_fail=True) + + def test_try_to_reenroll_with_deleted_host(self): + """ + Client re-enrollment using keytab, with deleted host + """ + self.backup_keytab() + self.delete_client_host_entry() + self.restore_client() + self.check_client_host_entry(not_found=True) + self.restore_keytab() + self.reenroll_client(keytab=self.BACKUP_KEYTAB, expect_fail=True) + + def test_try_to_reenroll_with_incorrect_keytab(self): + """ + Client re-enrollment using keytab, with incorrect keytab file + """ + EMPTY_KEYTAB = os.path.join( + self.clients[0].config.test_dir, + 'empty.keytab' + ) + self.restore_client() + self.check_client_host_entry() + self.clients[0].run_command(['touch', EMPTY_KEYTAB]) + self.reenroll_client(keytab=EMPTY_KEYTAB, expect_fail=True) + + def uninstall_client(self): + self.clients[0].run_command( + ['ipa-client-install', '--uninstall', '-U'], + set_env=False, + raiseonerr=False + ) + + def restore_client(self): + client = self.clients[0] + + client.run_command([ + 'iptables', + '-A', 'INPUT', + '-j', 'ACCEPT', + '-p', 'tcp', + '--dport', '22' + ]) + client.run_command([ + 'iptables', + '-A', 'INPUT', + '-j', 'REJECT', + '-p', 'all', + '--source', self.master.ip + ]) + self.uninstall_client() + client.run_command(['iptables', '-F']) + + def reenroll_client(self, keytab=None, to_replica=False, force_join=False, + expect_fail=False): + server = self.replicas[0] if to_replica else self.master + client = self.clients[0] + + self.fix_resolv_conf(client, server) + + args = [ + 'ipa-client-install', '-U', + '--server', server.hostname, + '--domain', server.domain.name + ] + if force_join: + args.append('--force-join') + if keytab: + args.extend(['--keytab', keytab]) + else: + args.extend([ + '-p', client.config.admin_name, + '-w', client.config.admin_password + ]) + + result = client.run_command( + args, + set_env=False, + raiseonerr=not expect_fail + ) + assert 'IPA Server: %s' % server.hostname in result.stderr_text + + if expect_fail: + err_msg = 'Kerberos authentication failed using keytab' + assert result.returncode == 1 + assert err_msg in result.stderr_text + elif force_join and keytab: + warn_msg = ("Option 'force-join' has no additional effect " + "when used with together with option 'keytab'.") + assert warn_msg in result.stderr_text + + def check_client_host_entry(self, enabled=True, not_found=False): + result = self.master.run_command( + ['ipa', 'host-show', self.clients[0].hostname], + raiseonerr=not not_found + ) + + if not_found: + assert result.returncode == 2 + assert 'host not found' in result.stderr_text + elif enabled: + assert 'Certificate:' in result.stdout_text + assert 'Keytab: True' in result.stdout_text + else: + assert 'Certificate:' not in result.stdout_text + assert 'Keytab: False' in result.stdout_text + + def disable_client_host_entry(self): + self.master.run_command( + ['ipa', 'host-disable', self.clients[0].hostname] + ) + + def delete_client_host_entry(self): + try: + self.master.run_command( + ['ipa', 'host-del', self.clients[0].hostname] + ) + except subprocess.CalledProcessError as e: + if e.returncode != 2: + raise + + def get_sshfp_record(self): + sshfp_record = '' + client_host = self.clients[0].hostname.split('.')[0] + + result = self.master.run_command( + ['ipa', 'dnsrecord-show', self.master.domain.name, client_host] + ) + + lines = result.stdout_text.splitlines() + for line in lines: + if 'SSHFP record:' in line: + sshfp_record = line.replace('SSHFP record:', '').strip() + + assert sshfp_record, 'SSHFP record not found' + return sshfp_record + + def backup_keytab(self): + contents = self.clients[0].get_file_contents(CLIENT_KEYTAB) + self.master.put_file_contents(self.BACKUP_KEYTAB, contents) + + def restore_keytab(self): + contents = self.master.get_file_contents(self.BACKUP_KEYTAB) + self.clients[0].put_file_contents(self.BACKUP_KEYTAB, contents) + + def fix_resolv_conf(self, client, server): + """ + Put server's ip address at the top of resolv.conf + """ + contents = client.get_file_contents('/etc/resolv.conf') + nameserver = 'nameserver %s\n' % server.ip + + if not contents.startswith(nameserver): + contents = nameserver + contents.replace(nameserver, '') + client.put_file_contents('/etc/resolv.conf', contents) -- 1.8.3.1
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel