From 4fdab0c94c4e17e42e5f38a0e671bea39bcc9b74 Mon Sep 17 00:00:00 2001 From: Anuja More Date: Aug 13 2021 06:14:24 +0000 Subject: ipatests: Test unsecure nsupdate. The test configures an external bind server on the ipa-server (not the IPA-embedded DNS server) that allows unauthenticated nsupdates. When the IPA client is registered using ipa-client-install, DNS records are added for the client in the bind server using nsupdate. The first try is using GSS-TIG but fails as expected, and the client installer then tries with unauthenticated nsupdate. Related : https://pagure.io/freeipa/issue/8402 Signed-off-by: Anuja More Reviewed-By: Rob Crittenden Reviewed-By: Florence Blanc-Renaud --- diff --git a/ipatests/test_integration/test_installation_client.py b/ipatests/test_integration/test_installation_client.py index fa59a52..014b0f6 100644 --- a/ipatests/test_integration/test_installation_client.py +++ b/ipatests/test_integration/test_installation_client.py @@ -8,10 +8,15 @@ Module provides tests for various options of ipa-client-install. from __future__ import absolute_import +import pytest +import re import shlex +import textwrap +from ipaplatform.paths import paths from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_ipa.integration import tasks +from ipatests.pytest_ipa.integration.firewall import Firewall class TestInstallClient(IntegrationTest): @@ -70,3 +75,116 @@ class TestInstallClient(IntegrationTest): extra_args=['--ssh-trust-dns']) result = self.clients[0].run_command(['cat', '/etc/ssh/ssh_config']) assert 'HostKeyAlgorithms' not in result.stdout_text + + +class TestClientInstallBind(IntegrationTest): + """ + The test configures an external bind server on the ipa-server + (not the IPA-embedded DNS server) that allows unauthenticated nsupdates. + When the IPA client is registered using ipa-client-install, + DNS records are added for the client in the bind server using nsupdate. + The first try is using GSS-TIG but fails as expected, and the client + installer then tries with unauthenticated nsupdate. + """ + + num_clients = 1 + + @classmethod + def install(cls, mh): + cls.client = cls.clients[0] + + @pytest.fixture + def setup_bindserver(self): + bindserver = self.master + named_conf_backup = tasks.FileBackup(self.master, paths.NAMED_CONF) + # create a zone in the BIND server that is identical to the IPA + add_zone = textwrap.dedent(""" + zone "{domain}" IN {{ type master; + file "{domain}.db"; allow-query {{ any; }}; + allow-update {{ any; }}; }}; + """).format(domain=bindserver.domain.name) + + namedcfg = bindserver.get_file_contents( + paths.NAMED_CONF, encoding='utf-8') + namedcfg += '\n' + add_zone + bindserver.put_file_contents(paths.NAMED_CONF, namedcfg) + + def update_contents(path, pattern, replace): + contents = bindserver.get_file_contents(path, encoding='utf-8') + namedcfg_query = re.sub(pattern, replace, contents) + bindserver.put_file_contents(path, namedcfg_query) + + update_contents(paths.NAMED_CONF, 'localhost;', 'any;') + update_contents(paths.NAMED_CONF, "listen-on port 53 { 127.0.0.1; };", + "#listen-on port 53 { 127.0.0.1; };") + update_contents(paths.NAMED_CONF, "listen-on-v6 port 53 { ::1; };", + "#listen-on-v6 port 53 { ::1; };") + + add_records = textwrap.dedent(""" + @ IN SOA {fqdn}. root.{domain}. ( + 1001 ;Serial + 3H ;Refresh + 15M ;Retry + 1W ;Expire + 1D ;Minimum 1D + ) + @ IN NS {fqdn}. + ns1 IN A {bindserverip} + _kerberos.{domain}. IN TXT {zoneupper} + {fqdn}. IN A {bindserverip} + ipa-ca.{domain}. IN A {bindserverip} + _kerberos-master._tcp.{domain}. IN SRV 0 100 88 {fqdn}. + _kerberos-master._udp.{domain}. IN SRV 0 100 88 {fqdn}. + _kerberos._tcp.{domain}. IN SRV 0 100 88 {fqdn}. + _kerberos._udp.{domain}. IN SRV 0 100 88 {fqdn}. + _kpasswd._tcp.{domain}. IN SRV 0 100 464 {fqdn}. + _kpasswd._udp.{domain}. IN SRV 0 100 464 {fqdn}. + _ldap._tcp.{domain}. IN SRV 0 100 389 {fqdn}. + """).format( + fqdn=bindserver.hostname, + domain=bindserver.domain.name, + bindserverip=bindserver.ip, + zoneupper=bindserver.domain.name.upper() + ) + bindserverdb = "/var/named/{0}.db".format(bindserver.domain.name) + bindserver.put_file_contents(bindserverdb, add_records) + bindserver.run_command(['systemctl', 'start', 'named']) + Firewall(bindserver).enable_services(["dns"]) + yield + named_conf_backup.restore() + bindserver.run_command(['rm', '-rf', bindserverdb]) + + def test_client_nsupdate(self, setup_bindserver): + """Test secure nsupdate failed, then try unsecure nsupdate.. + + Test to verify when bind is configured with dynamic update policy, + and during client-install 'nsupdate -g' fails then it should run with + second call using unauthenticated nsupdate. + + Related : https://pagure.io/freeipa/issue/8402 + """ + # with pre-configured bind server, install ipa-server without dns. + tasks.install_master(self.master, setup_dns=False) + self.client.resolver.backup() + self.client.resolver.setup_resolver( + self.master.ip, self.master.domain.name) + try: + self.client.run_command(['ipa-client-install', '-U', + '--domain', self.client.domain.name, + '--realm', self.client.domain.realm, + '-p', self.client.config.admin_name, + '-w', self.client.config.admin_password, + '--server', self.master.hostname]) + # call unauthenticated nsupdate if GSS-TSIG nsupdate failed. + str1 = "nsupdate (GSS-TSIG) failed" + str2 = "'/usr/bin/nsupdate', '/etc/ipa/.dns_update.txt'" + client_log = self.client.get_file_contents( + paths.IPACLIENT_INSTALL_LOG, encoding='utf-8' + ) + assert str1 in client_log and str2 in client_log + dig_after = self.client.run_command( + ['dig', '@{0}'.format(self.master.ip), self.client.hostname, + '-t', 'SSHFP']) + assert "ANSWER: 0" not in dig_after.stdout_text.strip() + finally: + self.client.resolver.restore()