From 3f02fc945e6306e8fb656db680d5a553683fabc4 Mon Sep 17 00:00:00 2001 From: Sergey Orlov Date: Tue, 21 May 2019 15:54:14 +0200 Subject: [PATCH] ipatests: new tests for establishing one-way AD trust with shared secret Tests added for two scenarios: 1) adding one-way external trust, trust on Windows side is created using netdom utility. 2) adding one-way forest trust, trust on Windows side is created using powershell bindings to .Net functions Tests verify that specified trusts can be established, trust domains can be fetched and AD user data can be queried by IPA client. Relates: https://pagure.io/freeipa/issue/6077 Reviewed-By: Kaleemullah Siddiqui --- ipatests/pytest_ipa/integration/tasks.py | 28 +++-- ipatests/test_integration/test_trust.py | 131 ++++++++++++++++++++++- 2 files changed, 151 insertions(+), 8 deletions(-) diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py index f07347619..0ae0d633f 100644 --- a/ipatests/pytest_ipa/integration/tasks.py +++ b/ipatests/pytest_ipa/integration/tasks.py @@ -644,7 +644,17 @@ def unconfigure_dns_for_trust(master, ad): restore_dnssec_validation(master) -def establish_trust_with_ad(master, ad_domain, extra_args=()): +def configure_windows_dns_for_trust(ad, master): + ad.run_command(['dnscmd', '/zoneadd', master.domain.name, + '/Forwarder', master.ip]) + + +def unconfigure_windows_dns_for_trust(ad, master): + ad.run_command(['dnscmd', '/zonedelete', master.domain.name, '/f']) + + +def establish_trust_with_ad(master, ad_domain, extra_args=(), + shared_secret=None): """ Establishes trust with Active Directory. Trust type is detected depending on the presence of SfU (Services for Unix) support on the AD. @@ -654,6 +664,7 @@ def establish_trust_with_ad(master, ad_domain, extra_args=()): """ # Force KDC to reload MS-PAC info by trying to get TGT for HTTP + extra_args = list(extra_args) master.run_command(['kinit', '-kt', paths.HTTP_KEYTAB, 'HTTP/%s' % master.hostname]) master.run_command(['systemctl', 'restart', 'krb5kdc.service']) @@ -663,12 +674,15 @@ def establish_trust_with_ad(master, ad_domain, extra_args=()): master.run_command(['klist']) master.run_command(['smbcontrol', 'all', 'debug', '100']) - run_repeatedly(master, - ['ipa', 'trust-add', - '--type', 'ad', ad_domain, - '--admin', 'Administrator', - '--password'] + list(extra_args), - stdin_text=master.config.ad_admin_password) + if shared_secret: + extra_args += ['--trust-secret'] + stdin_text = shared_secret + else: + extra_args += ['--admin', 'Administrator', '--password'] + stdin_text = master.config.ad_admin_password + run_repeatedly( + master, ['ipa', 'trust-add', '--type', 'ad', ad_domain] + extra_args, + stdin_text=stdin_text) master.run_command(['smbcontrol', 'all', 'debug', '1']) clear_sssd_cache(master) master.run_command(['systemctl', 'restart', 'krb5kdc.service']) diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py index 71ce9d83d..0e620fefb 100644 --- a/ipatests/test_integration/test_trust.py +++ b/ipatests/test_integration/test_trust.py @@ -21,6 +21,8 @@ class BaseTestTrust(IntegrationTest): upn_principal = '{}@{}'.format(upn_username, upn_suffix) upn_password = 'Secret123456' + shared_secret = 'qwertyuiopQq!1' + @classmethod def install(cls, mh): if not cls.master.transport.file_exists('/usr/bin/rpcclient'): @@ -37,6 +39,13 @@ class BaseTestTrust(IntegrationTest): cls.tree_ad = cls.ad_treedomains[0] # pylint: disable=no-member cls.ad_treedomain = cls.tree_ad.domain.name + # values used in workaround for + # https://bugzilla.redhat.com/show_bug.cgi?id=1711958 + cls.srv_gc_record_name = \ + '_ldap._tcp.Default-First-Site-Name._sites.gc._msdcs' + cls.srv_gc_record_value = '0 100 389 {}.'.format(cls.master.hostname) + + @classmethod def check_sid_generation(cls): command = ['ipa', 'user-show', 'admin', '--all', '--raw'] @@ -80,8 +89,10 @@ class BaseTestTrust(IntegrationTest): tasks.clear_sssd_cache(self.master) -# Tests for non-posix AD trust class TestTrust(BaseTestTrust): + + # Tests for non-posix AD trust + def test_establish_nonposix_trust(self): self.configure_dns_and_time(self.ad) tasks.establish_trust_with_ad( @@ -344,3 +355,121 @@ class TestTrust(BaseTestTrust): def test_remove_external_rootdomain_trust(self): self.remove_trust(self.ad) + + # Test for one-way forest trust with shared secret + + def test_establish_forest_trust_with_shared_secret(self): + self.configure_dns_and_time(self.ad) + tasks.configure_windows_dns_for_trust(self.ad, self.master) + + # this is a workaround for + # https://bugzilla.redhat.com/show_bug.cgi?id=1711958 + self.master.run_command( + ['ipa', 'dnsrecord-add', self.master.domain.name, + self.srv_gc_record_name, + '--srv-rec', self.srv_gc_record_value]) + + # create windows side of trust using powershell bindings + # to .Net functions + ps_cmd = ( + '[System.DirectoryServices.ActiveDirectory.Forest]' + '::getCurrentForest()' + '.CreateLocalSideOfTrustRelationship("{}", 1, "{}")'.format( + self.master.domain.name, self.shared_secret)) + self.ad.run_command(['powershell', '-c', ps_cmd]) + + # create ipa side of trust + tasks.establish_trust_with_ad( + self.master, self.ad_domain, shared_secret=self.shared_secret) + + def test_trustdomains_found_in_forest_trust_with_shared_secret(self): + result = self.master.run_command( + ['ipa', 'trust-fetch-domains', self.ad.domain.name], + raiseonerr=False) + assert result.returncode == 1 + self.check_trustdomains( + self.ad_domain, [self.ad_domain, self.ad_subdomain]) + + def test_user_gid_uid_resolution_in_forest_trust_with_shared_secret(self): + """Check that user has SID-generated UID""" + # Using domain name since it is lowercased realm name for AD domains + testuser = 'testuser@%s' % self.ad_domain + result = self.master.run_command(['getent', 'passwd', testuser]) + + # This regex checks that Test User does not have UID 10042 nor belongs + # to the group with GID 10047 + testuser_regex = r"^testuser@%s:\*:(?!10042)(\d+):(?!10047)(\d+):"\ + r"Test User:/home/%s/testuser:/bin/sh$"\ + % (re.escape(self.ad_domain), + re.escape(self.ad_domain)) + + assert re.search( + testuser_regex, result.stdout_text), result.stdout_text + + def test_remove_forest_trust_with_shared_secret(self): + ps_cmd = ( + '[System.DirectoryServices.ActiveDirectory.Forest]' + '::getCurrentForest()' + '.DeleteLocalSideOfTrustRelationship("{}")'.format( + self.master.domain.name)) + self.ad.run_command(['powershell', '-c', ps_cmd]) + + self.remove_trust(self.ad) + + # this is cleanup for workaround for + # https://bugzilla.redhat.com/show_bug.cgi?id=1711958 + self.master.run_command( + ['ipa', 'dnsrecord-del', self.master.domain.name, + self.srv_gc_record_name, '--srv-rec', + self.srv_gc_record_value]) + + tasks.unconfigure_windows_dns_for_trust(self.ad, self.master) + + # Test for one-way external trust with shared secret + + def test_establish_external_trust_with_shared_secret(self): + self.configure_dns_and_time(self.ad) + tasks.configure_windows_dns_for_trust(self.ad, self.master) + + # create windows side of trust using netdom.exe utility + self.ad.run_command( + ['netdom.exe', 'trust', self.master.domain.name, + '/d:' + self.ad.domain.name, + '/passwordt:' + self.shared_secret, '/add', '/oneside:TRUSTED']) + + # create ipa side of trust + tasks.establish_trust_with_ad( + self.master, self.ad_domain, shared_secret=self.shared_secret, + extra_args=['--range-type', 'ipa-ad-trust', '--external=True']) + + def test_trustdomains_found_in_external_trust_with_shared_secret(self): + result = self.master.run_command( + ['ipa', 'trust-fetch-domains', self.ad.domain.name], + raiseonerr=False) + assert result.returncode == 1 + self.check_trustdomains( + self.ad_domain, [self.ad_domain]) + + def test_user_uid_resolution_in_external_trust_with_shared_secret(self): + """Check that user has SID-generated UID""" + # Using domain name since it is lowercased realm name for AD domains + testuser = 'testuser@%s' % self.ad_domain + result = self.master.run_command(['getent', 'passwd', testuser]) + + # This regex checks that Test User does not have UID 10042 nor belongs + # to the group with GID 10047 + testuser_regex = r"^testuser@%s:\*:(?!10042)(\d+):(?!10047)(\d+):"\ + r"Test User:/home/%s/testuser:/bin/sh$"\ + % (re.escape(self.ad_domain), + re.escape(self.ad_domain)) + + assert re.search( + testuser_regex, result.stdout_text), result.stdout_text + + def test_remove_external_trust_with_shared_secret(self): + self.ad.run_command( + ['netdom.exe', 'trust', self.master.domain.name, + '/d:' + self.ad.domain.name, '/remove', '/oneside:TRUSTED'] + ) + self.remove_trust(self.ad) + tasks.unconfigure_windows_dns_for_trust(self.ad, self.master)