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)