diff --git a/0001-webuitests-close-notification-which-hides-Add-button.patch b/0001-webuitests-close-notification-which-hides-Add-button.patch new file mode 100644 index 0000000..f554010 --- /dev/null +++ b/0001-webuitests-close-notification-which-hides-Add-button.patch @@ -0,0 +1,35 @@ +From 4f6ebb5fdf6d2514d4683247e5d1bfc6022a500e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 6 Jun 2023 09:04:48 +0200 +Subject: [PATCH] webuitests: close notification which hides Add button + +The webui test test_service.py::test_service::test_arbitrary_certificates +randomly fails. +The test is creating a new service then navigates to the Service page +and clicks on the Add Certificate button. +The notification area may still be present and hide the button, with +the message "Service successfully added". +Close all notifications before navigating to the Service page. + +Fixes: https://pagure.io/freeipa/issue/9389 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Michal Polovka +--- + ipatests/test_webui/test_service.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py +index f1d9a9d624bc587634e03a86050627a648feb26d..e2976d73acd1f574f1164828be9d8e871b737d7f 100644 +--- a/ipatests/test_webui/test_service.py ++++ b/ipatests/test_webui/test_service.py +@@ -296,6 +296,7 @@ class test_service(sevice_tasks): + cert_widget_sel = "div.certificate-widget" + + self.add_record(ENTITY, data) ++ self.close_notifications() + self.navigate_to_record(pkey) + + # check whether certificate section is present +-- +2.41.0 + diff --git a/0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch b/0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch new file mode 100644 index 0000000..34d91f6 --- /dev/null +++ b/0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch @@ -0,0 +1,48 @@ +From 8d34f453fb139c4cef055a4963f307a760316a73 Mon Sep 17 00:00:00 2001 +From: Anuja More +Date: Thu, 11 May 2023 12:50:10 +0530 +Subject: [PATCH] ipatests: Check that SSSD_PUBCONF_KRB5_INCLUDE_D_DIR is not + included in krb5.conf + +SSSD already provides a config snippet which includes +SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, and having both breaks Java. +Test checks that krb5.conf does not include +SSSD_PUBCONF_KRB5_INCLUDE_D_DIR. + +Related: https://pagure.io/freeipa/issue/9267 + +Signed-off-by: Anuja More +Reviewed-By: Florence Blanc-Renaud +--- + .../test_integration/test_installation_client.py | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/ipatests/test_integration/test_installation_client.py b/ipatests/test_integration/test_installation_client.py +index 014b0f6ab34dd92c00c0187c2c86b8bfbaa70e81..56e1593bfcfa3eb7f9918fc6f2993d836884ea38 100644 +--- a/ipatests/test_integration/test_installation_client.py ++++ b/ipatests/test_integration/test_installation_client.py +@@ -76,6 +76,21 @@ class TestInstallClient(IntegrationTest): + result = self.clients[0].run_command(['cat', '/etc/ssh/ssh_config']) + assert 'HostKeyAlgorithms' not in result.stdout_text + ++ def test_client_install_with_krb5(self): ++ """Test that SSSD_PUBCONF_KRB5_INCLUDE_D_DIR is not added in krb5.conf ++ ++ SSSD already provides a config snippet which includes ++ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, and having both breaks Java. ++ Test checks that krb5.conf does not include ++ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR. ++ ++ related: https://pagure.io/freeipa/issue/9267 ++ """ ++ krb5_cfg = self.master.get_file_contents(paths.KRB5_CONF) ++ assert 'includedir {dir}'.format( ++ dir=paths.SSSD_PUBCONF_KRB5_INCLUDE_D_DIR ++ ).encode() not in krb5_cfg ++ + + class TestClientInstallBind(IntegrationTest): + """ +-- +2.41.0 + diff --git a/0001-Revert-cert_find-fix-call-with-all.patch b/0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch similarity index 75% rename from 0001-Revert-cert_find-fix-call-with-all.patch rename to 0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch index f81b3b7..9f55246 100644 --- a/0001-Revert-cert_find-fix-call-with-all.patch +++ b/0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch @@ -1,17 +1,20 @@ -From a44fd5a7691d263d670312e0c8e02efd868618c1 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Tue, 6 Jun 2023 17:15:11 +0200 -Subject: [PATCH] Revert "cert_find: fix call with --all" +From 276138087158c6b2ea76b43c754084144e543c0b Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Wed, 7 Jun 2023 11:32:21 -0400 +Subject: [PATCH] Revert "Use the OpenSSL certificate parser in cert-find" -This reverts commit 918b6e011795ba4854d178d18c86ad54f3cf75ab. +This reverts commit 191880bc9f77c3e8a3cecc82e6eea33ab5ad03e4. -Revert "Use the OpenSSL certificate parser in cert-find" +The problem isn't with python-cryptography, it is with the +IPACertificate class which does way more work on a certificate +than is necessary in cert-find. -This reverts commit 50dd79d1a35549034bc281fbdffea4399baed3c7. +Related: https://pagure.io/freeipa/issue/9331 +Reviewed-By: Florence Blanc-Renaud --- freeipa.spec.in | 2 -- - ipaserver/plugins/cert.py | 27 +++------------------------ - 2 files changed, 3 insertions(+), 26 deletions(-) + ipaserver/plugins/cert.py | 26 +++----------------------- + 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index 3e23bbfe9d054a3a9febf468de0bcb4a6e81bb32..bec9780a82fe0d9bc5a50a93bdce8aa7e27a9f30 100755 @@ -34,7 +37,7 @@ index 3e23bbfe9d054a3a9febf468de0bcb4a6e81bb32..bec9780a82fe0d9bc5a50a93bdce8aa7 Requires: python3-requests Requires: python3-six diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 400b1b3cec0aba82e699a4a981516e121f3e0c77..36a0e8cb31b4dbdd9bff09165d1d8aa203936d37 100644 +index 400b1b3cec0aba82e699a4a981516e121f3e0c77..2e32f4ecd50ac92c28bcaffcebe9c2c87557858a 100644 --- a/ipaserver/plugins/cert.py +++ b/ipaserver/plugins/cert.py @@ -30,7 +30,6 @@ import cryptography.x509 @@ -78,7 +81,7 @@ index 400b1b3cec0aba82e699a4a981516e121f3e0c77..36a0e8cb31b4dbdd9bff09165d1d8aa2 ldap = self.api.Backend.ldap2 filters = [] -@@ -1813,21 +1795,18 @@ class cert_find(Search, CertMethod): +@@ -1813,14 +1795,12 @@ class cert_find(Search, CertMethod): ca_enabled = getattr(context, 'ca_enabled') for entry in entries: for attr in ('usercertificate', 'usercertificate;binary'): @@ -95,13 +98,6 @@ index 400b1b3cec0aba82e699a4a981516e121f3e0c77..36a0e8cb31b4dbdd9bff09165d1d8aa2 if not pkey_only and (all or not ca_enabled): # Retrieving certificate details is now deferred # until after all certificates are collected. - # For the case of CA-less we need to keep - # the certificate because getting it again later - # would require unnecessary LDAP searches. -- cert = cert.to_cryptography() - obj['certificate'] = ( - base64.b64encode( - cert.public_bytes(x509.Encoding.DER)) -- -2.40.1 +2.41.0 diff --git a/0004-Revert-cert_find-fix-call-with-all.patch b/0004-Revert-cert_find-fix-call-with-all.patch new file mode 100644 index 0000000..baaa558 --- /dev/null +++ b/0004-Revert-cert_find-fix-call-with-all.patch @@ -0,0 +1,32 @@ +From d83a4b0babdc7beb124d3748b5815ce309739eb7 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 13 Jun 2023 17:01:49 -0400 +Subject: [PATCH] Revert "cert_find: fix call with --all" + +This reverts commit 1f30cc65276a532e7288217f216b72a2b0628c8f. + +The problem isn't with python-cryptography, it is with the +IPACertificate class which does way more work on a certificate +than is necessary in cert-find. + +Related: https://pagure.io/freeipa/issue/9331 +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/plugins/cert.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index 2e32f4ecd50ac92c28bcaffcebe9c2c87557858a..36a0e8cb31b4dbdd9bff09165d1d8aa203936d37 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -1807,7 +1807,6 @@ class cert_find(Search, CertMethod): + # For the case of CA-less we need to keep + # the certificate because getting it again later + # would require unnecessary LDAP searches. +- cert = cert.to_cryptography() + obj['certificate'] = ( + base64.b64encode( + cert.public_bytes(x509.Encoding.DER)) +-- +2.41.0 + diff --git a/0005-Use-the-python-cryptography-parser-directly-in-cert-.patch b/0005-Use-the-python-cryptography-parser-directly-in-cert-.patch new file mode 100644 index 0000000..1293cd0 --- /dev/null +++ b/0005-Use-the-python-cryptography-parser-directly-in-cert-.patch @@ -0,0 +1,115 @@ +From d9aa75459d650e5282a160a3eef09ed175dc5b51 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Wed, 7 Jun 2023 11:44:05 -0400 +Subject: [PATCH] Use the python-cryptography parser directly in cert-find + +cert-find is a rather complex beast because it not only +looks for certificates in the optional CA but within the +IPA LDAP database as well. It has a process to deduplicate +the certificates since any PKI issued certificates will +also be associated with an IPA record. + +In order to obtain the data to deduplicate the certificates +the cert from LDAP must be parser for issuer and serial number. +ipaldap has automation to determine the datatype of an +attribute and will use the ipalib.x509 IPACertificate class to +decode a certificate automatically if you access +entry['usercertificate']. + +The downside is that this is comparatively slow. Here is the +parse time in microseconds: + +cryptography 0.0081 +OpenSSL.crypto 0.2271 +ipalib.x509 2.6814 + +Since only issuer and subject are required there is no need to +make the expensive IPACertificate call. + +The IPACertificate parsing time is fine if you're parsing one +certificate but if the LDAP search returns a lot of certificates, +say in the thousands, then those microseconds add up quickly. +In testing it took ~17 seconds to parse 5k certificates (excluding +transmission overhead, etc). + +cert-find when there are a lot of certificates has been +historically slow. It isn't related to the CA which returns +large sets (well, 5k anyway) in a second or two. It was the +LDAP comparision adding tens of seconds to the runtime. + +When searching with the default sizelimit of 100 the time is +~10s without this patch. With it the time is 1.5s. + +CLI times from before and after searching for all certs: + +original: + +------------------------------- +Number of entries returned 5038 +------------------------------- +real 0m15.507s +user 0m0.828s +sys 0m0.241s + +using cryptography: + +real 0m4.037s +user 0m0.816s +sys 0m0.193s + +Fixes: https://pagure.io/freeipa/issue/9331 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/plugins/cert.py | 3 ++- + ipatests/test_xmlrpc/test_cert_plugin.py | 12 +++++++++++- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index 36a0e8cb31b4dbdd9bff09165d1d8aa203936d37..4fb85069a835d94969c9d05789714345ecc60e2e 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -1795,7 +1795,8 @@ class cert_find(Search, CertMethod): + ca_enabled = getattr(context, 'ca_enabled') + for entry in entries: + for attr in ('usercertificate', 'usercertificate;binary'): +- for cert in entry.get(attr, []): ++ for der in entry.raw.get(attr, []): ++ cert = cryptography.x509.load_der_x509_certificate(der) + cert_key = self._get_cert_key(cert) + try: + obj = result[cert_key] +diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py +index 433cebcd79f792e5c97307c6d599e50855ff4151..583c67fd942a61f42e578cc51a0e456cacf9a5e5 100644 +--- a/ipatests/test_xmlrpc/test_cert_plugin.py ++++ b/ipatests/test_xmlrpc/test_cert_plugin.py +@@ -254,6 +254,16 @@ class test_cert(BaseCert): + result = _emails_are_valid(email_addrs, []) + assert not result + ++ def test_00012_cert_find_all(self): ++ """ ++ Test that cert-find --all returns successfully. ++ ++ We don't know how many we'll get but there should be at least 10 ++ by default. ++ """ ++ res = api.Command['cert_find'](all=True) ++ assert 'count' in res and res['count'] >= 10 ++ + def test_99999_cleanup(self): + """ + Clean up cert test data +@@ -283,7 +293,7 @@ class test_cert_find(XMLRPC_test): + + short = api.env.host.split('.', maxsplit=1)[0] + +- def test_0001_find_all(self): ++ def test_0001_find_all_certs(self): + """ + Search for all certificates. + +-- +2.41.0 + diff --git a/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch b/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch new file mode 100644 index 0000000..407363f --- /dev/null +++ b/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch @@ -0,0 +1,38 @@ +From f25003a730c0e28c22fae5fce607df734b55525c Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 19 Jun 2023 19:01:25 +0200 +Subject: [PATCH] Upgrade: add PKI drop-in file if missing + +During the installation of IPA server, the installer adds a drop-in +file in /etc/systemd/system/pki-tomcatd@pki-tomcat.service.d/ipa.conf +that ensures the CA is reachable before the start command returns. +If the file is missing (for instance because the server was installed +with an old version before this drop-in was created), the upgrade +should add the file. + +Fixes: https://pagure.io/freeipa/issue/9381 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/server/upgrade.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index f8701c8a0d43c7c1c1090e8576976b1c370b0104..8f3d57353605f28103c69cb0a34bf1c16fc4ae19 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1742,6 +1742,10 @@ def upgrade_configuration(): + os.path.join(paths.USR_SHARE_IPA_DIR, + "ipa-kdc-proxy.conf.template")) + if ca.is_configured(): ++ # Ensure that the drop-in file is present ++ if not os.path.isfile(paths.SYSTEMD_PKI_TOMCAT_IPA_CONF): ++ ca.add_ipa_wait() ++ + # Handle upgrade of AJP connector configuration + rewrite = ca.secure_ajp_connector() + if ca.ajp_secret: +-- +2.41.0 + diff --git a/0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch b/0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch new file mode 100644 index 0000000..1e2912d --- /dev/null +++ b/0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch @@ -0,0 +1,53 @@ +From 392e60e3fa0e39a2e364268a21d869a2f3a85905 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 19 Jun 2023 19:04:32 +0200 +Subject: [PATCH] Integration test: add a test for upgrade and PKI drop-in file + +Add an upgrade test with the following scenario: +- remove PKI drop-in file (to simulate an upgrade from an old +version) +- remove caECServerCertWithSCT profile from LDAP +- launch the ipa-server-upgrade command +- check that the upgrade added the file + +Related: https://pagure.io/freeipa/issue/9381 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_upgrade.py | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py +index 9203503cdccf4478f9864bd487e458761e9a2a2f..182e3b5da3c758cc10913ad4eed119b0983fcc23 100644 +--- a/ipatests/test_integration/test_upgrade.py ++++ b/ipatests/test_integration/test_upgrade.py +@@ -455,3 +455,25 @@ class TestUpgrade(IntegrationTest): + assert 'tXTRecord' in location_krb_rec + assert len(location_krb_rec['tXTRecord']) == 1 + assert location_krb_rec['tXTRecord'][0] == f'"{realm}"' ++ ++ def test_pki_dropin_file(self): ++ """Test that upgrade adds the drop-in file if missing ++ ++ Test for ticket 9381 ++ Simulate an update from a version that didn't provide ++ /etc/systemd/system/pki-tomcatd@pki-tomcat.service.d/ipa.conf, ++ remove one of the certificate profiles from LDAP and check that upgrade ++ completes successfully and adds the missing file. ++ When the drop-in file is missing, the upgrade tries to login to ++ PKI in order to migrate the profile and fails because PKI failed to ++ start. ++ """ ++ self.master.run_command(["rm", "-f", paths.SYSTEMD_PKI_TOMCAT_IPA_CONF]) ++ ldif = textwrap.dedent(""" ++ dn: cn=caECServerCertWithSCT,ou=certificateProfiles,ou=ca,o=ipaca ++ changetype: delete ++ """) ++ tasks.ldapmodify_dm(self.master, ldif) ++ self.master.run_command(['ipa-server-upgrade']) ++ assert self.master.transport.file_exists( ++ paths.SYSTEMD_PKI_TOMCAT_IPA_CONF) +-- +2.41.0 + diff --git a/0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch b/0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch new file mode 100644 index 0000000..2877404 --- /dev/null +++ b/0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch @@ -0,0 +1,129 @@ +From f93a6d3ff52247ce5e582816fec689b8901fc984 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 14 Jun 2023 15:12:39 +0200 +Subject: [PATCH] Uninstaller: uninstall PKI before shutting down services + +The uninstaller is stopping all the services before +calling pkidestroy to uninstall the CA. +With PKI 11.4+ this sequence fails as pkidestroy tries +to connect to PKI server in order to unregister from the +security domain. The error interrupts the full completion +of pkidestroy, is logged but doesn't make ipa uninstallation +fail. +The issue is that trying to re-install later on would fail because +pkidestroy did not completely uninstall the CA. + +To avoid this, call pkidestroy before shutting down the services. +Also add an uninstall_check method that restarts IPA if it is +not running, and use pkidestroy --force to make sure that PKI +is uninstalled even if restart failed. + +Fixes: https://pagure.io/freeipa/issue/9330 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/ca.py | 18 ++++++++++++++++++ + ipaserver/install/dogtaginstance.py | 2 +- + ipaserver/install/kra.py | 2 ++ + ipaserver/install/server/install.py | 8 +++++--- + 4 files changed, 26 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py +index be0e732e8ff6966ccc0077d9339f9f0bc66ae6ec..c93ae1fce4c8848d493677eafee7952740e51631 100644 +--- a/ipaserver/install/ca.py ++++ b/ipaserver/install/ca.py +@@ -169,6 +169,24 @@ def print_ca_configuration(options): + + + def uninstall_check(options): ++ """IPA needs to be running so pkidestroy can unregister CA""" ++ ca = cainstance.CAInstance(api.env.realm) ++ if not ca.is_installed(): ++ return ++ ++ result = ipautil.run([paths.IPACTL, 'status'], ++ raiseonerr=False) ++ ++ if result.returncode not in [0, 4]: ++ try: ++ logger.info( ++ "Starting services to unregister CA from security domain") ++ ipautil.run([paths.IPACTL, 'start']) ++ except Exception: ++ logger.info("Re-starting IPA failed, continuing uninstall") ++ ++ ++def uninstall_crl_check(options): + """Check if the host is CRL generation master""" + # Skip the checks if the host is not a CA instance + ca = cainstance.CAInstance(api.env.realm) +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index c2c6b3f49243f096448c178fafd09f429f0f46c8..4967aca01807e58dfcc3157af10b92eff5dba206 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -305,7 +305,7 @@ class DogtagInstance(service.Service): + self.print_msg("Unconfiguring %s" % self.subsystem) + + args = [paths.PKIDESTROY, +- "-i", "pki-tomcat", ++ "-i", "pki-tomcat", "--force", + "-s", self.subsystem] + + # specify --log-file on PKI 11.0.0 or later +diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py +index 857c5165b808baee3f0815e78828fb899eb78a2d..59cbda812a853997752f7d932e0690e3a950aa1f 100644 +--- a/ipaserver/install/kra.py ++++ b/ipaserver/install/kra.py +@@ -132,6 +132,8 @@ def uninstall_check(options): + + if result.returncode not in [0, 4]: + try: ++ logger.info( ++ "Starting services to unregister KRA from security domain") + ipautil.run([paths.IPACTL, 'start']) + except Exception: + logger.info("Re-starting IPA failed, continuing uninstall") +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 4e4076410f1c1af188a0ab3606ef13be39702b7d..ccb958232935de2166f2d4867b626f59d7ba5333 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -1110,6 +1110,7 @@ def uninstall_check(installer): + raise ScriptError("Aborting uninstall operation.") + + kra.uninstall_check(options) ++ ca.uninstall_check(options) + + try: + api.Backend.ldap2.connect(autobind=True) +@@ -1132,7 +1133,7 @@ def uninstall_check(installer): + else: + dns.uninstall_check(options) + +- ca.uninstall_check(options) ++ ca.uninstall_crl_check(options) + + cleanup_dogtag_server_specific_data() + +@@ -1181,6 +1182,9 @@ def uninstall(installer): + # Uninstall the KRA prior to shutting the services down so it + # can un-register with the CA. + kra.uninstall() ++ # Uninstall the CA priori to shutting the services down so it ++ # can unregister from the security domain ++ ca.uninstall() + + print("Shutting down all IPA services") + try: +@@ -1194,8 +1198,6 @@ def uninstall(installer): + + restore_time_sync(sstore, fstore) + +- ca.uninstall() +- + dns.uninstall() + + httpinstance.HTTPInstance(fstore).uninstall() +-- +2.41.0 + diff --git a/0009-Detection-of-PKI-subsystem.patch b/0009-Detection-of-PKI-subsystem.patch new file mode 100644 index 0000000..c85677a --- /dev/null +++ b/0009-Detection-of-PKI-subsystem.patch @@ -0,0 +1,44 @@ +From b9a07b1e97ee4e310b50860103872685da540da4 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 19 Jun 2023 15:40:39 +0200 +Subject: [PATCH] Detection of PKI subsystem + +In order to know if ca/kra is installed locally, the code +is calling pki-server subsystem-show _subsystem_ +and ensures that "Enabled: True" is in the output. + +If a subsystem fails to start, the command returns +"Enabled: False" but it doesn't mean that the subsystem +is not installed, it just means that it is not active +right now. +Same output if the subsystem has been disabled with +pki-server subsystem-disable _subsystem_. + +The correct way to check if a subsystem is installed is to +ensure that subsystem-show does not exit on error and +contains "Enabled: ", whatever the value. + +Related: https://pagure.io/freeipa/issue/9330 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/install/dogtaginstance.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index 4967aca01807e58dfcc3157af10b92eff5dba206..7fdf2e0ed0f3ed99a6672f527d38dda0ce5ef8bb 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -184,7 +184,7 @@ class DogtagInstance(service.Service): + ['pki-server', 'subsystem-show', self.subsystem.lower()], + capture_output=True) + # parse the command output +- return 'Enabled: True' in result.output ++ return 'Enabled: ' in result.output + except ipautil.CalledProcessError: + return False + +-- +2.41.0 + diff --git a/0010-Upgrade-fix-replica-agreement.patch b/0010-Upgrade-fix-replica-agreement.patch new file mode 100644 index 0000000..46dc830 --- /dev/null +++ b/0010-Upgrade-fix-replica-agreement.patch @@ -0,0 +1,164 @@ +From ad77c4c6512f82019d1970d910647761b60aaedb Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 19 Jun 2023 10:36:29 +0200 +Subject: [PATCH] Upgrade: fix replica agreement + +The upgrade checks the replication agreements to ensure that +some attributes are excluded from replication. The agreements +are stored in entries like +cn=serverToreplica,cn=replica,cn=_suffix_,cn=mapping tree,cn=config +but those entries are managed by the replication topology plugin +and should not be updated directly. The consequence is that the update +of the attributes fails and ipa-server-update prints an error message: + +Error caught updating nsDS5ReplicatedAttributeList: Server is unwilling +to perform: Entry and attributes are managed by topology plugin.No direct +modifications allowed. +Error caught updating nsDS5ReplicatedAttributeListTotal: Server is +unwilling to perform: Entry and attributes are managed by topology +plugin.No direct modifications allowed. + +The upgrade continues but the replication is not excluding +passwordgraceusertime. + +Instead of editing the agreements, perform the modifications on +the topology segments. + +Fixes: https://pagure.io/freeipa/issue/9385 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + .../install/plugins/fix_replica_agreements.py | 80 +++++++++---------- + 1 file changed, 38 insertions(+), 42 deletions(-) + +diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py +index c0cdd3eb19c486121f727476360ce421b1d82728..d963753d0bf9ee65285a86fa9a249198c28a66e2 100644 +--- a/ipaserver/install/plugins/fix_replica_agreements.py ++++ b/ipaserver/install/plugins/fix_replica_agreements.py +@@ -22,6 +22,7 @@ import logging + from ipaserver.install import replication + from ipalib import Registry + from ipalib import Updater ++from ipalib import errors + + logger = logging.getLogger(__name__) + +@@ -41,35 +42,42 @@ class update_replica_attribute_lists(Updater): + def execute(self, **options): + # We need an LDAPClient connection to the backend + logger.debug("Start replication agreement exclude list update task") +- conn = self.api.Backend.ldap2 + +- repl = replication.ReplicationManager(self.api.env.realm, +- self.api.env.host, +- None, conn=conn) +- +- # We need to update only IPA replica agreements, not winsync +- ipa_replicas = repl.find_ipa_replication_agreements() +- +- logger.debug("Found %d agreement(s)", len(ipa_replicas)) +- +- for replica in ipa_replicas: +- for desc in replica.get('description', []): +- logger.debug('%s', desc) +- +- self._update_attr(repl, replica, +- 'nsDS5ReplicatedAttributeList', +- replication.EXCLUDES, template=EXCLUDE_TEMPLATE) +- self._update_attr(repl, replica, +- 'nsDS5ReplicatedAttributeListTotal', +- replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE) +- self._update_attr(repl, replica, +- 'nsds5ReplicaStripAttrs', replication.STRIP_ATTRS) ++ # Find suffixes ++ suffixes = self.api.Command.topologysuffix_find()['result'] ++ for suffix in suffixes: ++ suffix_name = suffix['cn'][0] ++ # Find segments ++ sgmts = self.api.Command.topologysegment_find( ++ suffix_name, all=True)['result'] ++ for segment in sgmts: ++ updates = {} ++ updates = self._update_attr( ++ segment, updates, ++ 'nsds5replicatedattributelist', ++ replication.EXCLUDES, template=EXCLUDE_TEMPLATE) ++ updates = self._update_attr( ++ segment, updates, ++ 'nsds5replicatedattributelisttotal', ++ replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE) ++ updates = self._update_attr( ++ segment, updates, ++ 'nsds5replicastripattrs', replication.STRIP_ATTRS) ++ if updates: ++ try: ++ self.api.Command.topologysegment_mod( ++ suffix_name, segment['cn'][0], ++ **updates) ++ except errors.EmptyModlist: ++ # No update done ++ logger.debug("No update required for the segment %s", ++ segment['cn'][0]) + + logger.debug("Done updating agreements") + + return False, [] # No restart, no updates + +- def _update_attr(self, repl, replica, attribute, values, template='%s'): ++ def _update_attr(self, segment, updates, attribute, values, template='%s'): + """Add or update an attribute of a replication agreement + + If the attribute doesn't already exist, it is added and set to +@@ -77,27 +85,21 @@ class update_replica_attribute_lists(Updater): + If the attribute does exist, `values` missing from it are just + appended to the end, also space-separated. + +- :param repl: Replication manager +- :param replica: Replica agreement ++ :param: updates: dict containing the updates ++ :param segment: dict containing segment information + :param attribute: Attribute to add or update + :param values: List of values the attribute should hold + :param template: Template to use when adding attribute + """ +- attrlist = replica.single_value.get(attribute) ++ attrlist = segment.get(attribute) + if attrlist is None: + logger.debug("Adding %s", attribute) + + # Need to add it altogether +- replica[attribute] = [template % " ".join(values)] +- +- try: +- repl.conn.update_entry(replica) +- logger.debug("Updated") +- except Exception as e: +- logger.error("Error caught updating replica: %s", str(e)) ++ updates[attribute] = template % " ".join(values) + + else: +- attrlist_normalized = attrlist.lower().split() ++ attrlist_normalized = attrlist[0].lower().split() + missing = [a for a in values + if a.lower() not in attrlist_normalized] + +@@ -105,14 +107,8 @@ class update_replica_attribute_lists(Updater): + logger.debug("%s needs updating (missing: %s)", attribute, + ', '.join(missing)) + +- replica[attribute] = [ +- '%s %s' % (attrlist, ' '.join(missing))] ++ updates[attribute] = '%s %s' % (attrlist[0], ' '.join(missing)) + +- try: +- repl.conn.update_entry(replica) +- logger.debug("Updated %s", attribute) +- except Exception as e: +- logger.error("Error caught updating %s: %s", +- attribute, str(e)) + else: + logger.debug("%s: No update necessary", attribute) ++ return updates +-- +2.41.0 + diff --git a/0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch b/0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch new file mode 100644 index 0000000..27161d9 --- /dev/null +++ b/0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch @@ -0,0 +1,69 @@ +From 3b58487c7b2f8ac133e37e8f90f85ff2fb05bf34 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 19 Jun 2023 10:36:59 +0200 +Subject: [PATCH] Integration tests: add a test to ipa-server-upgrade + +Add an integration test ensuring that the upgrade +properly updates the attributes to be excluded from +replication. + +Related: https://pagure.io/freeipa/issue/9385 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + .../test_simple_replication.py | 30 +++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/ipatests/test_integration/test_simple_replication.py b/ipatests/test_integration/test_simple_replication.py +index 17092a49966e61d5a4a9b04c15abcb1de8be9683..d1e65ef7cc3e748670f2cdebe2a5cb7172af27f0 100644 +--- a/ipatests/test_integration/test_simple_replication.py ++++ b/ipatests/test_integration/test_simple_replication.py +@@ -23,8 +23,10 @@ import pytest + + from ipaplatform.paths import paths + from ipapython.dn import DN ++from ipaserver.install.replication import EXCLUDES + from ipatests.pytest_ipa.integration import tasks + from ipatests.test_integration.base import IntegrationTest ++from ipatests.test_integration.test_topology import find_segment + + + def check_replication(source_host, dest_host, login): +@@ -104,6 +106,34 @@ class TestSimpleReplication(IntegrationTest): + [paths.IPA_CUSTODIA_CHECK, self.master.hostname] + ) + ++ def test_fix_agreements(self): ++ """Test that upgrade fixes the list of attributes excluded from repl ++ ++ Test for ticket 9385 ++ """ ++ # Prepare the server by removing some values from ++ # from the nsDS5ReplicatedAttributeList ++ segment = find_segment(self.master, self.replicas[0], "domain") ++ self.master.run_command([ ++ "ipa", "topologysegment-mod", "domain", segment, ++ "--replattrs", ++ "(objectclass=*) $ EXCLUDE memberof idnssoaserial entryusn"]) ++ # Run the upgrade ++ result = self.master.run_command(["ipa-server-upgrade"]) ++ # Ensure that the upgrade updated the attribute without error ++ errmsg = "Error caught updating nsDS5ReplicatedAttributeList" ++ assert errmsg not in result.stdout_text ++ # Check the updated value ++ suffix = DN(self.master.domain.basedn) ++ dn = DN(('cn', str(suffix)), ('cn', 'mapping tree'), ('cn', 'config')) ++ result = tasks.ldapsearch_dm(self.master, str(dn), ++ ["nsDS5ReplicatedAttributeList"]) ++ output = result.stdout_text.lower() ++ ++ template = 'nsDS5ReplicatedAttributeList: (objectclass=*) $ EXCLUDE %s' ++ expected_value = template % " ".join(EXCLUDES) ++ assert expected_value.lower() in output ++ + def test_replica_removal(self): + """Test replica removal""" + result = self.master.run_command(['ipa-replica-manage', 'list']) +-- +2.41.0 + diff --git a/0012-tests-fix-backup-restore-scenario-with-replica.patch b/0012-tests-fix-backup-restore-scenario-with-replica.patch new file mode 100644 index 0000000..3c188e3 --- /dev/null +++ b/0012-tests-fix-backup-restore-scenario-with-replica.patch @@ -0,0 +1,55 @@ +From 5e291da42898cc646f699c21a44b03b833d346e8 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 27 Jun 2023 15:30:08 +0200 +Subject: [PATCH] tests: fix backup-restore scenario with replica + +The test TestBackupAndRestoreWithReplica is simulating a +master crash in order to check the behavior after ipa-restore. + +Since commit 67a33e5, the uninstaller restarts the services in +order to unregister the server from PKI security domain. An +indirect consequence is that master/replica communication is re- +established and operations removing entries (done by the uninstaller) +are replicated to the replica. +This means that the scenario does not really simulate a server crash. + +To make sure that no replication happens during this "crash", stop +the replica first, then uninstall the master, and finally restart +the replica before calling the ipa-restore command on the master. + +Fixes: https://pagure.io/freeipa/issue/9404 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_integration/test_backup_and_restore.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/ipatests/test_integration/test_backup_and_restore.py b/ipatests/test_integration/test_backup_and_restore.py +index 390c065f373e9a8a667f228a09eebd9ac033a19f..83b6a6b44d805fb0615e2128d4be984c6f858bf9 100644 +--- a/ipatests/test_integration/test_backup_and_restore.py ++++ b/ipatests/test_integration/test_backup_and_restore.py +@@ -602,6 +602,12 @@ class TestBackupAndRestoreWithReplica(IntegrationTest): + tasks.user_add(self.replica1, 'test2_replica') + + # simulate master crash ++ # the replica is stopped to make sure master uninstallation ++ # does not delete any entry on the replica. In case of a ++ # real master crash there would not be any communication between ++ # master and replica ++ self.replica1.run_command(['ipactl', 'stop']) ++ + self.master.run_command(['ipactl', 'stop']) + tasks.uninstall_master(self.master, clean=False) + +@@ -612,6 +618,7 @@ class TestBackupAndRestoreWithReplica(IntegrationTest): + self.master.run_command([ + "systemctl", "disable", "oddjobd" + ]) ++ self.replica1.run_command(['ipactl', 'start']) + + self.master.run_command(['ipa-restore', '-U', backup_path]) + +-- +2.41.0 + diff --git a/0013-OTP-fix-data-type-to-avoid-endianness-issue.patch b/0013-OTP-fix-data-type-to-avoid-endianness-issue.patch new file mode 100644 index 0000000..e3dd65d --- /dev/null +++ b/0013-OTP-fix-data-type-to-avoid-endianness-issue.patch @@ -0,0 +1,54 @@ +From 631dd72369385b0793e5bc0e019c088b4f1e2bb3 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 26 Jun 2023 18:24:46 +0200 +Subject: [PATCH] OTP: fix data type to avoid endianness issue + +When 389-ds process an OTP authentication, the ipa-pwd-extop +plugin reads a buffer to extract the authentication type. +The type is stored in an int but the data is a ber_tag_t. + +On big endian machines the type cast does not cause any issue +but on s390x the buffer that should return 128 is seen as 0. + +As a consequence, the plugin considers that the method is not +LDAP_AUTH_SIMPLE and exits early, without processing the OTP. + +The fix is simple and consists in using the right type +(ber_tag_t is an unsigned long). + +Fixes: https://pagure.io/freeipa/issue/9402 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +index 937594117956d57540d4cf4eabeef6d22860aec8..45626523ffa1030cdff4f3e0ccdfa1618a51ccaf 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +@@ -1433,7 +1433,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) + Slapi_DN *target_sdn = NULL; + Slapi_DN *sdn = NULL; + const char *dn = NULL; +- int method = 0; ++ ber_tag_t method = 0; + bool syncreq; + bool otpreq; + int ret = 0; +@@ -1454,8 +1454,10 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) + } + + /* We're only interested in simple authentication. */ +- if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) ++ if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) { ++ LOG("Not handled (not simple bind or NULL dn/credentials)\n"); + return 0; ++ } + + /* Retrieve the user's entry. */ + sdn = slapi_sdn_dup(target_sdn); +-- +2.41.0 + diff --git a/freeipa.spec b/freeipa.spec index cc68507..feb4b2f 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -223,7 +223,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 1%{?rc_version:.%rc_version}%{?dist} +Release: 2%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -247,7 +247,19 @@ Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch %endif %if 0%{?rhel} == 9 -Patch0001: 0001-Revert-cert_find-fix-call-with-all.patch +Patch0001: 0001-webuitests-close-notification-which-hides-Add-button.patch +Patch0002: 0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch +Patch0003: 0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch +Patch0004: 0004-Revert-cert_find-fix-call-with-all.patch +Patch0005: 0005-Use-the-python-cryptography-parser-directly-in-cert-.patch +Patch0006: 0006-Upgrade-add-PKI-drop-in-file-if-missing.patch +Patch0007: 0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch +Patch0008: 0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch +Patch0009: 0009-Detection-of-PKI-subsystem.patch +Patch0010: 0010-Upgrade-fix-replica-agreement.patch +Patch0011: 0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch +Patch0012: 0012-tests-fix-backup-restore-scenario-with-replica.patch +Patch0013: 0013-OTP-fix-data-type-to-avoid-endianness-issue.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -1739,6 +1751,14 @@ fi %endif %changelog +* Thu Jun 29 2023 Florence Blanc-Renaud - 4.10.2-2 +- Resolves: rhbz#2192969 Better handling of the command line and web UI cert search and/or list features +- Resolves: rhbz#2214933 Uninstalling of the IPA server is encountering a failure during the unconfiguration of the CA (Unconfiguring CA) +- Resolves: rhbz#2216114 After updating the RHEL from 8.7 to 8.8, IPA services fails to start +- Resolves: rhbz#2216549 Upgrade to 4.9.10-6.0.1 fails: attributes are managed by topology plugin +- Resolves: rhbz#2216611 Backport latest test fixes in python3-ipatests +- Resolves: rhbz#2216872 User authentication failing on OTP validation using multiple tokens, succeeds with password only + * Tue Jun 06 2023 Florence Blanc-Renaud - 4.10.2-1 - Resolves: rhbz#2196426 [Rebase] Rebase ipa to latest 4.10.x release for RHEL 9.3 - Resolves: rhbz#2192969 Better handling of the command line and web UI cert search and/or list features