diff --git a/0087-ipatests-certbot-removed-the-manual-public-ip-loggin.patch b/0087-ipatests-certbot-removed-the-manual-public-ip-loggin.patch new file mode 100644 index 0000000..2e91493 --- /dev/null +++ b/0087-ipatests-certbot-removed-the-manual-public-ip-loggin.patch @@ -0,0 +1,34 @@ +From 8ecf75b29429aa6f9e0fc0abfb1d74068b5d4f48 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 6 Jan 2025 14:37:42 +0100 +Subject: [PATCH] ipatests: certbot removed the --manual-public-ip-logging-ok + parameter + +The certbot CLI has deprecated the parameter --manual-public-ip-logging-ok +and finally removed it from certbot 3.0. +The test test_acme.py is using this parameter and fails in rawhide. + +Do not use this parameter any more. + +Fixes: https://pagure.io/freeipa/issue/9724 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_acme.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py +index 4032d266a8dc72fae6ee11857c306aa3a21e51bc..b0d79182cfc98d23333266ee4c3d710bfffb4d73 100644 +--- a/ipatests/test_integration/test_acme.py ++++ b/ipatests/test_integration/test_acme.py +@@ -311,7 +311,6 @@ class TestACME(CALessBase): + '--domain', self.clients[0].hostname, + '--preferred-challenges', 'dns', + '--manual', +- '--manual-public-ip-logging-ok', + '--manual-auth-hook', CERTBOT_DNS_IPA_SCRIPT, + '--manual-cleanup-hook', CERTBOT_DNS_IPA_SCRIPT, + '--key-type', 'rsa', +-- +2.50.0 + diff --git a/0088-ipatests-adapt-error-code-and-message-for-samba-4.22.patch b/0088-ipatests-adapt-error-code-and-message-for-samba-4.22.patch new file mode 100644 index 0000000..1832789 --- /dev/null +++ b/0088-ipatests-adapt-error-code-and-message-for-samba-4.22.patch @@ -0,0 +1,45 @@ +From d03164fc104588e88ad75483e7233b7fccacabb6 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 6 Mar 2025 15:58:53 +0100 +Subject: [PATCH] ipatests: adapt error code and message for samba 4.22 + +When establishing trust with an unreachable AD domain controller, +the error code and message have changed with samba 4.22. + +Update the test to be compatible with any version of samba. + +Fixes: https://pagure.io/freeipa/issue/9751 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +--- + ipatests/test_integration/test_trust.py | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py +index f71ec377b429b104241e85a3d04ee42c6721494c..4086cb30ac5d52ee595c1ecdbe86a8d511cbb704 100644 +--- a/ipatests/test_integration/test_trust.py ++++ b/ipatests/test_integration/test_trust.py +@@ -1072,8 +1072,18 @@ class TestTrust(BaseTestTrust): + paths.VAR_LOG_HTTPD_ERROR, + encoding='utf-8' + ) +- assert 'CIFS server communication error: code "3221225653", ' \ +- 'message "{Device Timeout}' in httpd_error_log ++ ++ # The error code and message changed in samba 4.22 ++ old_msg = 'CIFS server communication error: code "3221225653", ' \ ++ 'message "{Device Timeout}' ++ new_msg = 'CIFS server communication error: code "3221226021", ' \ ++ 'message "The object was not found."' ++ result = self.master.run_command(["smbstatus", "-V"]).stdout_text ++ version = result.split()[1] ++ if tasks.parse_version(version) < tasks.parse_version('4.22.0rc4'): ++ assert old_msg in httpd_error_log ++ else: ++ assert new_msg in httpd_error_log + + # Check that trust is successfully established with --server option + tasks.establish_trust_with_ad( +-- +2.50.0 + diff --git a/0089-Fix-inconsistency-in-manpage-for-DoT-forwarder-optio.patch b/0089-Fix-inconsistency-in-manpage-for-DoT-forwarder-optio.patch new file mode 100644 index 0000000..69dd62b --- /dev/null +++ b/0089-Fix-inconsistency-in-manpage-for-DoT-forwarder-optio.patch @@ -0,0 +1,59 @@ +From d0f6979c0250bdf5299404bf711cef74dd458042 Mon Sep 17 00:00:00 2001 +From: Antonio Torres +Date: Wed, 4 Jun 2025 09:36:55 +0200 +Subject: [PATCH] Fix inconsistency in manpage for DoT forwarder option + +The example given in manpages for --dot-forwarder option is inconsistent +to the format that is required. + +Fixes: https://pagure.io/freeipa/issue/9804 +Signed-off-by: Antonio Torres +Reviewed-By: Florence Blanc-Renaud +--- + install/tools/man/ipa-dns-install.1 | 2 +- + install/tools/man/ipa-replica-install.1 | 2 +- + install/tools/man/ipa-server-install.1 | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/install/tools/man/ipa-dns-install.1 b/install/tools/man/ipa-dns-install.1 +index 6008d2028e1d91a39c8cbffc9e240121d8fd18f5..96eee1ef713a5069804088d68785f333c76b2369 100644 +--- a/install/tools/man/ipa-dns-install.1 ++++ b/install/tools/man/ipa-dns-install.1 +@@ -74,7 +74,7 @@ An unattended installation that will never prompt for user input + Configure DNS over TLS. + .TP + \fB\-\-dot\-forwarder\fR=\fIIP_ADDRESS#HOSTNAME\fR +-Add a DNS-over-TLS-enabled forwarder in the format of ip#hostname, e.g.: dns.example.com#1.2.3.4. This option can be used multiple times. ++Add a DNS-over-TLS-enabled forwarder in the format of ip#hostname, e.g.: 1.2.3.4#dns.example.com. This option can be used multiple times. + .TP + \fB\-\-dns\-over\-tls\-cert\fR=\fIFILE\fR + Certificate to use for DNS over TLS. If empty, a new certificate will be requested from IPA CA. +diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 +index c55d21253f8d565e04605ea7d632ab9794cdd938..637c5c1b55031c3c1636477f867e519fbe98efeb 100644 +--- a/install/tools/man/ipa-replica-install.1 ++++ b/install/tools/man/ipa-replica-install.1 +@@ -228,7 +228,7 @@ Disable DNSSEC validation on this server. + Configure DNS over TLS. + .TP + \fB\-\-dot\-forwarder\fR=\fIIP_ADDRESS#HOSTNAME\fR +-Add a DNS-over-TLS-enabled forwarder in the format of ip#hostname, e.g.: dns.example.com#1.2.3.4. This option can be used multiple times. ++Add a DNS-over-TLS-enabled forwarder in the format of ip#hostname, e.g.: 1.2.3.4#dns.example.com. This option can be used multiple times. + .TP + \fB\-\-dns\-over\-tls\-cert\fR=\fIFILE\fR + Certificate to use for DNS over TLS. If empty, a new certificate will be requested from IPA CA. +diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 +index 84d82531c50f05b9756eee967e13de90caf578f8..b9367ce1194724147a3f88d24f2d42854aff31a3 100644 +--- a/install/tools/man/ipa-server-install.1 ++++ b/install/tools/man/ipa-server-install.1 +@@ -257,7 +257,7 @@ Allow creation of (reverse) zone even if the zone is already resolvable. Using t + Configure DNS over TLS. + .TP + \fB\-\-dot\-forwarder\fR=\fIIP_ADDRESS#HOSTNAME\fR +-Add a DNS-over-TLS-enabled forwarder in the format of ip#hostname, e.g.: dns.example.com#1.2.3.4. This option can be used multiple times. ++Add a DNS-over-TLS-enabled forwarder in the format of ip#hostname, e.g.: 1.2.3.4#dns.example.com. This option can be used multiple times. + .TP + \fB\-\-dns\-over\-tls\-cert\fR=\fIFILE\fR + Certificate to use for DNS over TLS. If empty, a new certificate will be requested from IPA CA. +-- +2.50.0 + diff --git a/0090-Set-krbCanonicalName-admin-REALM-on-the-admin-user.patch b/0090-Set-krbCanonicalName-admin-REALM-on-the-admin-user.patch new file mode 100644 index 0000000..f30a8d4 --- /dev/null +++ b/0090-Set-krbCanonicalName-admin-REALM-on-the-admin-user.patch @@ -0,0 +1,188 @@ +From 796ed20092d554ee0c9e23295e346ec1e8a0bf6e Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 28 Apr 2025 13:43:40 -0400 +Subject: [PATCH] Set krbCanonicalName=admin@REALM on the admin user + +The admin must always own this name. If another entry has this +value set then remove it. + +There is a uniqueness plugin for this attribute so the only two +possibilities are: + +- no entry has this value set +- the admin user has this value set +- a different entry has the value set + +Still, for robustness purposes, the upgrade plugin will handle +more entries. + +Signed-off-by: Rob Crittenden +--- + install/share/bootstrap-template.ldif | 1 + + .../updates/90-post_upgrade_plugins.update | 1 + + .../plugins/add_admin_krbcanonicalname.py | 79 +++++++++++++++++++ + ipatests/test_integration/test_commands.py | 38 +++++++++ + 4 files changed, 119 insertions(+) + create mode 100644 ipaserver/install/plugins/add_admin_krbcanonicalname.py + +diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif +index 325eb8450c786899e7b5e4ae2ef8978f42a8425b..94972eb7270fc9224650bd414c740fc2e8f6c149 100644 +--- a/install/share/bootstrap-template.ldif ++++ b/install/share/bootstrap-template.ldif +@@ -239,6 +239,7 @@ objectClass: ipasshuser + uid: admin + krbPrincipalName: admin@$REALM + krbPrincipalName: root@$REALM ++krbCanonicalName: admin@$REALM + cn: Administrator + sn: Administrator + uidNumber: $IDSTART +diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update +index 7c3bba3e0317162d4739513e16b9fac973495c66..3d78c7b5a983f418502a7902a53ff8cd8d6847c4 100644 +--- a/install/updates/90-post_upgrade_plugins.update ++++ b/install/updates/90-post_upgrade_plugins.update +@@ -25,6 +25,7 @@ plugin: update_mapping_Guests_to_nobody + plugin: fix_kra_people_entry + plugin: update_pwpolicy + plugin: update_pwpolicy_grace ++plugin: add_admin_krbcanonicalname + + # last + # DNS version 1 +diff --git a/ipaserver/install/plugins/add_admin_krbcanonicalname.py b/ipaserver/install/plugins/add_admin_krbcanonicalname.py +new file mode 100644 +index 0000000000000000000000000000000000000000..e9ffdf55a3f9a1e182bcadda352eda99e536cf16 +--- /dev/null ++++ b/ipaserver/install/plugins/add_admin_krbcanonicalname.py +@@ -0,0 +1,79 @@ ++# ++# Copyright (C) 2025 FreeIPA Contributors see COPYING for license ++# ++ ++from __future__ import absolute_import ++ ++import logging ++ ++from ipalib import errors ++from ipalib import Registry ++from ipalib import Updater ++from ipapython.dn import DN ++ ++logger = logging.getLogger(__name__) ++ ++register = Registry() ++ ++ ++@register() ++class add_admin_krbcanonicalname(Updater): ++ """ ++ Ensures that only the admin user has the krbCanonicalName of ++ admin@$REALM. ++ """ ++ ++ def execute(self, **options): ++ ldap = self.api.Backend.ldap2 ++ ++ search_filter = ( ++ "(krbcanonicalname=admin@{})".format(self.api.env.realm)) ++ try: ++ (entries, _truncated) = ldap.find_entries( ++ filter=search_filter, base_dn=self.api.env.basedn, ++ time_limit=0, size_limit=0) ++ except errors.EmptyResult: ++ logger.debug("add_admin_krbcanonicalname: No user set with " ++ "admin krbcanonicalname") ++ entries = [] ++ # fall through ++ except errors.ExecutionError as e: ++ logger.error("add_admin_krbcanonicalname: Can not get list " ++ "of krbcanonicalname: %s", e) ++ return False, [] ++ ++ admin_set = False ++ # admin should be only user with admin@ as krbcanonicalname ++ # It has a uniquness setting so there can be only one, we ++ # just didn't automatically set it for admin. ++ for entry in entries: ++ if entry.single_value.get('uid') != 'admin': ++ logger.critical( ++ "add_admin_krbcanonicalname: " ++ "entry %s has a krbcanonicalname of admin. Removing.", ++ entry.dn) ++ del entry['krbcanonicalname'] ++ ldap.update_entry(entry) ++ else: ++ admin_set = True ++ ++ if not admin_set: ++ dn = DN( ++ ('uid', 'admin'), ++ self.api.env.container_user, ++ self.api.env.basedn) ++ entry = ldap.get_entry(dn) ++ entry['krbcanonicalname'] = 'admin@%s' % self.api.env.realm ++ try: ++ ldap.update_entry(entry) ++ except errors.DuplicateEntry: ++ logger.critical( ++ "add_admin_krbcanonicalname: " ++ "Failed to set krbcanonicalname on admin. It is set " ++ "on another entry.") ++ except errors.ExecutionError as e: ++ logger.critical( ++ "add_admin_krbcanonicalname: " ++ "Failed to set krbcanonicalname on admin: %s", e) ++ ++ return False, [] +diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py +index 9cad5772127bcd860aeecc8dabe73d5f160faf7b..ad97affe62e15c68442239d669032f0c84e7f5c9 100644 +--- a/ipatests/test_integration/test_commands.py ++++ b/ipatests/test_integration/test_commands.py +@@ -2179,6 +2179,44 @@ class TestIPACommandWithoutReplica(IntegrationTest): + + assert isrgrootx1_nick in result + ++ def test_unique_krbcanonicalname(self): ++ """Verify that the uniqueness for krbcanonicalname is working""" ++ master = self.master ++ ++ base_dn = str(master.domain.basedn) ++ hostname = master.hostname ++ realm = master.domain.realm ++ principal = f'test/{hostname}@{realm}' ++ entry_ldif = textwrap.dedent(""" ++ dn: krbprincipalname={principal},cn=services,cn=accounts,{base_dn} ++ changetype: add ++ ipakrbprincipalalias: test/{hostname}@{realm} ++ krbprincipalname: {principal} ++ objectclass: ipakrbprincipal ++ objectclass: ipaobject ++ objectclass: ipaservice ++ objectclass: krbprincipal ++ objectclass: krbprincipalaux ++ objectclass: top ++ krbcanonicalname: admin@{realm} ++ managedby: fqdn={hostname},cn=computers,cn=accounts,{base_dn} ++ """).format( ++ base_dn=base_dn, ++ hostname=hostname, ++ principal=principal, ++ realm=realm) ++ tasks.kdestroy_all(master) ++ master.run_command( ++ ['kinit', '-kt', '/etc/krb5.keytab', f'host/{hostname}@{realm}']) ++ args = [ ++ 'ldapmodify', ++ '-Y', ++ 'GSSAPI' ++ ] ++ result = master.run_command(args, stdin_text=entry_ldif, ++ raiseonerr=False) ++ assert "entry with the same attribute value" in result.stderr_text ++ + + class TestIPAautomount(IntegrationTest): + @classmethod +-- +2.50.0 + diff --git a/0091-ipa-client-install-Fix-nsupdate-issues-when-dns_over.patch b/0091-ipa-client-install-Fix-nsupdate-issues-when-dns_over.patch new file mode 100644 index 0000000..8e62b66 --- /dev/null +++ b/0091-ipa-client-install-Fix-nsupdate-issues-when-dns_over.patch @@ -0,0 +1,43 @@ +From 7b4317979080cb8efe901e2ab491f6f4e4ccad15 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Thu, 12 Jun 2025 17:44:44 +0200 +Subject: [PATCH] ipa-client-install: Fix nsupdate issues when dns_over_tls is + enabled + +The server commands for nsupdate.txt to define the server with the port +853 have been added for dns_over_tls. These commands do not have a leading +newline. This results in a syntax error as the next line is added to the +command. + +Fixes: https://pagure.io/freeipa/issue/9806 +Signed-off-by: Thomas Woerner +Reviewed-By: David Hanina +--- + ipaclient/install/client.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 372daa51e4647023dde76e183189eeebdd9525b8..43a71828335ad655ad067b5320572d40bee1a44b 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -1540,7 +1540,7 @@ def update_dns(server, hostname, options): + + update_txt = "debug\n" + if options.dns_over_tls: +- update_txt += "server %s 853" % server ++ update_txt += "server %s 853\n" % server + update_txt += ipautil.template_str(DELETE_TEMPLATE_A, + dict(HOSTNAME=hostname)) + update_txt += ipautil.template_str(DELETE_TEMPLATE_AAAA, +@@ -1788,7 +1788,7 @@ def update_ssh_keys(hostname, ssh_dir, options, server): + + update_txt = 'debug\n' + if options.dns_over_tls: +- update_txt += "server %s 853" % server ++ update_txt += "server %s 853\n" % server + update_txt += 'update delete %s. IN SSHFP\nshow\nsend\n' % hostname + for pubkey in pubkeys: + sshfp = pubkey.fingerprint_dns_sha1() +-- +2.50.0 + diff --git a/0092-ipatests-fix-test_adtrust_install_with_non_ipa_user.patch b/0092-ipatests-fix-test_adtrust_install_with_non_ipa_user.patch new file mode 100644 index 0000000..f1ca610 --- /dev/null +++ b/0092-ipatests-fix-test_adtrust_install_with_non_ipa_user.patch @@ -0,0 +1,90 @@ +From 39e92c4033d0ecd702281f3ecbeac3b5f654e973 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 19 Jun 2025 17:17:44 +0200 +Subject: [PATCH] ipatests: fix test_adtrust_install_with_non_ipa_user + +Fix the test scenario: +create a user with a second krbprincipalname but no +krbcanonical name. +kinit -E with the other name +try ipa-adtrust-install with the other name +It should fail with the error message 'user not found' + +Fixes: https://pagure.io/freeipa/issue/9812 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +--- + .../test_integration/test_adtrust_install.py | 48 ++++++++++++++----- + 1 file changed, 36 insertions(+), 12 deletions(-) + +diff --git a/ipatests/test_integration/test_adtrust_install.py b/ipatests/test_integration/test_adtrust_install.py +index 99d3029443ea39bb5f0e333a5087d30291191968..09e227ec8125e90b37d1d92f0512f9819f5b48c3 100644 +--- a/ipatests/test_integration/test_adtrust_install.py ++++ b/ipatests/test_integration/test_adtrust_install.py +@@ -360,27 +360,51 @@ class TestIpaAdTrustInstall(IntegrationTest): + assert msg in result.stdout_text + assert result.returncode == 0 + +- def test_adtrust_install_with_non_ipa_user(self): ++ @pytest.fixture ++ def create_user(self): ++ # create a user with 'othername' as 2nd krbprincipalname but ++ # no krbcanonicalname ++ basedn = self.master.domain.basedn ++ self.test_user = 'idmuser' ++ self.test_alias = 'othername' ++ tasks.create_active_user( ++ self.master, self.test_user, self.master.config.admin_password, ++ first=self.test_user, last=self.test_user) ++ user_update_ldif = textwrap.dedent(""" ++ dn: uid={user},cn=users,cn=accounts,{base_dn} ++ changetype: modify ++ add: krbprincipalname ++ krbprincipalname: {alias}@{realm} ++ - ++ delete: krbcanonicalname ++ """.format(base_dn=basedn, user=self.test_user, ++ alias=self.test_alias, realm=self.master.domain.realm)) ++ tasks.ldapmodify_dm(self.master, user_update_ldif) ++ yield ++ tasks.kinit_admin(self.master) ++ self.master.run_command(["ipa", "user-del", self.test_user]) ++ ++ def test_adtrust_install_with_user_missing_krbcanonical(self, create_user): + """ + Test that ipa-adtrust-install command returns +- an error when kinit is done as alias +- i.e root which is not an ipa user. ++ an error when kinit is done as an alias ++ for which there is no krbcanonicalname. + """ +- msg = ( +- 'Unrecognized error during check of admin rights: ' +- 'root: user not found' +- ) +- user = 'root' ++ self.master.run_command(["kdestroy", "-A"]) + self.master.run_command( +- ["kinit", "-E", user], +- stdin_text=self.master.config.admin_password +- ) ++ ["kinit", "-E", self.test_alias], ++ stdin_text=self.master.config.admin_password) ++ + result = self.master.run_command( +- ["ipa-adtrust-install", "-A", user, ++ ["ipa-adtrust-install", "-A", self.test_alias, + "-a", self.master.config.admin_password, + "-U"], raiseonerr=False + ) + assert result.returncode != 0 ++ msg = ( ++ 'Unrecognized error during check of admin rights: ' ++ '{alias}: user not found' ++ ).format(alias=self.test_alias) + assert msg in result.stderr_text + + def test_adtrust_install_as_regular_ipa_user(self): +-- +2.50.0 + diff --git a/0093-ipa-idrange-fix-check-that-IPA-server-is-installed.patch b/0093-ipa-idrange-fix-check-that-IPA-server-is-installed.patch new file mode 100644 index 0000000..48dbc4e --- /dev/null +++ b/0093-ipa-idrange-fix-check-that-IPA-server-is-installed.patch @@ -0,0 +1,63 @@ +From fba7aa10c8487116075d56c8dedeebefc40b74eb Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 16 Jun 2025 18:15:22 +0200 +Subject: [PATCH] ipa-idrange-fix: check that IPA server is installed + +If ipa-idrange-fix is called on a system where the server is not configured, +it crashes with a Traceback when trying to access api.env.basedn. + +Check that IPA server is configured before processing further + +ipatests: add test launching ipa-idrange-fix on unconfigured server + +Fixes: https://pagure.io/freeipa/issue/9809 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +Reviewed-By: David Hanina +--- + ipaserver/install/ipa_idrange_fix.py | 3 +++ + .../test_integration/test_cli_ipa_not_configured.py | 10 ++++++++++ + 2 files changed, 13 insertions(+) + +diff --git a/ipaserver/install/ipa_idrange_fix.py b/ipaserver/install/ipa_idrange_fix.py +index c6c67ae9330e2d0184efc09d09a84216ef0772a6..cd21ed4281d37b013537174fb4ab9e773382990e 100644 +--- a/ipaserver/install/ipa_idrange_fix.py ++++ b/ipaserver/install/ipa_idrange_fix.py +@@ -10,6 +10,7 @@ from ipalib import api, errors + from ipapython.admintool import AdminTool + from ipapython.dn import DN + from ipapython import ipautil ++from ipaserver.install.installutils import check_server_configuration + from typing import List, Tuple + + logger = logging.getLogger(__name__) +@@ -169,6 +170,8 @@ for confirmation", + super().validate_options(needs_root) + + def run(self): ++ check_server_configuration() ++ + api.bootstrap(in_server=True) + api.finalize() + +diff --git a/ipatests/test_integration/test_cli_ipa_not_configured.py b/ipatests/test_integration/test_cli_ipa_not_configured.py +index 1bf36d8ee6e9d1e6019786f3b62d79dbce22655e..7c5601247d7d3c98cf6513eecc333de6aa59d704 100644 +--- a/ipatests/test_integration/test_cli_ipa_not_configured.py ++++ b/ipatests/test_integration/test_cli_ipa_not_configured.py +@@ -22,3 +22,13 @@ class TestIPANotConfigured(IntegrationTest): + assert (exp_str in cmd.stderr_text and + cmd.returncode == SERVER_NOT_CONFIGURED and + unexp_str not in cmd.stderr_text) ++ ++ def test_ipa_idrange_fix(self): ++ """ ++ Test for https://pagure.io/freeipa/issue/9809 ++ Launch ipa-idrange-fix command when the server is not configured. ++ """ ++ exp_str = "IPA is not configured" ++ cmd = self.master.run_command(["ipa-idrange-fix"], raiseonerr=False) ++ assert (exp_str in cmd.stderr_text ++ and cmd.returncode == SERVER_NOT_CONFIGURED) +-- +2.50.0 + diff --git a/0094-ipa-migrate-only-remove-repl-state-attribute-options.patch b/0094-ipa-migrate-only-remove-repl-state-attribute-options.patch new file mode 100644 index 0000000..cc4bade --- /dev/null +++ b/0094-ipa-migrate-only-remove-repl-state-attribute-options.patch @@ -0,0 +1,74 @@ +From ceaa1c9a244499534343dc667227e47a923212ee Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 17 Jun 2025 12:50:36 -0400 +Subject: [PATCH] ipa-migrate - only remove repl state attribute options + +Improve how we process attributes that might include replication state +data. Previously we only cared about ";binary" but there are other +attribute options that are used in IPA. Now we completely break down the +attribute into each option and rebuild it without any repl state options + +Fixes: https://pagure.io/freeipa/issue/9784 + +Signed-off-by: Mark Reynolds +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/ipa_migrate.py | 17 +++++++++-------- + ipaserver/install/ipa_migrate_constants.py | 2 ++ + 2 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py +index a24a2ab7a5ffd4cf1d59179f14e2f5d348fd57e2..b26fb66853ce91a139c3193753b34bed1ce2f586 100644 +--- a/ipaserver/install/ipa_migrate.py ++++ b/ipaserver/install/ipa_migrate.py +@@ -33,7 +33,7 @@ from ipaserver.install.ipa_migrate_constants import ( + DS_CONFIG, DB_OBJECTS, DS_INDEXES, BIND_DN, LOG_FILE_NAME, + STRIP_OP_ATTRS, STRIP_ATTRS, STRIP_OC, PROD_ATTRS, + DNA_REGEN_VAL, DNA_REGEN_ATTRS, NIS_PLUGIN, IGNORE_ATTRS, +- DB_EXCLUDE_TREES, POLICY_OP_ATTRS ++ DB_EXCLUDE_TREES, POLICY_OP_ATTRS, STATE_OPTIONS + ) + + """ +@@ -202,14 +202,15 @@ def decode_attr_vals(entry_attrs): + decoded_attrs = {} + for attr in entry_attrs: + vals = ensure_list_str(entry_attrs[attr]) +- # Remove replication state data, but don't remove ";binary" +- # e.g. userCertififccate;binary;adcsn= ++ # Remove "only" replication state data, but don't remove other attr ++ # options like ";binary" ++ # e.g. userCertificate;binary;adcsn= + parts = attr.split(";") +- if len(parts) > 1 and not attr.endswith(";binary"): +- if parts[1] == "binary": +- attr = parts[0] + ";binary" +- else: +- attr = parts[0] ++ attr_parts = [ ++ parts[0]] + [p for p in parts[1:] ++ if not any(p.startswith(opt) ++ for opt in STATE_OPTIONS)] ++ attr = (';').join(attr_parts) + decoded_attrs[attr] = vals + return decoded_attrs + +diff --git a/ipaserver/install/ipa_migrate_constants.py b/ipaserver/install/ipa_migrate_constants.py +index 4beaa4f42a667ba83008213075b3ded782a83260..19cd5141316d018cf1d81f8db174197f4c5f15ff 100644 +--- a/ipaserver/install/ipa_migrate_constants.py ++++ b/ipaserver/install/ipa_migrate_constants.py +@@ -117,6 +117,8 @@ AD_TRUST_ATTRS = [ # ipaNTTrustedDomain objectclass + 'ipantadditionalsuffixes', + ] + ++STATE_OPTIONS = ('adcsn-', 'mdcsn-', 'vucsn-', 'vdcsn-') ++ + DNA_REGEN_VAL = "-1" + + DNA_REGEN_ATTRS = [ +-- +2.50.0 + diff --git a/0095-ipa-kdb-support-storing-multiple-KVNO-for-the-same-p.patch b/0095-ipa-kdb-support-storing-multiple-KVNO-for-the-same-p.patch new file mode 100644 index 0000000..8fd5bff --- /dev/null +++ b/0095-ipa-kdb-support-storing-multiple-KVNO-for-the-same-p.patch @@ -0,0 +1,224 @@ +From cafaed1c2119fb2e25209eefac74bc21ccab3dcb Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Thu, 25 Jul 2024 19:35:33 +0200 +Subject: [PATCH] ipa-kdb: support storing multiple KVNO for the same principal + +All MIT krb5 keys are encoded with an encryption type identifier and a +KVNO (key version number). The KVNO is referring to the original +credentials string (and its associated salt) which was used to generate +the key using the derivation function of the associated encryption type. + +So far, when a set of Kerberos keys was provided to ipa-kdb, only the +newest KVNO ones were saved in a single "krbPrincipalKey" LDAP +attribute. All the older ones were deleted in the process. + +This commit allows to keep older keys by splitting them in multiple +"krbPrincipalKey" attribute based on their KVNO. + +Fixes: https://pagure.io/freeipa/issue/9370 +Signed-off-by: Julien Rische +Reviewed-By: Rob Crittenden +--- + daemons/ipa-kdb/ipa_kdb_principals.c | 125 +++++++++++++++++++++++---- + util/ipa_krb5.c | 7 ++ + 2 files changed, 115 insertions(+), 17 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index 114957b884786dd3ca3b01c47f6bb82e8a040beb..19998c2a38b5d8ae80aeedeb003f54241d2c2a9f 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -22,6 +22,7 @@ + + #include "ipa_kdb.h" + #include "ipa_krb5.h" ++#include + #include + + /* +@@ -279,22 +280,64 @@ done: + static int ipadb_ldap_attr_to_key_data(LDAP *lcontext, LDAPMessage *le, + char *attrname, + krb5_key_data **result, int *num, +- krb5_kvno *res_mkvno) ++ krb5_kvno *mkvno) + { +- struct berval **vals; +- int mkvno; ++ struct berval **vals, **p; ++ krb5_key_data *cur_res = NULL, *fin_res = NULL, *tmp_res; ++ int fin_mkvno = 0, cur_mkvno, cur_num, fin_num = 0; + int ret; + + vals = ldap_get_values_len(lcontext, le, attrname); +- if (!vals) { ++ if (!vals) + return ENOENT; ++ ++ for (p = vals; *p; ++p) { ++ ret = ber_decode_krb5_key_data(*p, &cur_mkvno, &cur_num, &cur_res); ++ if (ret) ++ goto end; ++ ++ /* All keys in a principal entry should be encrypted with the same ++ * master key. */ ++ if (fin_mkvno == 0) { ++ fin_mkvno = cur_mkvno; ++ } else if (cur_mkvno != fin_mkvno) { ++ ret = EINVAL; ++ goto end; ++ } ++ ++ if (!fin_res) { ++ fin_res = cur_res; ++ } else { ++ tmp_res = realloc(fin_res, (fin_num + cur_num) * sizeof(*fin_res)); ++ if (!tmp_res) { ++ ret = ENOMEM; ++ goto end; ++ } else { ++ fin_res = tmp_res; ++ } ++ ++ memcpy(fin_res + fin_num, cur_res, cur_num * sizeof(*fin_res)); ++ free(cur_res); ++ } ++ ++ cur_res = NULL; ++ fin_num += cur_num; + } + +- ret = ber_decode_krb5_key_data(vals[0], &mkvno, num, result); +- ldap_value_free_len(vals); +- if (ret == 0) { +- *res_mkvno = mkvno; ++ if (mkvno) ++ *mkvno = fin_mkvno; ++ if (num) ++ *num = fin_num; ++ if (result) { ++ *result = fin_res; ++ } else { ++ free(fin_res); + } ++ ++end: ++ ldap_value_free_len(vals); ++ if (cur_res && fin_res != cur_res) ++ free(cur_res); + return ret; + } + +@@ -2532,15 +2575,26 @@ static krb5_error_code ipadb_get_mkvno_from_tl_data(krb5_tl_data *tl_data, + return 0; + } + ++static int desc_key_data(const void *a, const void *b) ++{ ++ const krb5_key_data *ka = a; ++ const krb5_key_data *kb = b; ++ ++ return ka->key_data_kvno != kb->key_data_kvno ++ ? kb->key_data_kvno - ka->key_data_kvno ++ : kb->key_data_type[0] - ka->key_data_type[0]; ++} ++ + static krb5_error_code ipadb_get_ldap_mod_key_data(struct ipadb_mods *imods, + krb5_key_data *key_data, + int n_key_data, int mkvno, + int mod_op) + { + krb5_error_code kerr; +- struct berval *bval = NULL; ++ krb5_key_data *kvno_kdata; ++ struct berval **bvals = NULL; + LDAPMod *mod; +- int ret; ++ int i, j, begin, n_kvno; + + /* If the key data is empty, remove all keys. */ + if (n_key_data == 0 || key_data == NULL) { +@@ -2559,19 +2613,56 @@ static krb5_error_code ipadb_get_ldap_mod_key_data(struct ipadb_mods *imods, + return 0; + } + +- ret = ber_encode_krb5_key_data(key_data, n_key_data, mkvno, &bval); +- if (ret != 0) { +- kerr = ret; ++ /* Copy key list. */ ++ kvno_kdata = calloc(n_key_data, sizeof(*kvno_kdata)); ++ if (!kvno_kdata) ++ return ENOMEM; ++ ++ memcpy(kvno_kdata, key_data, n_key_data * sizeof(*kvno_kdata)); ++ ++ /* Make sure the key list is sorted by KVNO and enctype. */ ++ qsort(kvno_kdata, n_key_data, sizeof(*kvno_kdata), desc_key_data); ++ ++ /* Count number of distinct KVNOs. */ ++ for (i = 1, n_kvno = 1; i < n_key_data; ++i) { ++ if (kvno_kdata[i - 1].key_data_kvno != kvno_kdata[i].key_data_kvno) ++ ++n_kvno; ++ } ++ ++ bvals = calloc(n_kvno, sizeof(*bvals)); ++ if (!bvals) { ++ kerr = ENOMEM; + goto done; + } + +- kerr = ipadb_get_ldap_mod_bvalues(imods, "krbPrincipalKey", +- &bval, 1, mod_op); ++ /* Add a "krbPrincipalKey" attribute for each KVNO. */ ++ for (i = 0, j = 0, begin = 0; i < n_key_data; ++i) { ++ if (kvno_kdata[begin].key_data_kvno != kvno_kdata[i].key_data_kvno) { ++ kerr = ber_encode_krb5_key_data(kvno_kdata + begin, i - begin, ++ mkvno, bvals + j); ++ if (kerr) ++ goto done; ++ ++ begin = i; ++ ++j; ++ } ++ } ++ ++ kerr = ber_encode_krb5_key_data(kvno_kdata + begin, i - begin, mkvno, ++ bvals + j); ++ if (kerr) ++ goto done; ++ ++ kerr = ipadb_get_ldap_mod_bvalues(imods, "krbPrincipalKey", bvals, n_kvno, ++ mod_op); + + done: +- if (kerr) { +- ber_bvfree(bval); ++ if (kerr && bvals) { ++ for (i = 0; i < n_kvno; ++i) ++ ber_bvfree(bvals[i]); ++ free(bvals); + } ++ free(kvno_kdata); + return kerr; + } + +diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c +index 0087e53e689fc4dc5549908b3eadd6d963d94489..fbd4d57de6728cd6d9449f25c7eb0d5e48269dbe 100644 +--- a/util/ipa_krb5.c ++++ b/util/ipa_krb5.c +@@ -394,6 +394,13 @@ int ber_encode_krb5_key_data(krb5_key_data *data, + + for (i = 0; i < numk; i++) { + ++ /* All keys must have the same KVNO, because there is only one attribute ++ * for all of them. */ ++ if (data[i].key_data_kvno != data[0].key_data_kvno) { ++ ret = EINVAL; ++ goto done; ++ } ++ + ret = ber_printf(be, "{"); + if (ret == -1) { + ret = EFAULT; +-- +2.50.0 + diff --git a/0096-Use-ipaplatform-tasks-for-krb5-enctypes.patch b/0096-Use-ipaplatform-tasks-for-krb5-enctypes.patch new file mode 100644 index 0000000..a13dc0a --- /dev/null +++ b/0096-Use-ipaplatform-tasks-for-krb5-enctypes.patch @@ -0,0 +1,214 @@ +From fb90a9492150d668003984345dcac874c4e26e61 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Wed, 12 Mar 2025 13:49:47 +0100 +Subject: [PATCH] Use ipaplatform tasks for krb5 enctypes + +Provide the master key encryption type and the list of supported +encryption types as ipaplatform..tasks methods. This allows +to generate the list at runtime based on the environment (e.g. FIPS) and +override the list depending of the platform. + +3DES HMAC-SHA1 encryption type is now removed from supported encryption +types if it is present. + +Reviewed-By: Rob Crittenden +--- + install/share/kerberos.ldif | 18 +----------------- + install/updates/50-krbenctypes.update | 11 +---------- + ipaplatform/base/tasks.py | 25 +++++++++++++++++++++++++ + ipaplatform/redhat/tasks.py | 8 ++++++++ + ipaserver/install/krbinstance.py | 27 +++++++++++---------------- + ipaserver/install/ldapupdate.py | 17 ++++++++++++++++- + 6 files changed, 62 insertions(+), 44 deletions(-) + +diff --git a/install/share/kerberos.ldif b/install/share/kerberos.ldif +index 3a5c30ec8533b6d60c614f276090bf2f4cfcd075..78c29923b166594c0c977304f4eed30823e69afb 100644 +--- a/install/share/kerberos.ldif ++++ b/install/share/kerberos.ldif +@@ -14,25 +14,9 @@ objectClass: krbrealmcontainer + objectClass: krbticketpolicyaux + krbSubTrees: $SUFFIX + krbSearchScope: 2 +-krbSupportedEncSaltTypes: aes256-cts:normal +-krbSupportedEncSaltTypes: aes256-cts:special +-krbSupportedEncSaltTypes: aes128-cts:normal +-krbSupportedEncSaltTypes: aes128-cts:special +-krbSupportedEncSaltTypes: aes128-sha2:normal +-krbSupportedEncSaltTypes: aes128-sha2:special +-krbSupportedEncSaltTypes: aes256-sha2:normal +-krbSupportedEncSaltTypes: aes256-sha2:special +-${FIPS}krbSupportedEncSaltTypes: camellia128-cts-cmac:normal +-${FIPS}krbSupportedEncSaltTypes: camellia128-cts-cmac:special +-${FIPS}krbSupportedEncSaltTypes: camellia256-cts-cmac:normal +-${FIPS}krbSupportedEncSaltTypes: camellia256-cts-cmac:special + krbMaxTicketLife: 86400 + krbMaxRenewableAge: 604800 +-krbDefaultEncSaltTypes: aes256-sha2:special +-krbDefaultEncSaltTypes: aes128-sha2:special +-krbDefaultEncSaltTypes: aes256-cts:special +-krbDefaultEncSaltTypes: aes128-cts:special +- ++${LDIF_SUPPORTED_ENCTYPES}${LDIF_DEFAULT_ENCTYPES} + # Default password Policy + dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX + changetype: add +diff --git a/install/updates/50-krbenctypes.update b/install/updates/50-krbenctypes.update +index 1bf2bf33a6566586639767771dff501d91a03508..3061b98c94b255dd99d77ed32e155f0447c45413 100644 +--- a/install/updates/50-krbenctypes.update ++++ b/install/updates/50-krbenctypes.update +@@ -1,11 +1,2 @@ + dn: cn=$REALM,cn=kerberos,$SUFFIX +-${FIPS}add: krbSupportedEncSaltTypes: camellia128-cts-cmac:normal +-${FIPS}add: krbSupportedEncSaltTypes: camellia128-cts-cmac:special +-${FIPS}add: krbSupportedEncSaltTypes: camellia256-cts-cmac:normal +-${FIPS}add: krbSupportedEncSaltTypes: camellia256-cts-cmac:special +-add: krbSupportedEncSaltTypes: aes128-sha2:normal +-add: krbSupportedEncSaltTypes: aes128-sha2:special +-add: krbSupportedEncSaltTypes: aes256-sha2:normal +-add: krbSupportedEncSaltTypes: aes256-sha2:special +-remove: krbDefaultEncSaltTypes: des3-hmac-sha1:special +-remove: krbDefaultEncSaltTypes: arcfour-hmac:special ++${ADD_SUPPORTED_ENCTYPES}${ADD_DEFAULT_ENCTYPES}${REMOVE_SUPPORTED_ENCTYPES}${REMOVE_DEFAULT_ENCTYPES} +diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py +index 4108a7ced240c3fa98a2bd58d21f655227d95a55..9e221d872e7ca9ac0607ff29e1b51dedcf688d75 100644 +--- a/ipaplatform/base/tasks.py ++++ b/ipaplatform/base/tasks.py +@@ -540,4 +540,29 @@ class BaseTaskNamespace: + 'ipa-client-automount-nsswitch', 'previous-automount' + ) + ++ def get_masterkey_enctype(self): ++ return 'aes256-sha2' ++ ++ # Encryption types allowed for Kerberos keys ++ def get_supported_enctypes(self): ++ return ('aes256-sha2:special', 'aes128-sha2:special', ++ 'aes256-sha2:normal', 'aes128-sha2:normal', ++ 'aes256-cts:special', 'aes128-cts:special', ++ 'aes256-cts:normal', 'aes128-cts:normal', ++ 'camellia256-cts:special', 'camellia128-cts:special', ++ 'camellia256-cts:normal', 'camellia128-cts:normal') ++ ++ # Encryption types used in the past, not supported anymore ++ def get_removed_supported_enctypes(self): ++ return ('des3-hmac-sha1:special') ++ ++ # Encryption types used by default when generating Kerberos keys ++ def get_default_enctypes(self): ++ return ('aes256-sha2:special', 'aes128-sha2:special', ++ 'aes256-cts:special', 'aes128-cts:special') ++ ++ # Encryption types no longer used by default when generating keys ++ def get_removed_default_enctypes(self): ++ return ('des3-hmac-sha1:special', 'arcfour-hmac:special') ++ + tasks = BaseTaskNamespace() +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index 18203bf0e25838ef529d4da998a84bdfbb715ce6..4953dc78ab0437b4c0041c1194f06b30d8628228 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -751,5 +751,13 @@ class RedHatTaskNamespace(BaseTaskNamespace): + logger.info("It may happen if the configuration was done " + "using authconfig instead of authselect") + ++ def get_supported_enctypes(self): ++ enctypes = super().get_supported_enctypes() ++ ++ if not self.is_fips_enabled(): ++ return enctypes ++ ++ return tuple(e for e in enctypes if not e.startswith('camellia')) ++ + + tasks = RedHatTaskNamespace() +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 9f0eea56301d66391b6ba87a7a2a4b7ed4e9eaa5..fb1a2884226a45e3c76f32432fe9b0831eebb888 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -55,14 +55,6 @@ from ipaplatform.paths import paths + + logger = logging.getLogger(__name__) + +-MASTER_KEY_TYPE = 'aes256-sha2' +-SUPPORTED_ENCTYPES = ('aes256-sha2:special', 'aes128-sha2:special', +- 'aes256-sha2:normal', 'aes128-sha2:normal', +- 'aes256-cts:special', 'aes128-cts:special', +- 'aes256-cts:normal', 'aes128-cts:normal', +- 'camellia256-cts:special', 'camellia128-cts:special', +- 'camellia256-cts:normal', 'camellia128-cts:normal') +- + + def get_pkinit_request_ca(): + """ +@@ -299,15 +291,18 @@ class KrbInstance(service.Service): + INCLUDES=includes, + FIPS='#' if fips_enabled else '') + +- if fips_enabled: +- supported_enctypes = list( +- filter(lambda e: not e.startswith('camellia'), +- SUPPORTED_ENCTYPES)) +- else: +- supported_enctypes = SUPPORTED_ENCTYPES +- self.sub_dict['SUPPORTED_ENCTYPES'] = ' '.join(supported_enctypes) ++ supported_enctypes = tasks.get_supported_enctypes() ++ str_supported_enctypes = ' '.join(supported_enctypes) ++ ldif_supported_enctypes = ''.join(f'krbSupportedEncSaltTypes: {e}\n' ++ for e in supported_enctypes) ++ ldif_default_enctypes = ''.join(f'krbDefaultEncSaltTypes: {e}\n' ++ for e in tasks.get_default_enctypes()) ++ ++ self.sub_dict['SUPPORTED_ENCTYPES'] = str_supported_enctypes ++ self.sub_dict['LDIF_SUPPORTED_ENCTYPES'] = ldif_supported_enctypes ++ self.sub_dict['LDIF_DEFAULT_ENCTYPES'] = ldif_default_enctypes + +- self.sub_dict['MASTER_KEY_TYPE'] = MASTER_KEY_TYPE ++ self.sub_dict['MASTER_KEY_TYPE'] = tasks.get_masterkey_enctype() + + # IPA server/KDC is not a subdomain of default domain + # Proper domain-realm mapping needs to be specified +diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py +index c3b59732ae8991b2e9ff203caab00da72e093781..9a1a1167ee168e5fea45517e01199baaeb29645b 100644 +--- a/ipaserver/install/ldapupdate.py ++++ b/ipaserver/install/ldapupdate.py +@@ -54,6 +54,9 @@ UPDATES_DIR=paths.UPDATES_DIR + UPDATE_SEARCH_TIME_LIMIT = 30 # seconds + + ++def ldif_mod(op, attr, values): ++ return ''.join(f'{op}: {attr}: {v}\n' for v in values) ++ + def get_sub_dict(realm, domain, suffix, fqdn, idstart=None, idmax=None): + """LDAP template substitution dict for installer and updater + """ +@@ -73,6 +76,15 @@ def get_sub_dict(realm, domain, suffix, fqdn, idstart=None, idmax=None): + named_uid = None + named_gid = None + ++ add_supported_enctypes = ldif_mod('add', 'krbSupportedEncSaltTypes', ++ tasks.get_supported_enctypes()) ++ add_default_enctypes = ldif_mod('add', 'krbDefaultEncSaltTypes', ++ tasks.get_default_enctypes()) ++ rm_supported_enctypes = ldif_mod('remove', 'krbSupportedEncSaltTypes', ++ tasks.get_removed_supported_enctypes()) ++ rm_default_enctypes = ldif_mod('remove', 'krbDefaultEncSaltTypes', ++ tasks.get_removed_default_enctypes()) ++ + return dict( + REALM=realm, + DOMAIN=domain, +@@ -82,7 +94,10 @@ def get_sub_dict(realm, domain, suffix, fqdn, idstart=None, idmax=None): + HOST=fqdn, + LIBARCH=paths.LIBARCH, + TIME=int(time.time()), +- FIPS="#" if tasks.is_fips_enabled() else "", ++ ADD_SUPPORTED_ENCTYPES=add_supported_enctypes, ++ ADD_DEFAULT_ENCTYPES=add_default_enctypes, ++ REMOVE_SUPPORTED_ENCTYPES=rm_supported_enctypes, ++ REMOVE_DEFAULT_ENCTYPES=rm_default_enctypes, + # idstart, idmax, and idrange_size may be None + IDSTART=idstart, + IDMAX=idmax, +-- +2.50.0 + diff --git a/0097-Add-test-for-master-key-upgrade.patch b/0097-Add-test-for-master-key-upgrade.patch new file mode 100644 index 0000000..0b2bc64 --- /dev/null +++ b/0097-Add-test-for-master-key-upgrade.patch @@ -0,0 +1,331 @@ +From b69616ed48224b48b5615044314787f69af13c13 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Wed, 12 Mar 2025 13:50:46 +0100 +Subject: [PATCH] Add test for master key upgrade + +Since commit 4ed7da378940198cf4415f86d4eb013de6ac6455 in MIT krb5, +kdb5_util sets the required bits on the modification mask of updated +principal entries to enable ipa-kdb to switch the active master key. + +This commit creates a "test_fedora_legacy" ipaplatform where the AES +HMAC-SHA2 encryption types are not enabled. "test_mkey_upgrade" uses +this platform to initialize a domain with an aes256-cts-hmac-sha1-96 +master key, and test its upgrade to aes256-cts-hmac-sha384-192. + +Some parts of the test infrastructure had to be made aware of this new +platform (e.g. firewall integration). + +Reviewed-By: Rob Crittenden +--- + ipaplatform/setup.py | 1 + + ipaplatform/test_fedora_legacy/__init__.py | 7 + + ipaplatform/test_fedora_legacy/constants.py | 16 +++ + ipaplatform/test_fedora_legacy/paths.py | 13 ++ + ipaplatform/test_fedora_legacy/services.py | 27 ++++ + ipaplatform/test_fedora_legacy/tasks.py | 35 +++++ + ipatests/pytest_ipa/integration/firewall.py | 1 + + .../test_integration/test_mkey_upgrade.py | 135 ++++++++++++++++++ + 8 files changed, 235 insertions(+) + create mode 100644 ipaplatform/test_fedora_legacy/__init__.py + create mode 100644 ipaplatform/test_fedora_legacy/constants.py + create mode 100644 ipaplatform/test_fedora_legacy/paths.py + create mode 100644 ipaplatform/test_fedora_legacy/services.py + create mode 100644 ipaplatform/test_fedora_legacy/tasks.py + create mode 100644 ipatests/test_integration/test_mkey_upgrade.py + +diff --git a/ipaplatform/setup.py b/ipaplatform/setup.py +index 086a99d1fa602551d2ff3270113608aa0fbc026c..1d6df1eff62b434162a7ce815e8273241d424c78 100644 +--- a/ipaplatform/setup.py ++++ b/ipaplatform/setup.py +@@ -42,6 +42,7 @@ if __name__ == '__main__': + "ipaplatform.rhel", + "ipaplatform.rhel_container", + "ipaplatform.suse", ++ "ipaplatform.test_fedora_legacy", + "ipaplatform.opencloudos", + "ipaplatform.tencentos" + ], +diff --git a/ipaplatform/test_fedora_legacy/__init__.py b/ipaplatform/test_fedora_legacy/__init__.py +new file mode 100644 +index 0000000000000000000000000000000000000000..a4f4cff5a7084d5d1697aefbe2bebcfb89e0a694 +--- /dev/null ++++ b/ipaplatform/test_fedora_legacy/__init__.py +@@ -0,0 +1,7 @@ ++# ++# Copyright (C) 2025 FreeIPA Contributors see COPYING for license ++# ++""" ++This module contains Fedora AES HMAC-SHA1 master key specific platform files. ++""" ++NAME = 'test_fedora_legacy' +diff --git a/ipaplatform/test_fedora_legacy/constants.py b/ipaplatform/test_fedora_legacy/constants.py +new file mode 100644 +index 0000000000000000000000000000000000000000..0cebac86a9eea45803af669d8237dffd34675d74 +--- /dev/null ++++ b/ipaplatform/test_fedora_legacy/constants.py +@@ -0,0 +1,16 @@ ++# ++# Copyright (C) 2025 FreeIPA Contributors see COPYING for license ++# ++"""Fedora AES HMAC-SHA1 master key constants ++""" ++from ipaplatform.fedora.constants import FedoraConstantsNamespace, User, Group ++ ++ ++__all__ = ("constants", "User", "Group") ++ ++ ++class TestFedoraLegacyConstantsNamespace(FedoraConstantsNamespace): ++ pass ++ ++ ++constants = TestFedoraLegacyConstantsNamespace() +diff --git a/ipaplatform/test_fedora_legacy/paths.py b/ipaplatform/test_fedora_legacy/paths.py +new file mode 100644 +index 0000000000000000000000000000000000000000..71fb8acdc9143a4daa14a0b0dc7cf46fe5fdc2ce +--- /dev/null ++++ b/ipaplatform/test_fedora_legacy/paths.py +@@ -0,0 +1,13 @@ ++# ++# Copyright (C) 2025 FreeIPA Contributors see COPYING for license ++# ++"""Fedora AES HMAC-SHA1 master key paths ++""" ++from ipaplatform.fedora.paths import FedoraPathNamespace ++ ++ ++class TestFedoraLegacyPathNamespace(FedoraPathNamespace): ++ pass ++ ++ ++paths = TestFedoraLegacyPathNamespace() +diff --git a/ipaplatform/test_fedora_legacy/services.py b/ipaplatform/test_fedora_legacy/services.py +new file mode 100644 +index 0000000000000000000000000000000000000000..adbe21f82e215349e54b586cdd5201374dd1378e +--- /dev/null ++++ b/ipaplatform/test_fedora_legacy/services.py +@@ -0,0 +1,27 @@ ++# ++# Copyright (C) 2025 FreeIPA Contributors see COPYING for license ++# ++"""Fedora AES HMAC-SHA1 master key services ++""" ++from ipaplatform.fedora import services as fedora_services ++ ++ ++test_fedora_legacy_system_units = fedora_services.fedora_system_units.copy() ++ ++ ++class TestFedoraLegacyService(fedora_services.FedoraService): ++ system_units = test_fedora_legacy_system_units ++ ++ ++def test_fedora_legacy_service_class_factory(name, api=None): ++ return fedora_services.fedora_service_class_factory(name, api) ++ ++ ++class TestFedoraLegacyServices(fedora_services.FedoraServices): ++ def service_class_factory(self, name, api=None): ++ return test_fedora_legacy_service_class_factory(name, api) ++ ++ ++timedate_services = fedora_services.timedate_services ++service = test_fedora_legacy_service_class_factory ++knownservices = TestFedoraLegacyServices() +diff --git a/ipaplatform/test_fedora_legacy/tasks.py b/ipaplatform/test_fedora_legacy/tasks.py +new file mode 100644 +index 0000000000000000000000000000000000000000..e6e72d7237cbc7d2a14b92cbb746bf8d66b197f2 +--- /dev/null ++++ b/ipaplatform/test_fedora_legacy/tasks.py +@@ -0,0 +1,35 @@ ++# ++# Copyright (C) 2025 FreeIPA Contributors see COPYING for license ++# ++"""Fedora AES HMAC-SHA1 master key tasks ++""" ++from ipaplatform.fedora.tasks import FedoraTaskNamespace ++ ++from re import compile ++ ++ ++def add_aes_sha1(enctypes): ++ return tuple({*enctypes, ++ 'aes256-cts:special', 'aes128-cts:special', ++ 'aes256-cts:normal', 'aes128-cts:normal'}) ++ ++ ++class TestFedoraLegacyTaskNamespace(FedoraTaskNamespace): ++ ++ def get_masterkey_enctype(self): ++ return 'aes256-cts' ++ ++ def get_supported_enctypes(self): ++ aes_sha2_pattern = compile('^aes[0-9]+-sha2:') ++ ++ return tuple(e for e in super().get_supported_enctypes() ++ if not aes_sha2_pattern.match(e)) ++ ++ def get_removed_supported_enctypes(self): ++ return add_aes_sha1(super().get_removed_supported_enctypes()) ++ ++ def get_removed_default_enctypes(self): ++ return add_aes_sha1(super().get_removed_default_enctypes()) ++ ++ ++tasks = TestFedoraLegacyTaskNamespace() +diff --git a/ipatests/pytest_ipa/integration/firewall.py b/ipatests/pytest_ipa/integration/firewall.py +index 1a5af5c5e71f71da4c939cddede7cab4817dd3a3..01661b6c6ab84b5ad0f13ebd537b25a2adf0ec1c 100644 +--- a/ipatests/pytest_ipa/integration/firewall.py ++++ b/ipatests/pytest_ipa/integration/firewall.py +@@ -239,6 +239,7 @@ class Firewall(FirewallBase): + firewalls = { + 'rhel': FirewallD, + 'fedora': FirewallD, ++ 'test_fedora_legacy': FirewallD, + 'debian': FirewallD, + 'ubuntu': FirewallD, + 'altlinux': NoOpFirewall, +diff --git a/ipatests/test_integration/test_mkey_upgrade.py b/ipatests/test_integration/test_mkey_upgrade.py +new file mode 100644 +index 0000000000000000000000000000000000000000..933623fbfc913ed6efe5409b3a35af1524305c8e +--- /dev/null ++++ b/ipatests/test_integration/test_mkey_upgrade.py +@@ -0,0 +1,135 @@ ++# ++# Copyright (C) 2015 FreeIPA Contributors see COPYING for license ++# ++ ++import re ++import textwrap ++ ++from ipatests.pytest_ipa.integration import tasks ++from ipatests.test_integration.base import IntegrationTest ++ ++ ++class TestMkeyUpgrade(IntegrationTest): ++ ++ num_replicas = 1 ++ topology = 'line' ++ ++ @classmethod ++ def install(cls, mh): ++ cls.master.put_file_contents( ++ '/etc/profile.d/ipaplatform.sh', ++ 'export IPAPLATFORM_OVERRIDE=test_fedora_legacy') ++ cls.master.run_command(['mkdir', '/etc/systemd/system/ipa.service.d']) ++ cls.master.put_file_contents( ++ '/etc/systemd/system/ipa.service.d/platform.conf', ++ '[Service]\n' ++ 'Environment="IPAPLATFORM_OVERRIDE=test_fedora_legacy"') ++ cls.master.run_command(['systemctl', 'daemon-reload']) ++ tasks.install_master(cls.master, setup_dns=False) ++ tasks.install_replica(cls.master, cls.replicas[0], setup_dns=False) ++ ++ def test_old_active_mkey(self): ++ p = re.compile('^KVNO: 1, Enctype: aes256-cts-hmac-sha1-96, .+ \\*$', ++ flags=re.MULTILINE) ++ ++ result = self.master.run_command(['kdb5_util', 'list_mkeys']) ++ assert p.search(result.stdout_text) ++ result = self.replicas[0].run_command(['kdb5_util', 'list_mkeys']) ++ assert p.search(result.stdout_text) ++ ++ def test_enable_new_entypes(self): ++ base_dn = "dc=%s" % (",dc=".join(self.master.domain.name.split("."))) ++ realm = self.master.domain.name.upper() ++ ++ entry_ldif = textwrap.dedent(""" ++ dn: cn={realm},cn=kerberos,{base_dn} ++ changetype: modify ++ replace: krbSupportedEncSaltTypes ++ krbSupportedEncSaltTypes: aes128-sha2:normal ++ krbSupportedEncSaltTypes: aes128-sha2:special ++ krbSupportedEncSaltTypes: aes256-sha2:normal ++ krbSupportedEncSaltTypes: aes256-sha2:special ++ krbSupportedEncSaltTypes: aes256-cts:normal ++ krbSupportedEncSaltTypes: aes256-cts:special ++ krbSupportedEncSaltTypes: aes128-cts:normal ++ krbSupportedEncSaltTypes: aes128-cts:special ++ krbSupportedEncSaltTypes: camellia128-cts-cmac:normal ++ krbSupportedEncSaltTypes: camellia128-cts-cmac:special ++ krbSupportedEncSaltTypes: camellia256-cts-cmac:normal ++ krbSupportedEncSaltTypes: camellia256-cts-cmac:special ++ - ++ replace: krbDefaultEncSaltTypes ++ krbDefaultEncSaltTypes: aes256-sha2:special ++ krbDefaultEncSaltTypes: aes128-sha2:special ++ krbDefaultEncSaltTypes: aes256-cts:special ++ krbDefaultEncSaltTypes: aes128-cts:special""").format( ++ base_dn=base_dn, realm=realm) ++ tasks.ldapmodify_dm(self.master, entry_ldif) ++ ++ def test_add_new_mkey(self): ++ self.master.run_command('kdb5_util add_mkey -e aes256-sha2 -s', ++ stdin_text='Secret123\nSecret123') ++ ++ def test_new_inactive_mkey(self): ++ p = re.compile('^KVNO: 2, Enctype: aes256-cts-hmac-sha384-192, ', ++ flags=re.MULTILINE) ++ ++ result = self.master.run_command(['kdb5_util', 'list_mkeys']) ++ assert p.search(result.stdout_text) ++ result = self.replicas[0].run_command(['kdb5_util', 'list_mkeys']) ++ assert p.search(result.stdout_text) ++ ++ def test_switch_mkey(self): ++ self.master.run_command(['kdb5_util', 'use_mkey', '2']) ++ ++ def test_new_active_mkey(self): ++ p = re.compile('^KVNO: 2, Enctype: aes256-cts-hmac-sha384-192, .+ \\*$', ++ flags=re.MULTILINE) ++ ++ result = self.master.run_command(['kdb5_util', 'list_mkeys']) ++ assert p.search(result.stdout_text) ++ result = self.replicas[0].run_command(['kdb5_util', 'list_mkeys']) ++ assert p.search(result.stdout_text) ++ ++ def test_used_old_mkey(self): ++ p = re.compile('^MKey: vno 1$', flags=re.MULTILINE) ++ ++ result = self.master.run_command(['kadmin.local', 'getprinc', ++ f'ldap/{self.master.hostname}']) ++ assert p.search(result.stdout_text) ++ result = self.replicas[0].run_command(['kadmin.local', 'getprinc', ++ f'ldap/{self.master.hostname}']) ++ assert p.search(result.stdout_text) ++ ++ def test_reencrypt_with_new_mkey(self): ++ self.master.run_command(['kdb5_util', '-x', 'unlockiter', ++ 'update_princ_encryption', '-vf']) ++ ++ def test_used_new_mkey(self): ++ p = re.compile('^MKey: vno 2$', flags=re.MULTILINE) ++ ++ result = self.master.run_command(['kadmin.local', 'getprinc', ++ f'ldap/{self.master.hostname}']) ++ assert p.search(result.stdout_text) ++ result = self.replicas[0].run_command(['kadmin.local', 'getprinc', ++ f'ldap/{self.master.hostname}']) ++ assert p.search(result.stdout_text) ++ ++ def test_purge_old_mkey(self): ++ self.master.run_command(['kdb5_util', 'purge_mkeys', '-vf']) ++ ++ def test_only_new_mkey(self): ++ p = re.compile('^KVNO: 1,', flags=re.MULTILINE) ++ ++ result = self.master.run_command(['kdb5_util', 'list_mkeys']) ++ assert not p.search(result.stdout_text) ++ result = self.replicas[0].run_command(['kdb5_util', 'list_mkeys']) ++ assert not p.search(result.stdout_text) ++ ++ @classmethod ++ def uninstall(cls, mh): ++ cls.master.run_command([ ++ 'rm', '/etc/profile.d/ipaplatform.sh', ++ '/etc/systemd/system/ipa.service.d/platform.conf']) ++ cls.master.run_command(['rmdir', '/etc/systemd/system/ipa.service.d']) ++ super().uninstall(mh) +-- +2.50.0 + diff --git a/0098-ipa-client-install-New-no-dnssec-validation-option.patch b/0098-ipa-client-install-New-no-dnssec-validation-option.patch new file mode 100644 index 0000000..b223d5c --- /dev/null +++ b/0098-ipa-client-install-New-no-dnssec-validation-option.patch @@ -0,0 +1,108 @@ +From 5db3bfafe6c12222b656f67d5ae3f6745e5f2644 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Thu, 12 Jun 2025 16:23:13 +0200 +Subject: [PATCH] ipa-client-install: New --no-dnssec-validation option + +The new option is needed to be able to deactivate DNSSEC validation +for unbound. + +Unbound is by default configured to do DNSSEC validation with the +validator module. + +The solution is to set module-config to "iterator". + +When the server is built with EDNS client subnet support this should be +changed to "subnetcache iterator" according to the unbound man page. + +Fixes: https://pagure.io/freeipa/issue/9805 +Signed-off-by: Thomas Woerner +Reviewed-By: Antonio Torres +Reviewed-By: Alexander Bokovoy +--- + client/man/ipa-client-install.1 | 3 +++ + client/share/unbound.conf.template | 1 + + ipaclient/install/client.py | 22 +++++++++++++++++++++- + 3 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 +index 6833991b83bf60718fc74a12657342715c0fda91..5432c48a993eec6aaf819d9ce2e0e82ff7c1e62a 100644 +--- a/client/man/ipa-client-install.1 ++++ b/client/man/ipa-client-install.1 +@@ -204,6 +204,9 @@ Create DNS A/AAAA record for each IP address on this host. + .TP + \fB\-\-dns\-over\-tls\fR + Configure DNS over TLS. ++.TP ++\fB\-\-no\-dnssec\-validation\fR ++Disable DNSSEC validation for DNS over TLS. + + .SS "SSSD OPTIONS" + .TP +diff --git a/client/share/unbound.conf.template b/client/share/unbound.conf.template +index 166036f651ddc5ba88235a41b2c06579348e5286..f611ebb7effc83fa07e797dfbe78568c27847851 100644 +--- a/client/share/unbound.conf.template ++++ b/client/share/unbound.conf.template +@@ -3,6 +3,7 @@ server: + tls-upstream: yes + interface: 127.0.0.55 + log-servfail: yes ++ ${MODULE_CONFIG_ITERATOR}module-config: "iterator" + forward-zone: + name: "." + forward-tls-upstream: yes +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 43a71828335ad655ad067b5320572d40bee1a44b..96e91268f54aecf08e0791c91811072e8d6f459f 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -1675,13 +1675,17 @@ def client_dns(server, hostname, options): + # setup and enable Unbound as resolver + server_ip = str(list(dnsutil.resolve_ip_addresses(server))[0]) + forward_addr = "forward-addr: %s#%s" % (server_ip, server) ++ # module_config_iterator is commented out if DNSSEC validation is ++ # not disabled. ++ module_config_iterator = '' if options.no_dnssec_validation else '# ' + ipautil.copy_template_file( + paths.UNBOUND_CONF_SRC, + paths.UNBOUND_CONF, + dict( + TLS_CERT_BUNDLE_PATH=os.path.join( + paths.OPENSSL_CERTS_DIR, "ca-bundle.crt"), +- FORWARD_ADDRS=forward_addr ++ FORWARD_ADDRS=forward_addr, ++ MODULE_CONFIG_ITERATOR=module_config_iterator + ) + ) + sr = services.knownservices["systemd-resolved"] +@@ -2419,6 +2423,16 @@ def install_check(options): + if not check_ip_addresses(options): + raise ScriptError(rval=CLIENT_INSTALL_ERROR) + ++ if options.dns_over_tls \ ++ and not services.knownservices["unbound"].is_installed(): ++ raise ScriptError( ++ "To enable DNS over TLS, package ipa-client-encrypted-dns must " ++ "be installed.") ++ if options.no_dnssec_validation and not options.dns_over_tls: ++ raise ScriptError( ++ "You can not specify --no-dnssec-validation option without the" ++ "--dns-over-tls option.") ++ + # Create the discovery instance + ds = discovery.IPADiscovery() + +@@ -4061,6 +4075,12 @@ class ClientInstallInterface(hostname_.HostNameInstallInterface, + ) + dns_over_tls = enroll_only(dns_over_tls) + ++ no_dnssec_validation = knob( ++ None, ++ description="Disable DNSSEC validation for DNS over TLS", ++ ) ++ no_dnssec_validation = enroll_only(no_dnssec_validation) ++ + request_cert = knob( + None, + deprecated=True, +-- +2.50.0 + diff --git a/0099-ipaserver-install-dns.py-Allow-to-Turn-off-DNSSEC-va.patch b/0099-ipaserver-install-dns.py-Allow-to-Turn-off-DNSSEC-va.patch new file mode 100644 index 0000000..9309162 --- /dev/null +++ b/0099-ipaserver-install-dns.py-Allow-to-Turn-off-DNSSEC-va.patch @@ -0,0 +1,46 @@ +From 0412252dd9a27138411e942305cdf54e70c06f27 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Mon, 23 Jun 2025 14:36:51 +0200 +Subject: [PATCH] ipaserver/install/dns.py: Allow to Turn off DNSSEC validation + for unbound + +Unbound is by default configured to do DNSSEC validation with the validator +module. The solution is to set module-config to "iterator". + +When the server is built with EDNS client subnet support this should be +changed to "subnetcache iterator" according to the unbound man page. + +Fixes: https://pagure.io/freeipa/issue/9805 +Signed-off-by: Thomas Woerner +Reviewed-By: Antonio Torres +Reviewed-By: Alexander Bokovoy +--- + ipaserver/install/dns.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index 470e1915971f66d84e4e4f279caaf81bd3a85cd3..ccec9d8019a250a275cbfac5a360fc3046bcb69c 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -133,13 +133,17 @@ def _setup_dns_over_tls(options): + if options.dot_forwarders: + forward_addrs = ["forward-addr: %s" % fw + for fw in options.dot_forwarders] ++ # module_config_iterator is commented out if DNSSEC validation is ++ # not disabled. ++ module_config_iterator = '' if options.no_dnssec_validation else '# ' + ipautil.copy_template_file( + paths.UNBOUND_CONF_SRC, + paths.UNBOUND_CONF, + dict( + TLS_CERT_BUNDLE_PATH=os.path.join( + paths.OPENSSL_CERTS_DIR, "ca-bundle.crt"), +- FORWARD_ADDRS="\n".join(forward_addrs) ++ FORWARD_ADDRS="\n".join(forward_addrs), ++ MODULE_CONFIG_ITERATOR=module_config_iterator + ) + ) + +-- +2.50.0 + diff --git a/0100-ipatests-Tests-for-32BitIdranges.patch b/0100-ipatests-Tests-for-32BitIdranges.patch new file mode 100644 index 0000000..332f8e7 --- /dev/null +++ b/0100-ipatests-Tests-for-32BitIdranges.patch @@ -0,0 +1,55 @@ +From 15adc2679dabc97fdc4514fc0775be7308bd922a Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Mon, 9 Jun 2025 17:20:32 +0530 +Subject: [PATCH] ipatests: Tests for 32BitIdranges. + +Running 32BitIdrange tests in AD enviornment + +Signed-off-by: Sudhir Menon +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Florence Blanc-Renaud +--- + .../test_integration/test_32bit_idranges.py | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/ipatests/test_integration/test_32bit_idranges.py b/ipatests/test_integration/test_32bit_idranges.py +index e76e117e5f1627af02274a13d3ac12ca84eb7ad9..a928628d399d3a94901f0220c3af3e97c5115ffe 100644 +--- a/ipatests/test_integration/test_32bit_idranges.py ++++ b/ipatests/test_integration/test_32bit_idranges.py +@@ -6,6 +6,7 @@ from __future__ import absolute_import + + from ipatests.pytest_ipa.integration import tasks + from ipatests.test_integration.base import IntegrationTest ++from ipatests.test_integration.test_trust import BaseTestTrust + + + class Test32BitIdRanges(IntegrationTest): +@@ -102,3 +103,24 @@ class Test32BitIdRanges(IntegrationTest): + ) + assert result.returncode == 0 + assert str(uid) in result.stdout_text ++ ++ ++class Test32BitIdrangeInTrustEnv(Test32BitIdRanges, BaseTestTrust): ++ """ ++ Tests to check 32BitIdrange functionality ++ in IPA-AD trust enviornment ++ """ ++ topology = 'line' ++ num_ad_domains = 1 ++ num_ad_subdomains = 0 ++ num_ad_treedomains = 0 ++ num_clients = 0 ++ ++ @classmethod ++ def install(cls, mh): ++ super(BaseTestTrust, cls).install(mh) ++ cls.ad = cls.ads[0] ++ cls.ad_domain = cls.ad.domain.name ++ tasks.configure_dns_for_trust(cls.master, cls.ad) ++ tasks.install_adtrust(cls.master) ++ tasks.establish_trust_with_ad(cls.master, cls.ad.domain.name) +-- +2.50.0 + diff --git a/0101-Replica-Request-cert-for-DoT-before-setting-up-bind.patch b/0101-Replica-Request-cert-for-DoT-before-setting-up-bind.patch new file mode 100644 index 0000000..a4f5168 --- /dev/null +++ b/0101-Replica-Request-cert-for-DoT-before-setting-up-bind.patch @@ -0,0 +1,59 @@ +From f4cbea00fde8dada84bfd1262b5271035d3ca7a4 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Thu, 12 Jun 2025 18:34:49 +0200 +Subject: [PATCH] Replica: Request cert for DoT before setting up bind + +Deploying a replica with DNS support using an IPA server DNS with DoT +fails while setting up DNS over TLS. The request for the certificate for +DoT using IPA CA is done after the DNS server for the replica is configured. + +The nameserver in /etc/resolv.conf has been changed to 127.0.0.1, but +unbound was not yet configured as a forwarder. + +The solution is to move the cert request before the DNS server +configuration. The unbound config from the client deployment is still +working at that moment. + +Fixes: https://pagure.io/freeipa/issue/9808 +Signed-off-by: Thomas Woerner +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/install/dns.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index ccec9d8019a250a275cbfac5a360fc3046bcb69c..9740faeddb244a56b2dc8a274ff82158f6dd2204 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -114,7 +114,7 @@ def _disable_dnssec(): + conn.update_entry(entry) + + +-def _setup_dns_over_tls(options): ++def _request_cert_for_dns_over_tls(options): + if os.path.isfile(paths.IPA_CA_CRT) and not options.dns_over_tls_cert: + # request certificate for DNS over TLS, using IPA CA + cert = paths.BIND_DNS_OVER_TLS_CRT +@@ -128,6 +128,8 @@ def _setup_dns_over_tls(options): + constants.NAMED_USER.chown(cert, gid=constants.NAMED_GROUP.gid) + constants.NAMED_USER.chown(key, gid=constants.NAMED_GROUP.gid) + ++ ++def _setup_dns_over_tls(options): + # setup and enable Unbound as resolver + forward_addrs = ["# forward-addr: specify here forwarders"] + if options.dot_forwarders: +@@ -435,6 +437,10 @@ def install(standalone, replica, options, api=api): + "and IPA CA is not present." + ) + ++ if options.dns_over_tls: ++ print("Request certificate for DNS over TLS, using IPA CA") ++ _request_cert_for_dns_over_tls(options) ++ + bind = bindinstance.BindInstance(fstore, api=api) + bind.setup(api.env.host, ip_addresses, api.env.realm, api.env.domain, + options.forwarders, options.forward_policy, +-- +2.50.0 + diff --git a/freeipa.spec b/freeipa.spec index 043ef6d..2a2c9aa 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -66,7 +66,6 @@ %if 0%{?rhel} %global package_name ipa %global alt_name freeipa -%global krb5_version 1.20.1-1 %global krb5_kdb_version 9.0 # 0.7.16: https://github.com/drkjam/netaddr/issues/71 %global python_netaddr_version 0.7.19 @@ -83,6 +82,14 @@ %global selinux_policy_version 38.1.1-1 %endif +%if 0%{?rhel} >= 10 +%global krb5_version 1.21.3-6 +%elif 0%{?rhel} == 9 +%global krb5_version 1.21.1-5 +%else +%global krb5_version 1.18.2-31 +%endif + # Fix for TLS 1.3 PHA, RHBZ#1775158 %global httpd_version 2.4.37-21 @@ -110,11 +117,9 @@ %if 0%{?fedora} < 38 # Fix for CVE-2020-28196 -%global krb5_version 1.18.2-29 %global krb5_kdb_version 8.0 %else # Fix for CVE-2020-28196 -%global krb5_version 1.20.1-3 %global krb5_kdb_version 9.0 %endif @@ -130,6 +135,14 @@ %global ds_version 2.1.0 %endif +%if 0%{?fedora} >= 42 +%global krb5_version 1.21.3-5 +%elif 0%{?fedora} == 41 +%global krb5_version 1.21.3-4 +%else +%global krb5_version 1.21.3-3 +%endif + # Fix for TLS 1.3 PHA, RHBZ#1775146 %global httpd_version 2.4.41-9 @@ -218,7 +231,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 18%{?rc_version:.%rc_version}%{?dist} +Release: 19%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -328,6 +341,21 @@ Patch0083: 0083-ipatests-Tests-for-krbLastSuccessfulAuth-warning.patch Patch0084: 0084-ipatests-ipahealthcheck-warns-for-user-provided-cert.patch Patch0085: 0085-Warn-when-UID-is-out-of-local-ID-ranges.patch Patch0086: 0086-ipatests-fix-invalid-range-creation-in-test_ipa_idra.patch +Patch0087: 0087-ipatests-certbot-removed-the-manual-public-ip-loggin.patch +Patch0088: 0088-ipatests-adapt-error-code-and-message-for-samba-4.22.patch +Patch0089: 0089-Fix-inconsistency-in-manpage-for-DoT-forwarder-optio.patch +Patch0090: 0090-Set-krbCanonicalName-admin-REALM-on-the-admin-user.patch +Patch0091: 0091-ipa-client-install-Fix-nsupdate-issues-when-dns_over.patch +Patch0092: 0092-ipatests-fix-test_adtrust_install_with_non_ipa_user.patch +Patch0093: 0093-ipa-idrange-fix-check-that-IPA-server-is-installed.patch +Patch0094: 0094-ipa-migrate-only-remove-repl-state-attribute-options.patch +Patch0095: 0095-ipa-kdb-support-storing-multiple-KVNO-for-the-same-p.patch +Patch0096: 0096-Use-ipaplatform-tasks-for-krb5-enctypes.patch +Patch0097: 0097-Add-test-for-master-key-upgrade.patch +Patch0098: 0098-ipa-client-install-New-no-dnssec-validation-option.patch +Patch0099: 0099-ipaserver-install-dns.py-Allow-to-Turn-off-DNSSEC-va.patch +Patch0100: 0100-ipatests-Tests-for-32BitIdranges.patch +Patch0101: 0101-Replica-Request-cert-for-DoT-before-setting-up-bind.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -1980,6 +2008,14 @@ fi %endif %changelog +* Thu Jun 26 2025 Florence Blanc-Renaud - 4.12.2-19 +- Resolves: RHEL-100450 eDNS: multiple issues during encrypted DNS setup +- Resolves: RHEL-89907 Privilege escalation from host to domain admin in FreeIPA +- Resolves: RHEL-99315 Include latest fixes in python3-ipatests package +- Resolves: RHEL-98565 ipa-idrange-fix: 'Env' object has no attribute 'basedn' +- Resolves: RHEL-96920 Nightly test failure (rawhide) in test_trust.py::TestTrust::test_server_option_with_unreachable_ad +- Resolves: RHEL-31907 kdb: support storing and retrieving multiple master keys + * Wed Jun 11 2025 Florence Blanc-Renaud - 4.12.2-18 - Related: RHEL-89873