diff --git a/0026-Fix-a-couple-of-instances-of-the-no-break-control-ch.patch b/0026-Fix-a-couple-of-instances-of-the-no-break-control-ch.patch new file mode 100644 index 0000000..5a1caf0 --- /dev/null +++ b/0026-Fix-a-couple-of-instances-of-the-no-break-control-ch.patch @@ -0,0 +1,52 @@ +From 993f792f2e26f8a14a5e3691c06a6b15d57072e7 Mon Sep 17 00:00:00 2001 +From: Sam Morris +Date: Tue, 17 Sep 2024 12:43:08 +0100 +Subject: [PATCH] Fix a couple of instances of the "no-break control character" + being used inadvertently + +Fixes https://pagure.io/freeipa/issue/9665 + +Signed-off-by: Sam Morris +Reviewed-By: Alexander Bokovoy +--- + client/man/ipa-client-install.1 | 4 ++-- + client/man/ipa.1 | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 +index 4a755ac33d35246304303b847a62cb3fc97680b7..725b114224781e2f7ec7c71eaf5b7be807008655 100644 +--- a/client/man/ipa-client-install.1 ++++ b/client/man/ipa-client-install.1 +@@ -240,8 +240,8 @@ for more information. The option is mutually exclusive with + \fB\-\-pkinit\-anchor\fR=\fIFILEDIR\fR + Trust anchors (root and intermediate CA certs) for PKINIT. \fIFILEDIR\fR is + either the absolute path to a PEM bundle (for example +-'FILE:/etc/pki/tls/cert.pem') or to an OpenSSL hash directory (for example +-'DIR:/etc/ssl/certs/'). The option can be used multiple times. PKINIT ++\fIFILE:/etc/pki/tls/cert.pem\fR) or to an OpenSSL hash directory (for example ++\fIDIR:/etc/ssl/certs/\fR). The option can be used multiple times. PKINIT + requires the full trust chain of the Kerberos KDC server as well as the full + trust chain of the identity certificate. + +diff --git a/client/man/ipa.1 b/client/man/ipa.1 +index 172c50d8a1f2ba137ea10d93343fb54efbdb765d..c404c5be36da78ebb4d08cd0e4b2b9ea27d9e71b 100644 +--- a/client/man/ipa.1 ++++ b/client/man/ipa.1 +@@ -176,11 +176,11 @@ journal as journald records execution context. See systemd.journal\-fields(7) + for details. + + The details of the individual logged messages can be explained with the help of +-'\fBjournalctl -x\fR' command, while full set of logged properties can be +-retrieved with '\fBjournalctl -o json-pretty\fR'. See journalctl(1) for details ++\fBjournalctl -x\fR command, while full set of logged properties can be ++retrieved with \fBjournalctl -o json-pretty\fR. See journalctl(1) for details + on the systemd journal viewer. + +-For the sample message above, an explanation could be requested with '\fBjournalctl -x -g ldap2_140328582446688\fR' where LDAP backend connection instance identifier can be used to uniquely fetch that individual message. ++For the sample message above, an explanation could be requested with \fBjournalctl -x -g ldap2_140328582446688\fR where LDAP backend connection instance identifier can be used to uniquely fetch that individual message. + + .SH "EXAMPLES" + .TP +-- +2.47.0 + diff --git a/0027-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch b/0027-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch new file mode 100644 index 0000000..2ed299e --- /dev/null +++ b/0027-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch @@ -0,0 +1,35 @@ +From 3d0962014adda39b754c4274ccb5ca5d70963c33 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Mon, 21 Oct 2024 13:51:13 -0400 +Subject: [PATCH] ipa-migrate - dryrun write updates crashes when removing + values + +When removing values the mod value list is None and that leads to a +crash when trying to iterate it. Instead check that the vals are not +None before looping. + +Fixes: https://pagure.io/freeipa/issue/9682 + +Signed-off-by: MArk Reynolds +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/ipa_migrate.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py +index 38356aa23ea435e2a616f48356feaea7b50dd1e4..f35629378490d3d45ca97f2aa5b4390c67d660ed 100644 +--- a/ipaserver/install/ipa_migrate.py ++++ b/ipaserver/install/ipa_migrate.py +@@ -622,7 +622,7 @@ class IPAMigrate(): + else: + action = "replace" + ldif_entry += f"{action}: {attr}\n" +- for val in vals: ++ for val in list(vals or []): + ldif_entry += get_ldif_attr_val(attr, val) + ldif_entry += "-\n" + ldif_entry += "\n" +-- +2.47.0 + diff --git a/0028-ipa-migrate-should-migrate-dns-forward-zones.patch b/0028-ipa-migrate-should-migrate-dns-forward-zones.patch new file mode 100644 index 0000000..ac75a1c --- /dev/null +++ b/0028-ipa-migrate-should-migrate-dns-forward-zones.patch @@ -0,0 +1,30 @@ +From 6bdb8603054fc60e9479f6aaf8b6315dfe508891 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 22 Oct 2024 13:00:03 -0400 +Subject: [PATCH] ipa-migrate should migrate dns forward zones + +Fixes: https://pagure.io/freeipa/issue/9686 + +Signed-off-by: Mark Reynolds +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/ipa_migrate_constants.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/ipa_migrate_constants.py b/ipaserver/install/ipa_migrate_constants.py +index 250f1b5b01bf066d316a98489ab6153b89615173..c140414ea6c607a93e35ef0705480d1002b7945e 100644 +--- a/ipaserver/install/ipa_migrate_constants.py ++++ b/ipaserver/install/ipa_migrate_constants.py +@@ -993,7 +993,7 @@ DB_OBJECTS = { + 'count': 0, + }, + 'dns_records': { +- 'oc': ['idnsrecord', 'idnszone'], ++ 'oc': ['idnsrecord', 'idnszone', 'idnsforwardzone'], + 'subtree': ',cn=dns,$SUFFIX', + 'label': 'DNS Records', + 'mode': 'all', +-- +2.47.0 + diff --git a/0029-vault-handle-pyca-InternalError-exception-for-PKCS-1.patch b/0029-vault-handle-pyca-InternalError-exception-for-PKCS-1.patch new file mode 100644 index 0000000..3f4ff73 --- /dev/null +++ b/0029-vault-handle-pyca-InternalError-exception-for-PKCS-1.patch @@ -0,0 +1,44 @@ +From dad2f06ed6854abbd81b747c26de6c13dfea327b Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 30 Oct 2024 10:48:50 +0200 +Subject: [PATCH] vault: handle pyca InternalError exception for PKCS#1 v1.5 + padding + +In FIPS mode one cannot use PKCS#1 v1.5 padding. OpenSSL did remove it +from the FIPS provider and will report an error that PyCA cannot +process, so it will raise its own InternalException. + +Handle it the same way as ValueError. + +Fixes: https://pagure.io/freeipa/issue/9689 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Francisco Trivino +--- + ipaclient/plugins/vault.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py +index 96edf09a2060e7b39e1e96c6fa65ae095ec18e73..75415c03a57242ae674636fa31a72db2fa56d6ea 100644 +--- a/ipaclient/plugins/vault.py ++++ b/ipaclient/plugins/vault.py +@@ -37,6 +37,7 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + from cryptography.hazmat.primitives.padding import PKCS7 + from cryptography.hazmat.primitives.serialization import ( + load_pem_public_key, load_pem_private_key) ++from cryptography.exceptions import InternalError as CryptographyInternalError + + from ipaclient.frontend import MethodOverride + from ipalib import x509 +@@ -717,7 +718,7 @@ class ModVaultData(Local): + algo.key, + padding.PKCS1v15() + ) +- except ValueError: ++ except (ValueError, CryptographyInternalError): + wrapped_session_key = public_key.encrypt( + algo.key, + padding.OAEP( +-- +2.47.0 + diff --git a/0030-ipatests-Tests-for-ipa-migrate-tool.patch b/0030-ipatests-Tests-for-ipa-migrate-tool.patch new file mode 100644 index 0000000..3b3c85f --- /dev/null +++ b/0030-ipatests-Tests-for-ipa-migrate-tool.patch @@ -0,0 +1,784 @@ +From 9da927c8eec7db6d1c75c296eef45beb93797e58 Mon Sep 17 00:00:00 2001 +From: Sudhir Menon +Date: Thu, 1 Aug 2024 16:30:16 +0530 +Subject: [PATCH] ipatests: Tests for ipa-migrate tool + +This patch includes test to covers below scenarios + +1. hbac and sudo rules are migrated to local server +2. uid for user migrated varies in stage/prod mode. +3. subids are migrated to local server +4. idranges are migrated to local server +5. vaults are not migrated to local server. +6. Ensure trust related data is also migrated to local server +7. Added paths.IPA_MIGRATE_LOG in ipatests/pytest_ipa/integration/__init__.py + +Signed-off-by: Sudhir Menon +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/pytest_ipa/integration/__init__.py | 2 + + .../test_ipa_ipa_migration.py | 596 ++++++++++++++---- + 2 files changed, 460 insertions(+), 138 deletions(-) + +diff --git a/ipatests/pytest_ipa/integration/__init__.py b/ipatests/pytest_ipa/integration/__init__.py +index 34b6ef0fb1e49fbb9c86e7496de50cf5cda5e91e..eb032cd72d2aa2a5ed4c476e3cb04dc77f607eaa 100644 +--- a/ipatests/pytest_ipa/integration/__init__.py ++++ b/ipatests/pytest_ipa/integration/__init__.py +@@ -88,6 +88,8 @@ CLASS_LOGFILES = [ + paths.VAR_LOG_AUDIT, + # sssd + paths.VAR_LOG_SSSD_DIR, ++ # ipa-ipa-migration logs ++ paths.IPA_MIGRATE_LOG, + # system + paths.RESOLV_CONF, + paths.HOSTS, +diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py +index 70c268951a0d7e40806742b16e62b764b2bae37b..d852ca63a6b3a7e7118d66ce1cd9bb98e56f1a73 100644 +--- a/ipatests/test_integration/test_ipa_ipa_migration.py ++++ b/ipatests/test_integration/test_ipa_ipa_migration.py +@@ -12,6 +12,7 @@ from ipaplatform.paths import paths + from collections import Counter + + import pytest ++import re + import textwrap + + +@@ -65,29 +66,7 @@ def prepare_ipa_server(master): + "--secondary-rid-base=400000", + ] + ) +- +- # Add Automount locations and maps +- master.run_command(["ipa", "automountlocation-add", "baltimore"]) +- master.run_command(["ipa", "automountmap-add", "baltimore", "auto.share"]) +- master.run_command( +- [ +- "ipa", +- "automountmap-add-indirect", +- "baltimore", +- "--parentmap=auto.share", +- "--mount=sub auto.man", +- ] +- ) +- master.run_command( +- [ +- "ipa", +- "automountkey-add", +- "baltimore", +- "auto.master", +- "--key=/share", +- "--info=auto.share", +- ] +- ) ++ master.run_command(["ipactl", "restart"]) + + # Run ipa-adtrust-install + master.run_command(["dnf", "install", "-y", "ipa-server-trust-ad"]) +@@ -235,6 +214,17 @@ def prepare_ipa_server(master): + ["ipa", "hbacrule-add-service", "--hbacsvcs=sshd", "testuser_sshd"] + ) + ++ # Add DNSForwardzone ++ master.run_command( ++ [ ++ "ipa", ++ "dnsforwardzone-add", ++ "forwardzone.test", ++ "--forwarder", ++ "10.11.12.13", ++ ] ++ ) ++ + # Vault addition + master.run_command( + [ +@@ -244,6 +234,7 @@ def prepare_ipa_server(master): + "vault1234", + "--type", + "symmetric", ++ "testvault", + ] + ) + +@@ -260,7 +251,46 @@ def prepare_ipa_server(master): + + # Modify passkeyconfig + master.run_command( +- ["ipa", "passkeyconfig-mod", "--require-user-verification=FALSE"] ++ [ ++ "ipa", "passkeyconfig-mod", ++ "--require-user-verification=FALSE" ++ ] ++ ) ++ ++ # Adding automountlocation, maps, keys ++ master.run_command( ++ [ ++ "ipa", "automountlocation-add", ++ "baltimore" ++ ] ++ ) ++ ++ master.run_command( ++ [ ++ "ipa", "automountmap-add", ++ "baltimore", ++ "auto.share" ++ ] ++ ) ++ ++ master.run_command( ++ [ ++ "ipa", "automountmap-add-indirect", ++ "baltimore", ++ "--parentmap=auto.share", ++ "--mount=sub", ++ "auto.man", ++ ] ++ ) ++ ++ master.run_command( ++ [ ++ "ipa", "automountkey-add", ++ "baltimore", ++ "auto.master", ++ "--key=/share", ++ "--info=auto.share", ++ ] + ) + + +@@ -288,12 +318,24 @@ def run_migrate( + return result + + +-class TestIPAMigrateScenario1(IntegrationTest): ++@pytest.fixture() ++def empty_log_file(request): + """ +- Tier-1 tests for ipa-migrate tool with DNS enabled on +- local and remote server ++ This fixture empties the log file before ipa-migrate tool ++ is run since the log is appended everytime the tool is run. + """ ++ request.cls.replicas[0].run_command( ++ ["truncate", "-s", "0", paths.IPA_MIGRATE_LOG] ++ ) ++ yield + ++ ++class MigrationTest(IntegrationTest): ++ """ ++ This class will help setup remote IPA server(cls.master) ++ and local IPA server(cls.replicas[0]) and it will ++ also prepare the remote IPA before migration actually begins. ++ """ + num_replicas = 1 + num_clients = 1 + topology = "line" +@@ -303,14 +345,14 @@ class TestIPAMigrateScenario1(IntegrationTest): + tasks.install_master(cls.master, setup_dns=True, setup_kra=True) + prepare_ipa_server(cls.master) + tasks.install_client(cls.master, cls.clients[0], nameservers=None) ++ tasks.install_master(cls.replicas[0], setup_dns=True, setup_kra=True) + +- def test_remote_server(self): +- """ +- This test installs IPA server instead of replica on +- system under test with the same realm and domain name. +- """ +- tasks.install_master(self.replicas[0], setup_dns=True, setup_kra=True) + ++class TestIPAMigrateCLIOptions(MigrationTest): ++ """ ++ Tests to check CLI options for ipa-migrate tool with ++ DNS enabled on local and remote server. ++ """ + def test_ipa_migrate_without_kinit_as_admin(self): + """ + This test checks that ipa-migrate tool displays +@@ -417,7 +459,7 @@ class TestIPAMigrateScenario1(IntegrationTest): + """ + ldif_file = "/tmp/test.ldif" + param = ['-x', '-o', ldif_file] +- run_migrate( ++ result = run_migrate( + self.replicas[0], + "stage-mode", + self.master.hostname, +@@ -426,45 +468,21 @@ class TestIPAMigrateScenario1(IntegrationTest): + extra_args=param, + ) + assert self.replicas[0].transport.file_exists("/tmp/test.ldif") ++ assert result.returncode == 0 + +- @pytest.fixture() +- def empty_log_file(self): +- """ +- This fixture empties the log file before ipa-migrate tool +- is run since the log is appended everytime the tool is run. +- """ +- self.replicas[0].run_command( +- ["truncate", "-s", "0", paths.IPA_MIGRATE_LOG] +- ) +- yield +- +- def test_ipa_sigden_plugin_fail_error(self, empty_log_file): +- """ +- This testcase checks that sidgen plugin fail error is +- not seen during migrate prod-mode +- """ +- SIDGEN_ERR_MSG = "SIDGEN task failed: \n" +- run_migrate( +- self.replicas[0], +- "stage-mode", +- self.master.hostname, +- "cn=Directory Manager", +- self.master.config.admin_password, +- extra_args=['-x'], +- ) +- error_msg = self.replicas[0].get_file_contents( +- paths.IPA_MIGRATE_LOG, encoding="utf-8" +- ) +- assert SIDGEN_ERR_MSG not in error_msg +- +- def test_ipa_migrate_stage_mode_dry_run(self, empty_log_file): ++ def test_ipa_migrate_stage_mode_dry_run(self): + """ + Test ipa-migrate stage mode with dry-run option ++ This test also checks SIDGEN task failure is ++ not seen in ipa migrate log. + """ + tasks.kinit_admin(self.master) + tasks.kinit_admin(self.replicas[0]) ++ SIDGEN_ERR_MSG = "SIDGEN task failed: \n" + IPA_MIGRATE_STAGE_DRY_RUN_LOG = "--dryrun=True\n" +- IPA_SERVER_UPRGADE_LOG = "Skipping ipa-server-upgrade in dryrun mode.\n" ++ IPA_SERVER_UPRGADE_LOG = ( ++ "Skipping ipa-server-upgrade in dryrun mode.\n" ++ ) + IPA_SKIP_SIDGEN_LOG = "Skipping SIDGEN task in dryrun mode." + result = run_migrate( + self.replicas[0], +@@ -481,6 +499,7 @@ class TestIPAMigrateScenario1(IntegrationTest): + assert IPA_MIGRATE_STAGE_DRY_RUN_LOG in install_msg + assert IPA_SERVER_UPRGADE_LOG in install_msg + assert IPA_SKIP_SIDGEN_LOG in install_msg ++ assert SIDGEN_ERR_MSG not in install_msg + + def test_ipa_migrate_prod_mode_dry_run(self, empty_log_file): + """ +@@ -509,7 +528,7 @@ class TestIPAMigrateScenario1(IntegrationTest): + assert IPA_SERVER_UPRGADE_LOG in install_msg + assert IPA_SIDGEN_LOG in install_msg + +- def test_ipa_migrate_with_skip_schema_option_dry_run(self, empty_log_file): ++ def test_ipa_migrate_skip_schema_dry_run(self, empty_log_file): + """ + This test checks that ipa-migrate tool works + with -S(schema) options in stage mode +@@ -532,7 +551,7 @@ class TestIPAMigrateScenario1(IntegrationTest): + ) + assert SKIP_SCHEMA_MSG_LOG in install_msg + +- def test_ipa_migrate_with_skip_config_option_dry_run(self, empty_log_file): ++ def test_ipa_migrate_skip_config_dry_run(self, empty_log_file): + """ + This test checks that ipa-migrate tool works + with -C(config) options in stage mode +@@ -579,7 +598,7 @@ class TestIPAMigrateScenario1(IntegrationTest): + ) + assert RESET_RANGE_LOG in install_msg + +- def test_ipa_migrate_stage_mode_dry_override_schema(self, empty_log_file): ++ def test_ipa_migrate_stage_mode_override_schema(self, empty_log_file): + """ + This test checks that -O option (override schema) works + in dry mode +@@ -601,70 +620,6 @@ class TestIPAMigrateScenario1(IntegrationTest): + ) + assert SCHEMA_OVERRIDE_LOG in install_msg + +- def test_ipa_migrate_stage_mode(self, empty_log_file): +- """ +- This test checks that ipa-migrate is successful +- in dry run mode +- """ +- tasks.kinit_admin(self.master) +- tasks.kinit_admin(self.replicas[0]) +- MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n" +- MIGRATION_CONFIG_LOG_MSG = "Migrating configuration ...\n" +- IPA_UPGRADE_LOG_MSG = ( +- "Running ipa-server-upgrade ... (this may take a while)\n" +- ) +- SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n" +- MIGRATION_COMPLETE_LOG_MSG = "Migration complete!\n" +- result = run_migrate( +- self.replicas[0], +- "stage-mode", +- self.master.hostname, +- "cn=Directory Manager", +- self.master.config.admin_password, +- extra_args=['-n'], +- ) +- install_msg = self.replicas[0].get_file_contents( +- paths.IPA_MIGRATE_LOG, encoding="utf-8" +- ) +- assert result.returncode == 0 +- assert MIGRATION_SCHEMA_LOG_MSG in install_msg +- assert MIGRATION_CONFIG_LOG_MSG in install_msg +- assert IPA_UPGRADE_LOG_MSG in install_msg +- assert SIDGEN_TASK_LOG_MSG in install_msg +- assert MIGRATION_COMPLETE_LOG_MSG in install_msg +- +- def test_ipa_migrate_prod_mode(self, empty_log_file): +- """ +- This test checks that ipa-migrate is successful +- in prod run mode +- """ +- tasks.kinit_admin(self.master) +- tasks.kinit_admin(self.replicas[0]) +- MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n" +- MIGRATION_DATABASE_LOG_MSG = ( +- "Migrating database ... (this may take a while)\n" +- ) +- IPA_UPGRADE_LOG_MSG = ( +- "Running ipa-server-upgrade ... (this may take a while)\n" +- ) +- SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n" +- result = run_migrate( +- self.replicas[0], +- "prod-mode", +- self.master.hostname, +- "cn=Directory Manager", +- self.master.config.admin_password, +- extra_args=['-n'], +- ) +- install_msg = self.replicas[0].get_file_contents( +- paths.IPA_MIGRATE_LOG, encoding="utf-8" +- ) +- assert result.returncode == 0 +- assert MIGRATION_SCHEMA_LOG_MSG in install_msg +- assert MIGRATION_DATABASE_LOG_MSG in install_msg +- assert IPA_UPGRADE_LOG_MSG in install_msg +- assert SIDGEN_TASK_LOG_MSG in install_msg +- + def test_ipa_migrate_with_bind_pwd_file_option(self, empty_log_file): + """ + This testcase checks that ipa-migrate tool +@@ -801,6 +756,9 @@ class TestIPAMigrateScenario1(IntegrationTest): + + @pytest.fixture() + def modify_dns_zone(self): ++ """ ++ This fixture adds dnszone and then removes the zone. ++ """ + zone_name = 'ipatest.test' + self.master.run_command( + ["ipa", "dnszone-add", zone_name, "--force"] +@@ -844,6 +802,20 @@ class TestIPAMigrateScenario1(IntegrationTest): + assert DNS_LOG2 in install_msg + assert DNS_LOG3 in install_msg + ++ def test_ipa_migrate_dns_forwardzone(self): ++ """ ++ This testcase checks that DNS forwardzone is ++ also migrated in prod-mode ++ """ ++ zone_name = "forwardzone.test" ++ result = self.replicas[0].run_command( ++ ["ipa", "dnsforwardzone-show", zone_name] ++ ) ++ assert 'Zone name: {}'.format(zone_name) in result.stdout_text ++ assert 'Active zone: True' in result.stdout_text ++ assert 'Zone forwarders: 10.11.12.13' in result.stdout_text ++ assert 'Forward policy: first' in result.stdout_text ++ + def test_ipa_migrate_version_option(self): + """ + The -V option has been removed. +@@ -922,20 +894,179 @@ class TestIPAMigrateScenario1(IntegrationTest): + assert result.returncode == 1 + assert ERR_MSG in result.stderr_text + +- def test_ipa_hbac_rule_duplication(self): ++ ++class TestIPAMigrationStageMode(MigrationTest): ++ """ ++ Tests for ipa-migrate tool in stage mode ++ """ ++ def test_ipa_migrate_stage_mode(self, empty_log_file): + """ +- This testcase checks that default hbac rules +- are not duplicated on the local server when +- ipa-migrate command is run. ++ This test checks that ipa-migrate is successful ++ in dry run mode + """ ++ tasks.kinit_admin(self.master) ++ tasks.kinit_admin(self.replicas[0]) ++ MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n" ++ MIGRATION_CONFIG_LOG_MSG = "Migrating configuration ...\n" ++ IPA_UPGRADE_LOG_MSG = ( ++ "Running ipa-server-upgrade ... (this may take a while)\n" ++ ) ++ SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n" ++ MIGRATION_COMPLETE_LOG_MSG = "Migration complete!\n" + run_migrate( ++ self.replicas[0], ++ "stage-mode", ++ self.master.hostname, ++ "cn=Directory Manager", ++ self.master.config.admin_password, ++ extra_args=['-n'], ++ ) ++ install_msg = self.replicas[0].get_file_contents( ++ paths.IPA_MIGRATE_LOG, encoding="utf-8" ++ ) ++ assert MIGRATION_SCHEMA_LOG_MSG in install_msg ++ assert MIGRATION_CONFIG_LOG_MSG in install_msg ++ assert IPA_UPGRADE_LOG_MSG in install_msg ++ assert SIDGEN_TASK_LOG_MSG in install_msg ++ assert MIGRATION_COMPLETE_LOG_MSG in install_msg ++ ++ def test_ipa_migrate_stage_mode_new_user(self): ++ """ ++ This testcase checks that when a new user is added and ++ ipa-migrate is run in stage-mode, uid/gid of the ++ migrated user is not preserved i.e we have different ++ uid/gid for user on remote and local IPA server. ++ """ ++ username = 'testuser4' ++ base_dn = str(self.master.domain.basedn) ++ LOG_MSG1 = ( ++ "DEBUG Resetting the DNA range for new entry: " ++ "uid={},cn=users,cn=accounts,{}\n" ++ ).format(username, base_dn) ++ install_msg = self.replicas[0].get_file_contents( ++ paths.IPA_MIGRATE_LOG, encoding="utf-8" ++ ) ++ assert LOG_MSG1 not in install_msg ++ tasks.clear_sssd_cache(self.master) ++ self.master.run_command(['ipa', 'user-show', username]) ++ cmd1 = self.master.run_command(['id', username]) ++ tasks.clear_sssd_cache(self.replicas[0]) ++ self.replicas[0].run_command(['ipa', 'user-show', username]) ++ cmd2 = self.replicas[0].run_command(['id', username]) ++ assert cmd1.stdout_text != cmd2.stdout_text ++ ++ ++class TestIPAMigrationProdMode(MigrationTest): ++ """ ++ Tests for ipa-migrate tool in prod mode ++ """ ++ def test_ipa_migrate_prod_mode(self, empty_log_file): ++ """ ++ This test checks that ipa-migrate is successful ++ in prod run mode ++ """ ++ tasks.kinit_admin(self.master) ++ tasks.kinit_admin(self.replicas[0]) ++ MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n" ++ MIGRATION_DATABASE_LOG_MSG = ( ++ "Migrating database ... (this may take a while)\n" ++ ) ++ IPA_UPGRADE_LOG_MSG = ( ++ "Running ipa-server-upgrade ... (this may take a while)\n" ++ ) ++ SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n" ++ result = run_migrate( + self.replicas[0], + "prod-mode", + self.master.hostname, + "cn=Directory Manager", + self.master.config.admin_password, +- extra_args=['-n'] ++ extra_args=['-n'], + ) ++ install_msg = self.replicas[0].get_file_contents( ++ paths.IPA_MIGRATE_LOG, encoding="utf-8" ++ ) ++ assert result.returncode == 0 ++ assert MIGRATION_SCHEMA_LOG_MSG in install_msg ++ assert MIGRATION_DATABASE_LOG_MSG in install_msg ++ assert IPA_UPGRADE_LOG_MSG in install_msg ++ assert SIDGEN_TASK_LOG_MSG in install_msg ++ ++ def test_ipa_migrate_prod_mode_hbac_rule(self): ++ """ ++ This testcase checks that hbac rule is migrated from ++ remote server to local server in prod mode. ++ """ ++ hbac_rule_name1 = 'test1' ++ hbac_rule_name2 = 'testuser_sshd' ++ tasks.kinit_admin(self.replicas[0]) ++ cmd1 = self.replicas[0].run_command( ++ ["ipa", "hbacrule-find", hbac_rule_name1]) ++ cmd2 = self.replicas[0].run_command( ++ ["ipa", "hbacrule-find", hbac_rule_name2]) ++ assert hbac_rule_name1 in cmd1.stdout_text ++ assert hbac_rule_name2 in cmd2.stdout_text ++ ++ def test_ipa_migrate_prod_mode_sudo_rule(self): ++ """ ++ This testcase checks that sudo cmd and rules are ++ migrated from remote server to local server in prod mode. ++ """ ++ sudorule = 'readfiles' ++ sudocmd = '/usr/bin/less' ++ tasks.kinit_admin(self.replicas[0]) ++ cmd1 = self.replicas[0].run_command( ++ ["ipa", "sudorule-find", sudorule]) ++ cmd2 = self.replicas[0].run_command( ++ ["ipa", "sudocmd-find", sudocmd]) ++ assert 'Rule name: readfiles\n' in cmd1.stdout_text ++ assert 'Sudo Command: /usr/bin/less\n' in cmd2.stdout_text ++ ++ def test_ipa_migrate_prod_mode_new_user_sid(self): ++ """ ++ This testcase checks that in prod-mode uid/gid of the ++ migrated user is preserved i.e we have same ++ uid/gid for user on remote and local IPA server. ++ """ ++ username = 'testuser4' ++ tasks.clear_sssd_cache(self.master) ++ result1 = self.master.run_command(['id', username]) ++ tasks.clear_sssd_cache(self.replicas[0]) ++ result2 = self.replicas[0].run_command(['id', username]) ++ assert result1.stdout_text == result2.stdout_text ++ ++ def test_check_vault_is_not_migrated(self): ++ """ ++ This testcase checks that vault is ++ not migrated ++ """ ++ vault_name = "testvault" ++ CMD_OUTPUT = "Number of entries returned 0" ++ cmd = self.replicas[0].run_command( ++ ["ipa", "vault-find", vault_name], raiseonerr=False) ++ assert cmd.returncode != 0 ++ assert CMD_OUTPUT in cmd.stdout_text ++ ++ def test_ipa_migrate_subids(self): ++ """ ++ This testcase checks that subids for users are migrated ++ to the local server from the remote server ++ """ ++ user_name = 'admin' ++ CMD_MSG = "1 subordinate id matched" ++ cmd = self.replicas[0].run_command( ++ ['ipa', 'subid-find', ++ '--owner', user_name] ++ ) ++ assert cmd.returncode == 0 ++ assert CMD_MSG in cmd.stdout_text ++ ++ def test_ipa_hbac_rule_duplication(self): ++ """ ++ This testcase checks that default hbac rules ++ are not duplicated on the local server when ++ ipa-migrate command is run. ++ """ + result = self.replicas[0].run_command( + ['ipa', 'hbacrule-find'] + ) +@@ -946,3 +1077,192 @@ class TestIPAMigrateScenario1(IntegrationTest): + count = Counter(line) + assert count.get('Rule name: allow_all') < 2 + assert count.get('Rule name: allow_systemd-user') < 2 ++ ++ def test_ipa_migrate_otptoken(self): ++ """ ++ This testcase checks that the otptoken ++ is migrated for the user. ++ """ ++ owner = "testuser1" ++ CMD_OUTPUT = "1 OTP token matched" ++ result = self.replicas[0].run_command([ ++ "ipa", "otptoken-find" ++ ]) ++ assert CMD_OUTPUT in result.stdout_text ++ assert 'Type: TOTP' in result.stdout_text ++ assert 'Owner: {}'.format(owner) in result.stdout_text ++ ++ def test_ipa_migrate_check_passkey_config(self): ++ """ ++ This testcase checks that passkey config ++ is migrated ++ """ ++ CMD_OUTPUT = "Require user verification: False" ++ result = self.replicas[0].run_command([ ++ "ipa", "passkeyconfig-show" ++ ]) ++ assert CMD_OUTPUT in result.stdout_text ++ ++ def test_ipa_migrate_check_service_status(self): ++ """ ++ This testcase checks that ipactl and sssd ++ services are running post ipa-migrate tool ++ successful runs completed ++ """ ++ cmd1 = self.replicas[0].run_command([ ++ "ipactl", "status" ++ ]) ++ assert cmd1.returncode == 0 ++ cmd2 = self.replicas[0].run_command([ ++ "systemctl", "status", "sssd" ++ ]) ++ assert cmd2.returncode == 0 ++ ++ def test_custom_idrange_is_migrated(self): ++ """ ++ This testcase checks that custom idrange is migrated ++ from remote server to local server in production ++ mode. ++ """ ++ range_name = "testrange" ++ CMD_OUTPUT = ( ++ "---------------\n" ++ "1 range matched\n" ++ "---------------\n" ++ " Range name: testrange\n" ++ " First Posix ID of the range: 10000\n" ++ " Number of IDs in the range: 10000\n" ++ " First RID of the corresponding RID range: 300000\n" ++ " First RID of the secondary RID range: 400000\n" ++ " Range type: local domain range\n" ++ "----------------------------\n" ++ "Number of entries returned 1\n" ++ "----------------------------\n" ++ ) ++ cmd = self.replicas[0].run_command( ++ ["ipa", "idrange-find", range_name]) ++ assert CMD_OUTPUT in cmd.stdout_text ++ ++ def test_automountlocation_is_migrated(self): ++ """ ++ This testcase checks that automount location/maps ++ and keys are migrated. ++ """ ++ base_dn = str(self.master.domain.basedn) ++ automount_cn = "automount" ++ loc_name = "baltimore" ++ auto_map_name = "auto.share" ++ DEBUG_LOG = ( ++ "Added entry: cn={},cn={},{}\n" ++ ).format(loc_name, automount_cn, base_dn) ++ CMD1_OUTPUT = ( ++ " Location: baltimore\n" ++ ) ++ CMD2_OUTPUT = ( ++ " Map: auto.share\n" ++ ) ++ CMD3_OUTPUT = ( ++ "-----------------------\n" ++ "1 automount key matched\n" ++ "-----------------------\n" ++ " Key: sub\n" ++ " Mount information: -fstype=autofs ldap:auto.man\n" ++ ) ++ cmd1 = self.replicas[0].run_command( ++ ["ipa", "automountlocation-show", loc_name]) ++ cmd2 = self.replicas[0].run_command( ++ ["ipa", "automountmap-find", loc_name]) ++ cmd3 = self.replicas[0].run_command( ++ ["ipa", "automountkey-find", loc_name, auto_map_name] ++ ) ++ install_msg = self.replicas[0].get_file_contents( ++ paths.IPA_MIGRATE_LOG, encoding="utf-8" ++ ) ++ assert CMD1_OUTPUT in cmd1.stdout_text ++ assert CMD2_OUTPUT in cmd2.stdout_text ++ assert CMD3_OUTPUT in cmd3.stdout_text ++ assert DEBUG_LOG in install_msg ++ ++ ++class TestIPAMigrationWithADtrust(IntegrationTest): ++ """ ++ Test for ipa-migrate tool with IPA Master having trust setup ++ with Windows AD. ++ """ ++ topology = "line" ++ num_ad_domains = 1 ++ num_replicas = 1 ++ ++ @classmethod ++ def install(cls, mh): ++ tasks.install_master( ++ cls.master, setup_dns=True, extra_args=['--no-dnssec-validation'] ++ ) ++ cls.ad = cls.ads[0] ++ cls.ad_domain = cls.ad.domain.name ++ tasks.install_adtrust(cls.master) ++ tasks.configure_dns_for_trust(cls.master, cls.ad) ++ tasks.establish_trust_with_ad(cls.master, cls.ad.domain.name) ++ ++ def test_install_local_server(self): ++ """ ++ This test installs local IPA Server() i.e new IPA server with ++ the same realm and domain name that will receive the migration data. ++ """ ++ tasks.install_master( ++ self.replicas[0], setup_dns=True, ++ extra_args=['--no-dnssec-validation'] ++ ) ++ tasks.install_adtrust(self.replicas[0]) ++ ++ def test_check_ad_attributes_migrate_prod_mode(self): ++ """ ++ This test checks that IPA-AD trust related attributes ++ are migrated to local server. ++ """ ++ result = run_migrate( ++ self.replicas[0], ++ "prod-mode", ++ self.master.hostname, ++ "cn=Directory Manager", ++ self.master.config.admin_password, ++ extra_args=['-n'] ++ ) ++ assert result.returncode == 0 ++ trust1 = self.master.run_command( ++ ['ipa', 'trust-show', self.ad_domain] ++ ).stdout_text ++ trust2 = self.replicas[0].run_command( ++ ['ipa', 'trust-show', self.ad_domain]).stdout_text ++ assert trust1 == trust2 ++ ++ def test_check_domain_sid_is_migrated(self): ++ """ ++ This testcase checks that domain sid is ++ migrated from a remote server having trust with AD ++ to local server and is displayed in the ++ ipa trustconfig-show command ++ """ ++ regexp = (r'Security Identifier: (.*)$') ++ cmd1 = self.master.run_command(["ipa", "trustconfig-show"]) ++ sid1 = re.findall(regexp, cmd1.stdout_text, re.MULTILINE) ++ cmd2 = self.replicas[0].run_command( ++ ["ipa", "trustconfig-show"] ++ ) ++ sid2 = re.findall(regexp, cmd2.stdout_text, re.MULTILINE) ++ assert sid1 == sid2 ++ ++ def test_check_ad_idrange_is_migrated(self): ++ """ ++ This testcase checks AD idrange is migrated ++ from remote IPA server having trust with AD ++ to local IPA server ++ """ ++ ad_domain_name = self.ad.domain.name.upper() ++ cmd1 = self.master.run_command( ++ ["ipa", "idrange-show", ad_domain_name + "_id_range"] ++ ) ++ cmd2 = self.replicas[0].run_command( ++ ["ipa", "idrange-show", ad_domain_name + "_id_range"] ++ ) ++ assert cmd1.stdout_text == cmd2.stdout_text +-- +2.47.0 + diff --git a/0031-Fix-Organization-field-in-Okta-not-required.patch b/0031-Fix-Organization-field-in-Okta-not-required.patch new file mode 100644 index 0000000..10f6abb --- /dev/null +++ b/0031-Fix-Organization-field-in-Okta-not-required.patch @@ -0,0 +1,34 @@ +From c64c098e1d0ae492499caa83a1b73532da511f84 Mon Sep 17 00:00:00 2001 +From: Carla Martinez +Date: Tue, 29 Oct 2024 15:23:55 +0100 +Subject: [PATCH] Fix: 'Organization' field in Okta not required + +Although the 'Organization' field is not required +when using the Okta template, the WebUI requires it +in order to create a new IDP. If this is not provided, +an error is shown. + +Fixes: https://pagure.io/freeipa/issue/9687 +Signed-off-by: Carla Martinez +Reviewed-By: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +--- + install/ui/src/freeipa/idp.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/install/ui/src/freeipa/idp.js b/install/ui/src/freeipa/idp.js +index ada09c0754f5a51575831e127deb81d1f27f44d1..04daad591a8e94ea9b8c146c12e0c84aaad6cee4 100644 +--- a/install/ui/src/freeipa/idp.js ++++ b/install/ui/src/freeipa/idp.js +@@ -41,7 +41,7 @@ idp.templates = [ + fields: ['ipaidporg']}, + { value: 'okta', + label: text.get('@i18n:objects.idp.template_okta'), +- fields: ['ipaidporg', 'ipaidpbaseurl']} ++ fields: ['ipaidpbaseurl']} + ]; + + +-- +2.47.0 + diff --git a/0032-Use-OpenSSL-provider-with-BIND-for-Fedora-41-and-RHE.patch b/0032-Use-OpenSSL-provider-with-BIND-for-Fedora-41-and-RHE.patch new file mode 100644 index 0000000..9a4163e --- /dev/null +++ b/0032-Use-OpenSSL-provider-with-BIND-for-Fedora-41-and-RHE.patch @@ -0,0 +1,363 @@ +From ace726cb83320d7fcb051751591817fd419a8f6b Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 6 Nov 2024 09:59:23 +0200 +Subject: [PATCH] Use OpenSSL provider with BIND for Fedora 41+ and RHEL10+ + +OpenSSL Engine API is deprecated and ability to compile against it is +removed in RHEL10. OpenSSL provider API is the future. + +Fedora 41+ also defaults to OpenSSL provider. With pkcs11-provider, the +same PKCS#11 modules can be loaded transparently like with OpenSSL +engines. Thus, we can update configuration to use the provider API. + +TODO: + - dnssec-keyfromlabel does not work without engine, needs backport from + bind 9.20 + +Fixes: https://pagure.io/freeipa/issue/9696 + +Signed-off-by: Alexander Bokovoy +--- + freeipa.spec.in | 12 +++- + install/share/Makefile.am | 2 + + .../share/bind.openssl.provider.cnf.template | 19 +++++++ + .../bind.openssl.provider.crp.cnf.template | 25 +++++++++ + ipaplatform/base/constants.py | 1 + + ipaplatform/fedora/constants.py | 9 ++- + ipaplatform/rhel/constants.py | 7 ++- + ipaserver/dnssec/bindmgr.py | 21 ++++--- + ipaserver/install/dnskeysyncinstance.py | 55 +++++++++++++++---- + ipaserver/install/server/upgrade.py | 12 ++-- + 10 files changed, 136 insertions(+), 27 deletions(-) + create mode 100644 install/share/bind.openssl.provider.cnf.template + create mode 100644 install/share/bind.openssl.provider.crp.cnf.template + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 72d7013a6c49873f4a59734c684c6c5510e669d0..3f6b133eee4ec40193b618882ad0813971beb5ec 100755 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -158,12 +158,20 @@ + + # BIND employs 'pkcs11' OpenSSL engine instead of native PKCS11 + # Fedora 31+ uses OpenSSL engine, as well as Fedora ELN (RHEL9) +-%if 0%{?fedora} || 0%{?rhel} >= 9 ++# Howevever, Fedora 40+ and RHEL10+ use OpenSSL provider ++%if 0%{?fedora} < 40 || 0%{?rhel} == 9 + %global openssl_pkcs11_version 0.4.10-6 ++ %global openssl_pkcs11_name openssl-pkcs11 + %global softhsm_version 2.5.0-4 ++%else ++%if 0%{?fedora} >= 40 || 0%{?rhel} >= 10 ++ %global openssl_pkcs11_version 0.3 ++ %global openssl_pkcs11_name pkcs11-provider ++ %global softhsm_version 2.6.1 + %else + %global with_bind_pkcs11 1 + %endif ++%endif + + %if 0%{?rhel} == 8 + # Make sure to use PKI versions that work with 389-ds fix for https://github.com/389ds/389-ds-base/issues/4609 +@@ -623,7 +631,7 @@ Requires: bind-dnssec-utils >= %{bind_version} + Requires: bind-pkcs11 >= %{bind_version} + %else + Requires: softhsm >= %{softhsm_version} +-Requires: openssl-pkcs11 >= %{openssl_pkcs11_version} ++Requires: %{openssl_pkcs11_name} >= %{openssl_pkcs11_version} + %endif + # See https://bugzilla.redhat.com/show_bug.cgi?id=1825812 + # RHEL 8.3+ and Fedora 32+ have 2.1 +diff --git a/install/share/Makefile.am b/install/share/Makefile.am +index 24664ca3bacb01fa4c57e9d7a5ea4ab48cfbdd90..0adebf8a3b0e01dbf62fe4b86190e60a3fbfea3b 100644 +--- a/install/share/Makefile.am ++++ b/install/share/Makefile.am +@@ -50,6 +50,8 @@ dist_app_DATA = \ + bind.named.conf.template \ + bind.openssl.cnf.template \ + bind.openssl.cryptopolicy.cnf.template \ ++ bind.openssl.provider.cnf.template \ ++ bind.openssl.provider.crp.cnf.template \ + certmap.conf.template \ + kdc.conf.template \ + kdc_extensions.template \ +diff --git a/install/share/bind.openssl.provider.cnf.template b/install/share/bind.openssl.provider.cnf.template +new file mode 100644 +index 0000000000000000000000000000000000000000..1bd5599cd32f9601416cbaca815dc73fca22b560 +--- /dev/null ++++ b/install/share/bind.openssl.provider.cnf.template +@@ -0,0 +1,19 @@ ++# OpenSSL configuration file ++# File generated by IPA instalation ++openssl_conf = openssl_init ++ ++[openssl_init] ++providers = provider_section ++ ++[provider_sect] ++default = default_sect ++pkcs11 = pkcs11_bind_sect ++ ++[default_sect] ++activate = 1 ++ ++[pkcs11_bind_sect] ++pkcs11-module-path = $SOFTHSM_MODULE ++pkcs11-module-token-pin = file:$SOFTHSM_PIN ++activate = 1 ++ +diff --git a/install/share/bind.openssl.provider.crp.cnf.template b/install/share/bind.openssl.provider.crp.cnf.template +new file mode 100644 +index 0000000000000000000000000000000000000000..b52175e8f9971fa1a25a6c1c7a7121b2fc4c8c36 +--- /dev/null ++++ b/install/share/bind.openssl.provider.crp.cnf.template +@@ -0,0 +1,25 @@ ++# OpenSSL configuration file ++# File generated by IPA instalation ++openssl_conf = openssl_init ++ ++[openssl_init] ++ssl_conf = ssl_configuration ++providers = provider_sect ++ ++[ssl_configuration] ++system_default = crypto_policy ++ ++[crypto_policy] ++.include $CRYPTO_POLICY_FILE ++ ++[provider_sect] ++default = default_sect ++pkcs11 = pkcs11_bind_sect ++ ++[default_sect] ++activate = 1 ++ ++[pkcs11_bind_sect] ++pkcs11-module-path = $SOFTHSM_MODULE ++pkcs11-module-token-pin = file:$SOFTHSM_PIN ++activate = 1 +diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py +index 1689efe52466f00fd8b014f720e1d21ebdbf2504..3f607ecbf961fbd78d78e05bcc1af3cd15a549d5 100644 +--- a/ipaplatform/base/constants.py ++++ b/ipaplatform/base/constants.py +@@ -120,6 +120,7 @@ class BaseConstantsNamespace: + NAMED_DATA_DIR = "data/" + NAMED_OPTIONS_VAR = "OPTIONS" + NAMED_OPENSSL_ENGINE = None ++ NAMED_OPENSSL_PROVIDER = None + NAMED_ZONE_COMMENT = "" + PKI_USER = User("pkiuser") + PKI_GROUP = Group("pkiuser") +diff --git a/ipaplatform/fedora/constants.py b/ipaplatform/fedora/constants.py +index 896e6f60737a904b06ac5fba6c1d1711577c79ec..78a53db28755d5394441ed6d5350648c80de54df 100644 +--- a/ipaplatform/fedora/constants.py ++++ b/ipaplatform/fedora/constants.py +@@ -19,6 +19,10 @@ from ipaplatform.osinfo import osinfo + # Fedora 29 has both + HAS_NFS_CONF = osinfo.version_number >= (30,) + ++# Fedora 40 and later deprecated OpenSSL engine and recommend using OpenSSL ++# provider API. ++HAS_OPENSSL_PROVIDER = osinfo.version_number >= (40,) ++ + + __all__ = ("constants", "User", "Group") + +@@ -32,6 +36,9 @@ class FedoraConstantsNamespace(RedHatConstantsNamespace): + if HAS_NFS_CONF: + SECURE_NFS_VAR = None + +- NAMED_OPENSSL_ENGINE = "pkcs11" ++ if HAS_OPENSSL_PROVIDER: ++ NAMED_OPENSSL_PROVIDER = True ++ else: ++ NAMED_OPENSSL_ENGINE = "pkcs11" + + constants = FedoraConstantsNamespace() +diff --git a/ipaplatform/rhel/constants.py b/ipaplatform/rhel/constants.py +index bc8c65a5d35af9afd27bc728768e49cd937e79a5..f4b50352190811db9dc780e3cec9d02cc0cab354 100644 +--- a/ipaplatform/rhel/constants.py ++++ b/ipaplatform/rhel/constants.py +@@ -18,8 +18,11 @@ from ipaplatform.osinfo import osinfo + # RHEL 8 uses /etc/nfs.conf + HAS_NFS_CONF = osinfo.version_number >= (8,) + # RHEL 9 uses pkcs11 as openssl engine +-HAS_PKCS11_OPENSSL_ENGINE = osinfo.version_number >= (9,) ++HAS_PKCS11_OPENSSL_ENGINE = osinfo.version_number == (9,) + ++# RHEL 10 and later deprecated OpenSSL engine and recommend using OpenSSL ++# provider API. ++HAS_OPENSSL_PROVIDER = osinfo.version_number >= (10,) + + __all__ = ("constants", "User", "Group") + +@@ -31,5 +34,7 @@ class RHELConstantsNamespace(RedHatConstantsNamespace): + SECURE_NFS_VAR = None + if HAS_PKCS11_OPENSSL_ENGINE: + NAMED_OPENSSL_ENGINE = "pkcs11" ++ if HAS_OPENSSL_PROVIDER: ++ NAMED_OPENSSL_PROVIDER = True + + constants = RHELConstantsNamespace() +diff --git a/ipaserver/dnssec/bindmgr.py b/ipaserver/dnssec/bindmgr.py +index 0c79cc03d404f0fb54bc3c6ab591206127c5870c..aeb8b919c64361fd8175366827fecba9705af3c3 100644 +--- a/ipaserver/dnssec/bindmgr.py ++++ b/ipaserver/dnssec/bindmgr.py +@@ -121,17 +121,24 @@ class BINDMgr: + assert attrs.get('idnsseckeyzone', [b'FALSE'])[0] == b'TRUE', \ + b'object %s is not a DNS zone key' % attrs['dn'] + +- uri = b"%s;pin-source=%s" % ( +- attrs['idnsSecKeyRef'][0], +- paths.DNSSEC_SOFTHSM_PIN.encode('utf-8') +- ) ++ uri = None ++ if platformconstants.NAMED_OPENSSL_ENGINE is not None: ++ uri = "%s;pin-source=%s" % ( ++ attrs['idnsSecKeyRef'][0], ++ paths.DNSSEC_SOFTHSM_PIN.encode('utf-8') ++ ) ++ elif platformconstants.NAMED_OPENSSL_PROVIDER is not None: ++ uri = "%s;token=%s" % ( ++ attrs['idnsSecKeyRef'][0], ++ ipalib.constants.SOFTHSM_DNSSEC_TOKEN_LABEL.encode('utf-8') ++ ) + cmd = [ + paths.DNSSEC_KEYFROMLABEL, +- '-E', 'pkcs11', + '-K', workdir, +- '-a', attrs['idnsSecAlgorithm'][0], +- '-l', uri ++ '-a', attrs['idnsSecAlgorithm'][0].encode('utf-8'), + ] ++ if uri is not None: ++ cmd.extend(['-l', uri]) + cmd.extend(self.dates2params(attrs)) + if attrs.get('idnsSecKeySep', [b'FALSE'])[0].upper() == b'TRUE': + cmd.extend(['-f', 'KSK']) +diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py +index 36524655265130fca910eceb63fd4793ccc60d48..1979a472dd882a70cb0a41d782689debc66017a9 100644 +--- a/ipaserver/install/dnskeysyncinstance.py ++++ b/ipaserver/install/dnskeysyncinstance.py +@@ -155,21 +155,36 @@ class DNSKeySyncInstance(service.Service): + return False + + def setup_named_openssl_conf(self): ++ opensslcnf_tmpl = None ++ conf_file_dict = { ++ 'CRYPTO_POLICY_FILE': paths.CRYPTO_POLICY_OPENSSLCNF_FILE, ++ 'SOFTHSM_MODULE': paths.LIBSOFTHSM2_SO, ++ 'SOFTHSM_PIN': paths.DNSSEC_SOFTHSM_PIN, ++ } + if constants.NAMED_OPENSSL_ENGINE is not None: +- logger.debug("Setup OpenSSL config for BIND") +- # setup OpenSSL config for BIND, +- # this one is needed because FreeIPA installation +- # disables p11-kit-proxy PKCS11 module +- conf_file_dict = { +- 'OPENSSL_ENGINE': constants.NAMED_OPENSSL_ENGINE, +- 'SOFTHSM_MODULE': paths.LIBSOFTHSM2_SO, +- 'CRYPTO_POLICY_FILE': paths.CRYPTO_POLICY_OPENSSLCNF_FILE, +- } ++ # Traditional configuration using OpenSSL engine API ++ # requires openssl-pkcs11 engine to load PKCS#11 token ++ # provided by SoftHSMv2 ++ conf_file_dict['OPENSSL_ENGINE'] = constants.NAMED_OPENSSL_ENGINE + if paths.CRYPTO_POLICY_OPENSSLCNF_FILE is None: + opensslcnf_tmpl = "bind.openssl.cnf.template" + else: + opensslcnf_tmpl = "bind.openssl.cryptopolicy.cnf.template" ++ elif constants.NAMED_OPENSSL_PROVIDER is not None: ++ # OpenSSL provider API is preferred and requires ++ # pkcs11-provider to load PKCS#11 token provided by SoftHSMv2 ++ if paths.CRYPTO_POLICY_OPENSSLCNF_FILE is None: ++ opensslcnf_tmpl = "bind.openssl.provider.cnf.template" ++ else: ++ opensslcnf_tmpl = "bind.openssl.provider.crp.cnf.template" ++ else: ++ conf_file_dict = None + ++ if opensslcnf_tmpl is not None and conf_file_dict is not None: ++ logger.debug("Setup OpenSSL config for BIND") ++ # setup OpenSSL config for BIND, ++ # this one is needed because FreeIPA installation ++ # disables p11-kit-proxy PKCS11 module + named_openssl_txt = ipautil.template_file( + os.path.join(paths.USR_SHARE_IPA_DIR, opensslcnf_tmpl), + conf_file_dict +@@ -189,7 +204,8 @@ class DNSKeySyncInstance(service.Service): + 'SOFTHSM2_CONF', paths.DNSSEC_SOFTHSM2_CONF, + quotes=False, separator='=') + +- if constants.NAMED_OPENSSL_ENGINE is not None: ++ if any([constants.NAMED_OPENSSL_ENGINE is not None, ++ constants.NAMED_OPENSSL_PROVIDER is not None]): + directivesetter.set_directive( + sysconfig, + 'OPENSSL_CONF', paths.DNSSEC_OPENSSL_CONF, +@@ -200,9 +216,23 @@ class DNSKeySyncInstance(service.Service): + constants.NAMED_OPTIONS_VAR, + separator="=" + ) or '' +- if not self._are_named_options_configured(options): ++ new_options = None ++ if all([constants.NAMED_OPENSSL_ENGINE is not None, ++ not self._are_named_options_configured(options)]): + engine_cmd = "-E {}".format(constants.NAMED_OPENSSL_ENGINE) + new_options = ' '.join([options, engine_cmd]) ++ # Remove '-E pkcs11' from the options in the OpenSSL provider case ++ if all([constants.NAMED_OPENSSL_ENGINE is None, ++ self._are_named_options_configured(options)]): ++ lst_options = options.split() ++ try: ++ idx = lst_options.index('-E') ++ lst_options.pop(idx) ++ lst_options.pop(idx) ++ new_options = ' '.join(lst_options) ++ except ValueError: ++ pass ++ if new_options is not None: + directivesetter.set_directive( + sysconfig, + constants.NAMED_OPTIONS_VAR, new_options, +@@ -216,7 +246,8 @@ class DNSKeySyncInstance(service.Service): + 'SOFTHSM2_CONF', paths.DNSSEC_SOFTHSM2_CONF, + quotes=False, separator='=') + +- if constants.NAMED_OPENSSL_ENGINE is not None: ++ if any([constants.NAMED_OPENSSL_ENGINE is not None, ++ constants.NAMED_OPENSSL_PROVIDER is not None]): + directivesetter.set_directive( + sysconfig, + 'OPENSSL_CONF', paths.DNSSEC_OPENSSL_CONF, +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index fb71df81a6bf8ecbb1631ca8f0a5fe55cc222782..e2aabb2845602aacda1ca3289b7d7e338bd2dba3 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -549,15 +549,19 @@ def ca_initialize_hsm_state(ca): + + def dnssec_set_openssl_engine(dnskeysyncd): + """ +- Setup OpenSSL engine for BIND ++ Setup OpenSSL engine or provider for BIND + """ +- if constants.NAMED_OPENSSL_ENGINE is None: ++ if all([constants.NAMED_OPENSSL_ENGINE is None, ++ constants.NAMED_OPENSSL_PROVIDER is None]): + return False + +- if sysupgrade.get_upgrade_state('dns', 'openssl_engine'): ++ # Nothing to do if we are using OpenSSL engine already and not on the OS ++ # that requires OpenSSL provider instead. ++ if all([sysupgrade.get_upgrade_state('dns', 'openssl_engine'), ++ constants.NAMED_OPENSSL_PROVIDER is None]): + return False + +- logger.info('[Set OpenSSL engine for BIND]') ++ logger.info('[Set OpenSSL engine or provider for BIND]') + dnskeysyncd.setup_named_openssl_conf() + dnskeysyncd.setup_named_sysconfig() + dnskeysyncd.setup_ipa_dnskeysyncd_sysconfig() +-- +2.47.0 + diff --git a/freeipa.spec b/freeipa.spec index 3feeb87..43e3517 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -139,12 +139,10 @@ # BIND employs 'pkcs11' OpenSSL engine instead of native PKCS11 # Fedora 31+ uses OpenSSL engine, as well as Fedora ELN (RHEL9) -%if 0%{?fedora} || 0%{?rhel} >= 9 - %global openssl_pkcs11_version 0.4.10-6 - %global softhsm_version 2.5.0-4 -%else - %global with_bind_pkcs11 1 -%endif +# Howevever, Fedora 40+ and RHEL10+ use OpenSSL provider +%global openssl_pkcs11_version 0.3 +%global openssl_pkcs11_name pkcs11-provider +%global softhsm_version 2.6.1 %if 0%{?rhel} == 8 # Make sure to use PKI versions that work with 389-ds fix for https://github.com/389ds/389-ds-base/issues/4609 @@ -205,7 +203,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 6%{?rc_version:.%rc_version}%{?dist} +Release: 7%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -261,6 +259,13 @@ Patch0022: 0022-ipatests-Test-for-ipa-hbac-rule-duplication.patch Patch0023: 0023-ipatests-refactor-password-file-handling-in-TestHSMI.patch Patch0024: 0024-ipatests-2FA-test-cases.patch Patch0025: 0025-Small-fixup-to-determine-which-ACME-uninstaller-to-u.patch +Patch0026: 0026-Fix-a-couple-of-instances-of-the-no-break-control-ch.patch +Patch0027: 0027-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch +Patch0028: 0028-ipa-migrate-should-migrate-dns-forward-zones.patch +Patch0029: 0029-vault-handle-pyca-InternalError-exception-for-PKCS-1.patch +Patch0030: 0030-ipatests-Tests-for-ipa-migrate-tool.patch +Patch0031: 0031-Fix-Organization-field-in-Okta-not-required.patch +Patch0032: 0032-Use-OpenSSL-provider-with-BIND-for-Fedora-41-and-RHE.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -620,12 +625,8 @@ Requires: bind-utils >= %{bind_version} # bind-dnssec-utils is required by the OpenDNSSec integration # https://pagure.io/freeipa/issue/9026 Requires: bind-dnssec-utils >= %{bind_version} -%if %{with bind_pkcs11} -Requires: bind-pkcs11 >= %{bind_version} -%else Requires: softhsm >= %{softhsm_version} -Requires: openssl-pkcs11 >= %{openssl_pkcs11_version} -%endif +Requires: %{openssl_pkcs11_name} >= %{openssl_pkcs11_version} # See https://bugzilla.redhat.com/show_bug.cgi?id=1825812 # RHEL 8.3+ and Fedora 32+ have 2.1 Requires: opendnssec >= 2.1.6-5 @@ -1883,6 +1884,14 @@ fi %endif %changelog +* Fri Nov 08 2024 Florence Blanc-Renaud - 4.12.2-7 +- Resolves: RHEL-66599 vault-add fails in FIPS mode +- Resolves: RHEL-66598 ipa-migrate should also migrate DNS forward zones +- Resolves: RHEL-66597 ipa-migrate in stage mode fails with TypeError: 'NoneType' object is not iterable +- Resolves: RHEL-66595 Sentences truncated in man pages +- Resolves: RHEL-66592 IDP configuration in the IdM WebUI shows Organization is required +- Resolves: RHEL-65650 ipa-server-install with setup-dns fails 'job for ipa.service failed because the control process exited with error code' + * Thu Oct 31 2024 Florence Blanc-Renaud - 4.12.2-6 - Resolves: RHEL-64018 Bump release for October 2024 mass rebuild