diff --git a/0022-UnsafeIPAddress-pass-flag-0-to-IPNetwork.patch b/0022-UnsafeIPAddress-pass-flag-0-to-IPNetwork.patch new file mode 100644 index 0000000..d1f15f2 --- /dev/null +++ b/0022-UnsafeIPAddress-pass-flag-0-to-IPNetwork.patch @@ -0,0 +1,34 @@ +From a9e653ca36a0829ae59cd204e7388d7a6c91e082 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 13 Sep 2024 09:58:36 +0200 +Subject: [PATCH] UnsafeIPAddress: pass flag=0 to IPNetwork + +When parsing a string, the constructor tries to parse the value +as an IP Address first, or falls back to an IPNetwork with the +flags INET_PTON. + +Use the flag 0 instead for an IPNetwork. + +Fixes: https://pagure.io/freeipa/issue/9645 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +--- + ipapython/ipautil.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 3e98bfd6a66f24933e7e4de8efb79f4f5bf8bd0e..c237d59fb4b8be4187fb0efb04b097ff4df6c182 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -119,7 +119,7 @@ class UnsafeIPAddress(netaddr.IPAddress): + if addr.version != 6: + raise + except ValueError: +- self._net = netaddr.IPNetwork(addr, flags=self.netaddr_ip_flags) ++ self._net = netaddr.IPNetwork(addr, flags=0) + addr = self._net.ip + super(UnsafeIPAddress, self).__init__(addr, + flags=self.netaddr_ip_flags) +-- +2.47.0 + diff --git a/0023-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch b/0023-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch new file mode 100644 index 0000000..2ed299e --- /dev/null +++ b/0023-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/0024-ipa-migrate-should-migrate-dns-forward-zones.patch b/0024-ipa-migrate-should-migrate-dns-forward-zones.patch new file mode 100644 index 0000000..ac75a1c --- /dev/null +++ b/0024-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/0025-ipatests-Tests-for-ipa-migrate-tool.patch b/0025-ipatests-Tests-for-ipa-migrate-tool.patch new file mode 100644 index 0000000..3b3c85f --- /dev/null +++ b/0025-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/0026-Fix-Organization-field-in-Okta-not-required.patch b/0026-Fix-Organization-field-in-Okta-not-required.patch new file mode 100644 index 0000000..10f6abb --- /dev/null +++ b/0026-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/0027-ipatests-install-master-with-allow-zone-overlap.patch b/0027-ipatests-install-master-with-allow-zone-overlap.patch new file mode 100644 index 0000000..04aabe6 --- /dev/null +++ b/0027-ipatests-install-master-with-allow-zone-overlap.patch @@ -0,0 +1,42 @@ +From baa9fc3e3e2f6b39db5ec465c92dc597cd5399b9 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 12 Nov 2024 16:44:46 +0100 +Subject: [PATCH] ipatests: install master with allow-zone-overlap + +In the IPA to IPA migration tests, install the destination master +with --setup-dns --allow-zone-overlap to allow installation +even if the zone is already served by the source master. + +Fixes: https://pagure.io/freeipa/issue/9697 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Sudhir Menon +--- + ipatests/test_integration/test_ipa_ipa_migration.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py +index d852ca63a6b3a7e7118d66ce1cd9bb98e56f1a73..0c637a0141d95f34f951c60a9648adf8e87eaa63 100644 +--- a/ipatests/test_integration/test_ipa_ipa_migration.py ++++ b/ipatests/test_integration/test_ipa_ipa_migration.py +@@ -345,7 +345,8 @@ class MigrationTest(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) ++ tasks.install_master(cls.replicas[0], setup_dns=True, setup_kra=True, ++ extra_args=['--allow-zone-overlap']) + + + class TestIPAMigrateCLIOptions(MigrationTest): +@@ -1211,7 +1212,7 @@ class TestIPAMigrationWithADtrust(IntegrationTest): + """ + tasks.install_master( + self.replicas[0], setup_dns=True, +- extra_args=['--no-dnssec-validation'] ++ extra_args=['--no-dnssec-validation', '--allow-zone-overlap'] + ) + tasks.install_adtrust(self.replicas[0]) + +-- +2.47.0 + diff --git a/freeipa.spec b/freeipa.spec index c35f853..0ac1229 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -224,7 +224,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 4%{?rc_version:.%rc_version}%{?dist} +Release: 5%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -269,6 +269,12 @@ Patch0018: 0018-ipatests-Test-for-ipa-hbac-rule-duplication.patch Patch0019: 0019-ipatests-refactor-password-file-handling-in-TestHSMI.patch Patch0020: 0020-ipatests-2FA-test-cases.patch Patch0021: 0021-Small-fixup-to-determine-which-ACME-uninstaller-to-u.patch +Patch0022: 0022-UnsafeIPAddress-pass-flag-0-to-IPNetwork.patch +Patch0023: 0023-ipa-migrate-dryrun-write-updates-crashes-when-removi.patch +Patch0024: 0024-ipa-migrate-should-migrate-dns-forward-zones.patch +Patch0025: 0025-ipatests-Tests-for-ipa-migrate-tool.patch +Patch0026: 0026-Fix-Organization-field-in-Okta-not-required.patch +Patch0027: 0027-ipatests-install-master-with-allow-zone-overlap.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -1884,6 +1890,13 @@ fi %endif %changelog +* Wed Nov 20 2024 Florence Blanc-Renaud - 4.12.2-5 +- Resolves: RHEL-67414 ipa dns-zone --allow-query '!198.18.2.0/24;any;' fails with Unrecognized IPAddress flags +- Resolves: RHEL-67410 ipa-migrate should also migrate DNS forward zones +- Resolves: RHEL-67409 ipa-migrate in stage mode fails with TypeError: 'NoneType' object is not iterable +- Resolves: RHEL-66964 Include latest fixes in python3-ipatests packages +- Resolves: RHEL-64135 IDP configuration in the IdM WebUI shows Organization is required + * Mon Nov 4 2024 Florence Blanc-Renaud - 4.12.2-4 - Bump release for rebuild